From d679c2e1e8d96f71f85e2ef3877407d264212cc3 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Fri, 17 Jan 2025 10:42:28 +0200 Subject: [PATCH 00001/11391] pstore/zone: rewrite some comments for better understanding Rewrite some comments to make it more clear and easier to understand; fix typos. Signed-off-by: Eugen Hristev Link: https://lore.kernel.org/r/20241224154405.295840-1-eugen.hristev@linaro.org Link: https://lore.kernel.org/r/20250117084228.3218024-1-eugen.hristev@linaro.org Signed-off-by: Kees Cook --- fs/pstore/zone.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/fs/pstore/zone.c b/fs/pstore/zone.c index ceb5639a0629..eb61ba5bb964 100644 --- a/fs/pstore/zone.c +++ b/fs/pstore/zone.c @@ -43,7 +43,7 @@ struct psz_buffer { * * @magic: magic num for kmsg dump header * @time: kmsg dump trigger time - * @compressed: whether conpressed + * @compressed: whether compressed * @counter: kmsg dump counter * @reason: the kmsg dump reason (e.g. oops, panic, etc) * @data: pointer to log data @@ -214,7 +214,7 @@ static int psz_zone_write(struct pstore_zone *zone, atomic_set(&zone->buffer->datalen, wlen + off); } - /* avoid to damage old records */ + /* avoid damaging old records */ if (!is_on_panic() && !atomic_read(&pstore_zone_cxt.recovered)) goto dirty; @@ -249,7 +249,7 @@ static int psz_zone_write(struct pstore_zone *zone, return 0; dirty: - /* no need to mark dirty if going to try next zone */ + /* no need to mark it dirty if going to try next zone */ if (wcnt == -ENOMSG) return -ENOMSG; atomic_set(&zone->dirty, true); @@ -378,7 +378,7 @@ static int psz_kmsg_recover_meta(struct psz_context *cxt) struct timespec64 time = { }; unsigned long i; /* - * Recover may on panic, we can't allocate any memory by kmalloc. + * Recover may happen on panic, we can't allocate any memory by kmalloc. * So, we use local array instead. */ char buffer_header[sizeof(*buf) + sizeof(*hdr)] = {0}; @@ -856,11 +856,11 @@ static int notrace psz_record_write(struct pstore_zone *zone, /** * psz_zone_write will set datalen as start + cnt. - * It work if actual data length lesser than buffer size. - * If data length greater than buffer size, pmsg will rewrite to - * beginning of zone, which make buffer->datalen wrongly. + * It works if actual data length is lesser than buffer size. + * If data length is greater than buffer size, pmsg will rewrite to + * the beginning of the zone, which makes buffer->datalen wrong. * So we should reset datalen as buffer size once actual data length - * greater than buffer size. + * is greater than buffer size. */ if (is_full_data) { atomic_set(&zone->buffer->datalen, zone->buffer_size); @@ -878,8 +878,9 @@ static int notrace psz_pstore_write(struct pstore_record *record) atomic_set(&cxt->on_panic, 1); /* - * if on panic, do not write except panic records - * Fix case that panic_write prints log which wakes up console backend. + * If on panic, do not write anything except panic records. + * Fix the case when panic_write prints log that wakes up + * console backend. */ if (is_on_panic() && record->type != PSTORE_TYPE_DMESG) return -EBUSY; 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 00002/11391] 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 @@ bool prb_reserve(struct prb_reserved_entry *e, struct printk_ringbuffer *rb, 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 00003/11391] 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 00004/11391] 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 cce436aafc2abad691fdd37de63ec8a4490b42ce Mon Sep 17 00:00:00 2001 From: Johannes Nixdorf Date: Fri, 25 Jul 2025 18:31:18 +0200 Subject: [PATCH 00005/11391] seccomp: Fix a race with WAIT_KILLABLE_RECV if the tracer replies too fast Normally the tracee starts in SECCOMP_NOTIFY_INIT, sends an event to the tracer, and starts to wait interruptibly. With SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV, if the tracer receives the message (SECCOMP_NOTIFY_SENT is reached) while the tracee was waiting and is subsequently interrupted, the tracee begins to wait again uninterruptibly (but killable). This fails if SECCOMP_NOTIFY_REPLIED is reached before the tracee is interrupted, as the check only considered SECCOMP_NOTIFY_SENT as a condition to begin waiting again. In this case the tracee is interrupted even though the tracer already acted on its behalf. This breaks the assumption SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV wanted to ensure, namely that the tracer can be sure the syscall is not interrupted or restarted on the tracee after it is received on the tracer. Fix this by also considering SECCOMP_NOTIFY_REPLIED when evaluating whether to switch to uninterruptible waiting. With the condition changed the loop in seccomp_do_user_notification() would exit immediately after deciding that noninterruptible waiting is required if the operation already reached SECCOMP_NOTIFY_REPLIED, skipping the code that processes pending addfd commands first. Prevent this by executing the remaining loop body one last time in this case. Fixes: c2aa2dfef243 ("seccomp: Add wait_killable semantic to seccomp user notifier") Reported-by: Ali Polatel Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220291 Signed-off-by: Johannes Nixdorf Link: https://lore.kernel.org/r/20250725-seccomp-races-v2-1-cf8b9d139596@nixdorf.dev Signed-off-by: Kees Cook --- kernel/seccomp.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 41aa761c7738..3bbfba30a777 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -1139,7 +1139,7 @@ static void seccomp_handle_addfd(struct seccomp_kaddfd *addfd, struct seccomp_kn static bool should_sleep_killable(struct seccomp_filter *match, struct seccomp_knotif *n) { - return match->wait_killable_recv && n->state == SECCOMP_NOTIFY_SENT; + return match->wait_killable_recv && n->state >= SECCOMP_NOTIFY_SENT; } static int seccomp_do_user_notification(int this_syscall, @@ -1186,13 +1186,11 @@ static int seccomp_do_user_notification(int this_syscall, if (err != 0) { /* - * Check to see if the notifcation got picked up and - * whether we should switch to wait killable. + * Check to see whether we should switch to wait + * killable. Only return the interrupted error if not. */ - if (!wait_killable && should_sleep_killable(match, &n)) - continue; - - goto interrupted; + if (!(!wait_killable && should_sleep_killable(match, &n))) + goto interrupted; } addfd = list_first_entry_or_null(&n.addfd, From b0c9bfbab925ac6385d4d06a134fd89cadf771fe Mon Sep 17 00:00:00 2001 From: Johannes Nixdorf Date: Fri, 25 Jul 2025 18:31:19 +0200 Subject: [PATCH 00006/11391] selftests/seccomp: Add a test for the WAIT_KILLABLE_RECV fast reply race If WAIT_KILLABLE_RECV was specified, and an event is received, the tracee's syscall is not supposed to be interruptible. This was not properly ensured if the reply was sent too fast, and an interrupting signal was received before the reply was processed on the tracee side. Add a test for this, that consists of: - a tracee with a timer that keeps sending it signals while repeatedly running a traced syscall in a loop, - a tracer that repeatedly handles all syscalls from the tracee in a loop, and - a shared pipe between both, on which the tracee sends one byte per syscall attempted and the tracer reads one byte per syscall handled. If the syscall for the tracee is restarted after the tracer received the event for it due to this bug, the tracee will not have sent a second token on the pipe, which the tracer will notice and fail the test. The tests also uses SECCOMP_IOCTL_NOTIF_ADDFD with SECCOMP_ADDFD_FLAG_SEND for the reply, as the fix for the bug has an additional code path change for handling addfd, which would not be exercised by a simple SECCOMP_IOCTL_NOTIF_SEND, and it is possible to fix the bug while leaving the same race intact for the addfd case. This test is not guaranteed to reproduce the bug on every run, but the parameters (signal frequency and number of repeated syscalls) have been chosen so that on my machine this test: - takes ~0.8s in the good case (+1s in the failure case), and - detects the bug in 999 of 1000 runs. Signed-off-by: Johannes Nixdorf Link: https://lore.kernel.org/r/20250725-seccomp-races-v2-2-cf8b9d139596@nixdorf.dev Signed-off-by: Kees Cook --- tools/testing/selftests/seccomp/seccomp_bpf.c | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c index 61acbd45ffaa..fc4910d35342 100644 --- a/tools/testing/selftests/seccomp/seccomp_bpf.c +++ b/tools/testing/selftests/seccomp/seccomp_bpf.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -3547,6 +3548,10 @@ static void signal_handler(int signal) perror("write from signal"); } +static void signal_handler_nop(int signal) +{ +} + TEST(user_notification_signal) { pid_t pid; @@ -4819,6 +4824,132 @@ TEST(user_notification_wait_killable_fatal) EXPECT_EQ(SIGTERM, WTERMSIG(status)); } +/* Ensure signals after the reply do not interrupt */ +TEST(user_notification_wait_killable_after_reply) +{ + int i, max_iter = 100000; + int listener, status; + int pipe_fds[2]; + pid_t pid; + long ret; + + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); + ASSERT_EQ(0, ret) + { + TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!"); + } + + listener = user_notif_syscall( + __NR_dup, SECCOMP_FILTER_FLAG_NEW_LISTENER | + SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV); + ASSERT_GE(listener, 0); + + /* + * Used to count invocations. One token is transferred from the child + * to the parent per syscall invocation, the parent tries to take + * one token per successful RECV. If the syscall is restarted after + * RECV the parent will try to get two tokens while the child only + * provided one. + */ + ASSERT_EQ(pipe(pipe_fds), 0); + + pid = fork(); + ASSERT_GE(pid, 0); + + if (pid == 0) { + struct sigaction new_action = { + .sa_handler = signal_handler_nop, + .sa_flags = SA_RESTART, + }; + struct itimerval timer = { + .it_value = { .tv_usec = 1000 }, + .it_interval = { .tv_usec = 1000 }, + }; + char c = 'a'; + + close(pipe_fds[0]); + + /* Setup the sigaction with SA_RESTART */ + if (sigaction(SIGALRM, &new_action, NULL)) { + perror("sigaction"); + exit(1); + } + + /* + * Kill with SIGALRM repeatedly, to try to hit the race when + * handling the syscall. + */ + if (setitimer(ITIMER_REAL, &timer, NULL) < 0) + perror("setitimer"); + + for (i = 0; i < max_iter; ++i) { + int fd; + + /* Send one token per iteration to catch repeats. */ + if (write(pipe_fds[1], &c, sizeof(c)) != 1) { + perror("write"); + exit(1); + } + + fd = syscall(__NR_dup, 0); + if (fd < 0) { + perror("dup"); + exit(1); + } + close(fd); + } + + exit(0); + } + + close(pipe_fds[1]); + + for (i = 0; i < max_iter; ++i) { + struct seccomp_notif req = {}; + struct seccomp_notif_addfd addfd = {}; + struct pollfd pfd = { + .fd = pipe_fds[0], + .events = POLLIN, + }; + char c; + + /* + * Try to receive one token. If it failed, one child syscall + * was restarted after RECV and needed to be handled twice. + */ + ASSERT_EQ(poll(&pfd, 1, 1000), 1) + kill(pid, SIGKILL); + + ASSERT_EQ(read(pipe_fds[0], &c, sizeof(c)), 1) + kill(pid, SIGKILL); + + /* + * Get the notification, reply to it as fast as possible to test + * whether the child wrongly skips going into the non-preemptible + * (TASK_KILLABLE) state. + */ + do + ret = ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req); + while (ret < 0 && errno == ENOENT); /* Accept interruptions before RECV */ + ASSERT_EQ(ret, 0) + kill(pid, SIGKILL); + + addfd.id = req.id; + addfd.flags = SECCOMP_ADDFD_FLAG_SEND; + addfd.srcfd = 0; + ASSERT_GE(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd), 0) + kill(pid, SIGKILL); + } + + /* + * Wait for the process to exit, and make sure the process terminated + * with a zero exit code.. + */ + EXPECT_EQ(waitpid(pid, &status, 0), pid); + EXPECT_EQ(true, WIFEXITED(status)); + EXPECT_EQ(0, WEXITSTATUS(status)); +} + struct tsync_vs_thread_leader_args { pthread_t leader; }; From 86de56487e5f0017ffd5930b0dbd9dda43048849 Mon Sep 17 00:00:00 2001 From: Amery Hung Date: Wed, 30 Jul 2025 11:58:52 -0700 Subject: [PATCH 00007/11391] bpf: Allow syscall bpf programs to call non-recur helpers Allow syscall programs to call non-recur helpers too since syscall bpf programs runs in process context through bpf syscall, BPF_PROG_TEST_RUN, and cannot run recursively. bpf_task_storage_{get,set} have "_recur" versions that call trylock instead of taking the lock directly to avoid deadlock when called by bpf programs that run recursively. Currently, only bpf_lsm, bpf_iter, struct_ops without private stack are allow to call the non-recur helpers since they cannot be recursively called in another bpf program. Signed-off-by: Amery Hung Reviewed-by: Emil Tsalapatis Link: https://lore.kernel.org/r/20250730185903.3574598-2-ameryhung@gmail.com Signed-off-by: Alexei Starovoitov --- include/linux/bpf_verifier.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 94defa405c85..c823f8efe3ed 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -962,6 +962,7 @@ static inline bool bpf_prog_check_recur(const struct bpf_prog *prog) case BPF_PROG_TYPE_STRUCT_OPS: return prog->aux->jits_use_priv_stack; case BPF_PROG_TYPE_LSM: + case BPF_PROG_TYPE_SYSCALL: return false; default: return true; From 31e838e1cdf4c4088fee8154ce8c12713ebfb2da Mon Sep 17 00:00:00 2001 From: Amery Hung Date: Wed, 30 Jul 2025 11:58:53 -0700 Subject: [PATCH 00008/11391] selftests/bpf: Introduce task local data Task local data defines an abstract storage type for storing task- specific data (TLD). This patch provides user space and bpf implementation as header-only libraries for accessing task local data. Task local data is a bpf task local storage map with two UPTRs: - tld_meta_u, shared by all tasks of a process, consists of the total count and size of TLDs and an array of metadata of TLDs. A TLD metadata contains the size and name. The name is used to identify a specific TLD in bpf programs. - u_tld_data points to a task-specific memory. It stores TLD data and the starting offset of data in a page. Task local design decouple user space and bpf programs. Since bpf program does not know the size of TLDs in compile time, u_tld_data is declared as a page to accommodate TLDs up to a page. As a result, while user space will likely allocate memory smaller than a page for actual TLDs, it needs to pin a page to kernel. It will pin the page that contains enough memory if the allocated memory spans across the page boundary. The library also creates another task local storage map, tld_key_map, to cache keys for bpf programs to speed up the access. Below are the core task local data API: User space BPF Define TLD TLD_DEFINE_KEY(), tld_create_key() - Init TLD object - tld_object_init() Get TLD data tld_get_data() tld_get_data() - TLD_DEFINE_KEY(), tld_create_key() A TLD is first defined by the user space with TLD_DEFINE_KEY() or tld_create_key(). TLD_DEFINE_KEY() defines a TLD statically and allocates just enough memory during initialization. tld_create_key() allows creating TLDs on the fly, but has a fix memory budget, TLD_DYN_DATA_SIZE. Internally, they all call __tld_create_key(), which iterates tld_meta_u->metadata to check if a TLD can be added. The total TLD size needs to fit into a page (limit of UPTR), and no two TLDs can have the same name. If a TLD can be added, u_tld_meta->cnt is increased using cmpxchg as there may be other concurrent __tld_create_key(). After a successful cmpxchg, the last available tld_meta_u->metadata now belongs to the calling thread. To prevent other threads from reading incomplete metadata while it is being updated, tld_meta_u->metadata->size is used to signal the completion. Finally, the offset, derived from adding up prior TLD sizes is then encapsulated as an opaque object key to prevent user misuse. The offset is guaranteed to be 8-byte aligned to prevent load/store tearing and allow atomic operations on it. - tld_get_data() User space programs can pass the key to tld_get_data() to get a pointer to the associated TLD. The pointer will remain valid for the lifetime of the thread. tld_data_u is lazily allocated on the first call to tld_get_data(). Trying to read task local data from bpf will result in -ENODATA during tld_object_init(). The task-specific memory need to be freed manually by calling tld_free() on thread exit to prevent memory leak or use TLD_FREE_DATA_ON_THREAD_EXIT. - tld_object_init() (BPF) BPF programs need to call tld_object_init() before calling tld_get_data(). This is to avoid redundant map lookup in tld_get_data() by storing pointers to the map values on stack. The pointers are encapsulated as tld_object. tld_key_map is also created on the first time tld_object_init() is called to cache TLD keys successfully fetched by tld_get_data(). bpf_task_storage_get(.., F_CREATE) needs to be retried since it may fail when another thread has already taken the percpu counter lock for the task local storage. - tld_get_data() (BPF) BPF programs can also get a pointer to a TLD with tld_get_data(). It uses the cached key in tld_key_map to locate the data in tld_data_u->data. If the cached key is not set yet (<= 0), __tld_fetch_key() will be called to iterate tld_meta_u->metadata and find the TLD by name. To prevent redundant string comparison in the future when the search fail, the tld_meta_u->cnt is stored in the non-positive range of the key. Next time, __tld_fetch_key() will be called only if there are new TLDs and the search will start from the newly added tld_meta_u->metadata using the old tld_meta_u-cnt. Signed-off-by: Amery Hung Reviewed-by: Emil Tsalapatis Link: https://lore.kernel.org/r/20250730185903.3574598-3-ameryhung@gmail.com Signed-off-by: Alexei Starovoitov --- .../bpf/prog_tests/task_local_data.h | 386 ++++++++++++++++++ .../selftests/bpf/progs/task_local_data.bpf.h | 237 +++++++++++ 2 files changed, 623 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/task_local_data.h create mode 100644 tools/testing/selftests/bpf/progs/task_local_data.bpf.h diff --git a/tools/testing/selftests/bpf/prog_tests/task_local_data.h b/tools/testing/selftests/bpf/prog_tests/task_local_data.h new file mode 100644 index 000000000000..a408d10c3688 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/task_local_data.h @@ -0,0 +1,386 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __TASK_LOCAL_DATA_H +#define __TASK_LOCAL_DATA_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef TLD_FREE_DATA_ON_THREAD_EXIT +#include +#endif + +#include + +/* + * OPTIONS + * + * Define the option before including the header + * + * TLD_FREE_DATA_ON_THREAD_EXIT - Frees memory on thread exit automatically + * + * Thread-specific memory for storing TLD is allocated lazily on the first call to + * tld_get_data(). The thread that calls it must also call tld_free() on thread exit + * to prevent memory leak. Pthread will be included if the option is defined. A pthread + * key will be registered with a destructor that calls tld_free(). + * + * + * TLD_DYN_DATA_SIZE - The maximum size of memory allocated for TLDs created dynamically + * (default: 64 bytes) + * + * A TLD can be defined statically using TLD_DEFINE_KEY() or created on the fly using + * tld_create_key(). As the total size of TLDs created with tld_create_key() cannot be + * possibly known statically, a memory area of size TLD_DYN_DATA_SIZE will be allocated + * for these TLDs. This additional memory is allocated for every thread that calls + * tld_get_data() even if no tld_create_key are actually called, so be mindful of + * potential memory wastage. Use TLD_DEFINE_KEY() whenever possible as just enough memory + * will be allocated for TLDs created with it. + * + * + * TLD_NAME_LEN - The maximum length of the name of a TLD (default: 62) + * + * Setting TLD_NAME_LEN will affect the maximum number of TLDs a process can store, + * TLD_MAX_DATA_CNT. + * + * + * TLD_DATA_USE_ALIGNED_ALLOC - Always use aligned_alloc() instead of malloc() + * + * When allocating the memory for storing TLDs, we need to make sure there is a memory + * region of the X bytes within a page. This is due to the limit posed by UPTR: memory + * pinned to the kernel cannot exceed a page nor can it cross the page boundary. The + * library normally calls malloc(2*X) given X bytes of total TLDs, and only uses + * aligned_alloc(PAGE_SIZE, X) when X >= PAGE_SIZE / 2. This is to reduce memory wastage + * as not all memory allocator can use the exact amount of memory requested to fulfill + * aligned_alloc(). For example, some may round the size up to the alignment. Enable the + * option to always use aligned_alloc() if the implementation has low memory overhead. + */ + +#define TLD_PAGE_SIZE getpagesize() +#define TLD_PAGE_MASK (~(TLD_PAGE_SIZE - 1)) + +#define TLD_ROUND_MASK(x, y) ((__typeof__(x))((y) - 1)) +#define TLD_ROUND_UP(x, y) ((((x) - 1) | TLD_ROUND_MASK(x, y)) + 1) + +#define TLD_READ_ONCE(x) (*(volatile typeof(x) *)&(x)) + +#ifndef TLD_DYN_DATA_SIZE +#define TLD_DYN_DATA_SIZE 64 +#endif + +#define TLD_MAX_DATA_CNT (TLD_PAGE_SIZE / sizeof(struct tld_metadata) - 1) + +#ifndef TLD_NAME_LEN +#define TLD_NAME_LEN 62 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + __s16 off; +} tld_key_t; + +struct tld_metadata { + char name[TLD_NAME_LEN]; + _Atomic __u16 size; +}; + +struct tld_meta_u { + _Atomic __u8 cnt; + __u16 size; + struct tld_metadata metadata[]; +}; + +struct tld_data_u { + __u64 start; /* offset of tld_data_u->data in a page */ + char data[]; +}; + +struct tld_map_value { + void *data; + struct tld_meta_u *meta; +}; + +struct tld_meta_u * _Atomic tld_meta_p __attribute__((weak)); +__thread struct tld_data_u *tld_data_p __attribute__((weak)); +__thread void *tld_data_alloc_p __attribute__((weak)); + +#ifdef TLD_FREE_DATA_ON_THREAD_EXIT +pthread_key_t tld_pthread_key __attribute__((weak)); + +static void tld_free(void); + +static void __tld_thread_exit_handler(void *unused) +{ + tld_free(); +} +#endif + +static int __tld_init_meta_p(void) +{ + struct tld_meta_u *meta, *uninit = NULL; + int err = 0; + + meta = (struct tld_meta_u *)aligned_alloc(TLD_PAGE_SIZE, TLD_PAGE_SIZE); + if (!meta) { + err = -ENOMEM; + goto out; + } + + memset(meta, 0, TLD_PAGE_SIZE); + meta->size = TLD_DYN_DATA_SIZE; + + if (!atomic_compare_exchange_strong(&tld_meta_p, &uninit, meta)) { + free(meta); + goto out; + } + +#ifdef TLD_FREE_DATA_ON_THREAD_EXIT + pthread_key_create(&tld_pthread_key, __tld_thread_exit_handler); +#endif +out: + return err; +} + +static int __tld_init_data_p(int map_fd) +{ + bool use_aligned_alloc = false; + struct tld_map_value map_val; + struct tld_data_u *data; + void *data_alloc = NULL; + int err, tid_fd = -1; + + tid_fd = syscall(SYS_pidfd_open, gettid(), O_EXCL); + if (tid_fd < 0) { + err = -errno; + goto out; + } + +#ifdef TLD_DATA_USE_ALIGNED_ALLOC + use_aligned_alloc = true; +#endif + + /* + * tld_meta_p->size = TLD_DYN_DATA_SIZE + + * total size of TLDs defined via TLD_DEFINE_KEY() + */ + data_alloc = (use_aligned_alloc || tld_meta_p->size * 2 >= TLD_PAGE_SIZE) ? + aligned_alloc(TLD_PAGE_SIZE, tld_meta_p->size) : + malloc(tld_meta_p->size * 2); + if (!data_alloc) { + err = -ENOMEM; + goto out; + } + + /* + * Always pass a page-aligned address to UPTR since the size of tld_map_value::data + * is a page in BTF. If data_alloc spans across two pages, use the page that contains large + * enough memory. + */ + if (TLD_PAGE_SIZE - (~TLD_PAGE_MASK & (intptr_t)data_alloc) >= tld_meta_p->size) { + map_val.data = (void *)(TLD_PAGE_MASK & (intptr_t)data_alloc); + data = data_alloc; + data->start = (~TLD_PAGE_MASK & (intptr_t)data_alloc) + + offsetof(struct tld_data_u, data); + } else { + map_val.data = (void *)(TLD_ROUND_UP((intptr_t)data_alloc, TLD_PAGE_SIZE)); + data = (void *)(TLD_ROUND_UP((intptr_t)data_alloc, TLD_PAGE_SIZE)); + data->start = offsetof(struct tld_data_u, data); + } + map_val.meta = TLD_READ_ONCE(tld_meta_p); + + err = bpf_map_update_elem(map_fd, &tid_fd, &map_val, 0); + if (err) { + free(data_alloc); + goto out; + } + + tld_data_p = data; + tld_data_alloc_p = data_alloc; +#ifdef TLD_FREE_DATA_ON_THREAD_EXIT + pthread_setspecific(tld_pthread_key, (void *)1); +#endif +out: + if (tid_fd >= 0) + close(tid_fd); + return err; +} + +static tld_key_t __tld_create_key(const char *name, size_t size, bool dyn_data) +{ + int err, i, sz, off = 0; + __u8 cnt; + + if (!TLD_READ_ONCE(tld_meta_p)) { + err = __tld_init_meta_p(); + if (err) + return (tld_key_t){err}; + } + + for (i = 0; i < TLD_MAX_DATA_CNT; i++) { +retry: + cnt = atomic_load(&tld_meta_p->cnt); + if (i < cnt) { + /* A metadata is not ready until size is updated with a non-zero value */ + while (!(sz = atomic_load(&tld_meta_p->metadata[i].size))) + sched_yield(); + + if (!strncmp(tld_meta_p->metadata[i].name, name, TLD_NAME_LEN)) + return (tld_key_t){-EEXIST}; + + off += TLD_ROUND_UP(sz, 8); + continue; + } + + /* + * TLD_DEFINE_KEY() is given memory upto a page while at most + * TLD_DYN_DATA_SIZE is allocated for tld_create_key() + */ + if (dyn_data) { + if (off + TLD_ROUND_UP(size, 8) > tld_meta_p->size) + return (tld_key_t){-E2BIG}; + } else { + if (off + TLD_ROUND_UP(size, 8) > TLD_PAGE_SIZE - sizeof(struct tld_data_u)) + return (tld_key_t){-E2BIG}; + tld_meta_p->size += TLD_ROUND_UP(size, 8); + } + + /* + * Only one tld_create_key() can increase the current cnt by one and + * takes the latest available slot. Other threads will check again if a new + * TLD can still be added, and then compete for the new slot after the + * succeeding thread update the size. + */ + if (!atomic_compare_exchange_strong(&tld_meta_p->cnt, &cnt, cnt + 1)) + goto retry; + + strncpy(tld_meta_p->metadata[i].name, name, TLD_NAME_LEN); + atomic_store(&tld_meta_p->metadata[i].size, size); + return (tld_key_t){(__s16)off}; + } + + return (tld_key_t){-ENOSPC}; +} + +/** + * TLD_DEFINE_KEY() - Define a TLD and a global variable key associated with the TLD. + * + * @name: The name of the TLD + * @size: The size of the TLD + * @key: The variable name of the key. Cannot exceed TLD_NAME_LEN + * + * The macro can only be used in file scope. + * + * A global variable key of opaque type, tld_key_t, will be declared and initialized before + * main() starts. Use tld_key_is_err() or tld_key_err_or_zero() later to check if the key + * creation succeeded. Pass the key to tld_get_data() to get a pointer to the TLD. + * bpf programs can also fetch the same key by name. + * + * The total size of TLDs created using TLD_DEFINE_KEY() cannot exceed a page. Just + * enough memory will be allocated for each thread on the first call to tld_get_data(). + */ +#define TLD_DEFINE_KEY(key, name, size) \ +tld_key_t key; \ + \ +__attribute__((constructor)) \ +void __tld_define_key_##key(void) \ +{ \ + key = __tld_create_key(name, size, false); \ +} + +/** + * tld_create_key() - Create a TLD and return a key associated with the TLD. + * + * @name: The name the TLD + * @size: The size of the TLD + * + * Return an opaque object key. Use tld_key_is_err() or tld_key_err_or_zero() to check + * if the key creation succeeded. Pass the key to tld_get_data() to get a pointer to + * locate the TLD. bpf programs can also fetch the same key by name. + * + * Use tld_create_key() only when a TLD needs to be created dynamically (e.g., @name is + * not known statically or a TLD needs to be created conditionally) + * + * An additional TLD_DYN_DATA_SIZE bytes are allocated per-thread to accommodate TLDs + * created dynamically with tld_create_key(). Since only a user page is pinned to the + * kernel, when TLDs created with TLD_DEFINE_KEY() uses more than TLD_PAGE_SIZE - + * TLD_DYN_DATA_SIZE, the buffer size will be limited to the rest of the page. + */ +__attribute__((unused)) +static tld_key_t tld_create_key(const char *name, size_t size) +{ + return __tld_create_key(name, size, true); +} + +__attribute__((unused)) +static inline bool tld_key_is_err(tld_key_t key) +{ + return key.off < 0; +} + +__attribute__((unused)) +static inline int tld_key_err_or_zero(tld_key_t key) +{ + return tld_key_is_err(key) ? key.off : 0; +} + +/** + * tld_get_data() - Get a pointer to the TLD associated with the given key of the + * calling thread. + * + * @map_fd: A file descriptor of tld_data_map, the underlying BPF task local storage map + * of task local data. + * @key: A key object created by TLD_DEFINE_KEY() or tld_create_key(). + * + * Return a pointer to the TLD if the key is valid; NULL if not enough memory for TLD + * for this thread, or the key is invalid. The returned pointer is guaranteed to be 8-byte + * aligned. + * + * Threads that call tld_get_data() must call tld_free() on exit to prevent + * memory leak if TLD_FREE_DATA_ON_THREAD_EXIT is not defined. + */ +__attribute__((unused)) +static void *tld_get_data(int map_fd, tld_key_t key) +{ + if (!TLD_READ_ONCE(tld_meta_p)) + return NULL; + + /* tld_data_p is allocated on the first invocation of tld_get_data() */ + if (!tld_data_p && __tld_init_data_p(map_fd)) + return NULL; + + return tld_data_p->data + key.off; +} + +/** + * tld_free() - Free task local data memory of the calling thread + * + * For the calling thread, all pointers to TLDs acquired before will become invalid. + * + * Users must call tld_free() on thread exit to prevent memory leak. Alternatively, + * define TLD_FREE_DATA_ON_THREAD_EXIT and a thread exit handler will be registered + * to free the memory automatically. + */ +__attribute__((unused)) +static void tld_free(void) +{ + if (tld_data_alloc_p) { + free(tld_data_alloc_p); + tld_data_alloc_p = NULL; + tld_data_p = NULL; + } +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* __TASK_LOCAL_DATA_H */ diff --git a/tools/testing/selftests/bpf/progs/task_local_data.bpf.h b/tools/testing/selftests/bpf/progs/task_local_data.bpf.h new file mode 100644 index 000000000000..432fff2af844 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/task_local_data.bpf.h @@ -0,0 +1,237 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __TASK_LOCAL_DATA_BPF_H +#define __TASK_LOCAL_DATA_BPF_H + +/* + * Task local data is a library that facilitates sharing per-task data + * between user space and bpf programs. + * + * + * USAGE + * + * A TLD, an entry of data in task local data, first needs to be created by the + * user space. This is done by calling user space API, TLD_DEFINE_KEY() or + * tld_create_key(), with the name of the TLD and the size. + * + * TLD_DEFINE_KEY(prio, "priority", sizeof(int)); + * + * or + * + * void func_call(...) { + * tld_key_t prio, in_cs; + * + * prio = tld_create_key("priority", sizeof(int)); + * in_cs = tld_create_key("in_critical_section", sizeof(bool)); + * ... + * + * A key associated with the TLD, which has an opaque type tld_key_t, will be + * initialized or returned. It can be used to get a pointer to the TLD in the + * user space by calling tld_get_data(). + * + * In a bpf program, tld_object_init() first needs to be called to initialized a + * tld_object on the stack. Then, TLDs can be accessed by calling tld_get_data(). + * The API will try to fetch the key by the name and use it to locate the data. + * A pointer to the TLD will be returned. It also caches the key in a task local + * storage map, tld_key_map, whose value type, struct tld_keys, must be defined + * by the developer. + * + * struct tld_keys { + * tld_key_t prio; + * tld_key_t in_cs; + * }; + * + * SEC("struct_ops") + * void prog(struct task_struct task, ...) + * { + * struct tld_object tld_obj; + * int err, *p; + * + * err = tld_object_init(task, &tld_obj); + * if (err) + * return; + * + * p = tld_get_data(&tld_obj, prio, "priority", sizeof(int)); + * if (p) + * // do something depending on *p + */ +#include +#include + +#define TLD_ROUND_MASK(x, y) ((__typeof__(x))((y) - 1)) +#define TLD_ROUND_UP(x, y) ((((x) - 1) | TLD_ROUND_MASK(x, y)) + 1) + +#define TLD_MAX_DATA_CNT (__PAGE_SIZE / sizeof(struct tld_metadata) - 1) + +#ifndef TLD_NAME_LEN +#define TLD_NAME_LEN 62 +#endif + +#ifndef TLD_KEY_MAP_CREATE_RETRY +#define TLD_KEY_MAP_CREATE_RETRY 10 +#endif + +typedef struct { + __s16 off; +} tld_key_t; + +struct tld_metadata { + char name[TLD_NAME_LEN]; + __u16 size; +}; + +struct tld_meta_u { + __u8 cnt; + __u16 size; + struct tld_metadata metadata[TLD_MAX_DATA_CNT]; +}; + +struct tld_data_u { + __u64 start; /* offset of tld_data_u->data in a page */ + char data[__PAGE_SIZE - sizeof(__u64)]; +}; + +struct tld_map_value { + struct tld_data_u __uptr *data; + struct tld_meta_u __uptr *meta; +}; + +typedef struct tld_uptr_dummy { + struct tld_data_u data[0]; + struct tld_meta_u meta[0]; +} *tld_uptr_dummy_t; + +struct tld_object { + struct tld_map_value *data_map; + struct tld_keys *key_map; + /* + * Force the compiler to generate the actual definition of tld_meta_u + * and tld_data_u in BTF. Without it, tld_meta_u and u_tld_data will + * be BTF_KIND_FWD. + */ + tld_uptr_dummy_t dummy[0]; +}; + +/* + * Map value of tld_key_map for caching keys. Must be defined by the developer. + * Members should be tld_key_t and passed to the 3rd argument of tld_fetch_key(). + */ +struct tld_keys; + +struct { + __uint(type, BPF_MAP_TYPE_TASK_STORAGE); + __uint(map_flags, BPF_F_NO_PREALLOC); + __type(key, int); + __type(value, struct tld_map_value); +} tld_data_map SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_TASK_STORAGE); + __uint(map_flags, BPF_F_NO_PREALLOC); + __type(key, int); + __type(value, struct tld_keys); +} tld_key_map SEC(".maps"); + +/** + * tld_object_init() - Initialize a tld_object. + * + * @task: The task_struct of the target task + * @tld_obj: A pointer to a tld_object to be initialized + * + * Return 0 on success; -ENODATA if the user space did not initialize task local data + * for the current task through tld_get_data(); -ENOMEM if the creation of tld_key_map + * fails + */ +__attribute__((unused)) +static int tld_object_init(struct task_struct *task, struct tld_object *tld_obj) +{ + int i; + + tld_obj->data_map = bpf_task_storage_get(&tld_data_map, task, 0, 0); + if (!tld_obj->data_map) + return -ENODATA; + + bpf_for(i, 0, TLD_KEY_MAP_CREATE_RETRY) { + tld_obj->key_map = bpf_task_storage_get(&tld_key_map, task, 0, + BPF_LOCAL_STORAGE_GET_F_CREATE); + if (likely(tld_obj->key_map)) + break; + } + if (!tld_obj->key_map) + return -ENOMEM; + + return 0; +} + +/* + * Return the offset of TLD if @name is found. Otherwise, return the current TLD count + * using the nonpositive range so that the next tld_get_data() can skip fetching key if + * no new TLD is added or start comparing name from the first newly added TLD. + */ +__attribute__((unused)) +static int __tld_fetch_key(struct tld_object *tld_obj, const char *name, int i_start) +{ + struct tld_metadata *metadata; + int i, cnt, start, off = 0; + + if (!tld_obj->data_map || !tld_obj->data_map->data || !tld_obj->data_map->meta) + return 0; + + start = tld_obj->data_map->data->start; + cnt = tld_obj->data_map->meta->cnt; + metadata = tld_obj->data_map->meta->metadata; + + bpf_for(i, 0, cnt) { + if (i >= TLD_MAX_DATA_CNT) + break; + + if (i >= i_start && !bpf_strncmp(metadata[i].name, TLD_NAME_LEN, name)) + return start + off; + + off += TLD_ROUND_UP(metadata[i].size, 8); + } + + return -cnt; +} + +/** + * tld_get_data() - Retrieve a pointer to the TLD associated with the name. + * + * @tld_obj: A pointer to a valid tld_object initialized by tld_object_init() + * @key: The cached key of the TLD in tld_key_map + * @name: The name of the key associated with a TLD + * @size: The size of the TLD. Must be a known constant value + * + * Return a pointer to the TLD associated with @name; NULL if not found or @size is too + * big. @key is used to cache the key if the TLD is found to speed up subsequent calls. + * It should be defined as an member of tld_keys of tld_key_t type by the developer. + */ +#define tld_get_data(tld_obj, key, name, size) \ + ({ \ + void *data = NULL, *_data = (tld_obj)->data_map->data; \ + long off = (tld_obj)->key_map->key.off; \ + int cnt; \ + \ + if (likely(_data)) { \ + if (likely(off > 0)) { \ + barrier_var(off); \ + if (likely(off < __PAGE_SIZE - size)) \ + data = _data + off; \ + } else { \ + cnt = -(off); \ + if (likely((tld_obj)->data_map->meta) && \ + cnt < (tld_obj)->data_map->meta->cnt) { \ + off = __tld_fetch_key(tld_obj, name, cnt); \ + (tld_obj)->key_map->key.off = off; \ + \ + if (likely(off < __PAGE_SIZE - size)) { \ + barrier_var(off); \ + if (off > 0) \ + data = _data + off; \ + } \ + } \ + } \ + } \ + data; \ + }) + +#endif From 120f1a950e495d9751fdb5c8b7852d94546dcd03 Mon Sep 17 00:00:00 2001 From: Amery Hung Date: Wed, 30 Jul 2025 11:58:54 -0700 Subject: [PATCH 00009/11391] selftests/bpf: Test basic task local data operations Test basic operations of task local data with valid and invalid tld_create_key(). For invalid calls, make sure they return the right error code and check that the TLDs are not inserted by running tld_get_data(" value_not_exists") on the bpf side. The call should a null pointer. For valid calls, first make sure the TLDs are created by calling tld_get_data() on the bpf side. The call should return a valid pointer. Finally, verify that the TLDs are indeed task-specific (i.e., their addresses do not overlap) with multiple user threads. This done by writing values unique to each thread, reading them from both user space and bpf, and checking if the value read back matches the value written. Signed-off-by: Amery Hung Reviewed-by: Emil Tsalapatis Link: https://lore.kernel.org/r/20250730185903.3574598-4-ameryhung@gmail.com Signed-off-by: Alexei Starovoitov --- .../bpf/prog_tests/test_task_local_data.c | 192 ++++++++++++++++++ .../bpf/progs/test_task_local_data.c | 65 ++++++ 2 files changed, 257 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/test_task_local_data.c create mode 100644 tools/testing/selftests/bpf/progs/test_task_local_data.c diff --git a/tools/testing/selftests/bpf/prog_tests/test_task_local_data.c b/tools/testing/selftests/bpf/prog_tests/test_task_local_data.c new file mode 100644 index 000000000000..2e77d3fa2534 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/test_task_local_data.c @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include + +#define TLD_FREE_DATA_ON_THREAD_EXIT +#define TLD_DYN_DATA_SIZE 4096 +#include "task_local_data.h" + +struct test_tld_struct { + __u64 a; + __u64 b; + __u64 c; + __u64 d; +}; + +#include "test_task_local_data.skel.h" + +TLD_DEFINE_KEY(value0_key, "value0", sizeof(int)); + +/* + * Reset task local data between subtests by clearing metadata other + * than the statically defined value0. This is safe as subtests run + * sequentially. Users of task local data library should not touch + * library internal. + */ +static void reset_tld(void) +{ + if (TLD_READ_ONCE(tld_meta_p)) { + /* Remove TLDs created by tld_create_key() */ + tld_meta_p->cnt = 1; + tld_meta_p->size = TLD_DYN_DATA_SIZE; + memset(&tld_meta_p->metadata[1], 0, + (TLD_MAX_DATA_CNT - 1) * sizeof(struct tld_metadata)); + } +} + +/* Serialize access to bpf program's global variables */ +static pthread_mutex_t global_mutex; + +static tld_key_t *tld_keys; + +#define TEST_BASIC_THREAD_NUM 32 + +void *test_task_local_data_basic_thread(void *arg) +{ + LIBBPF_OPTS(bpf_test_run_opts, opts); + struct test_task_local_data *skel = (struct test_task_local_data *)arg; + int fd, err, tid, *value0, *value1; + struct test_tld_struct *value2; + + fd = bpf_map__fd(skel->maps.tld_data_map); + + value0 = tld_get_data(fd, value0_key); + if (!ASSERT_OK_PTR(value0, "tld_get_data")) + goto out; + + value1 = tld_get_data(fd, tld_keys[1]); + if (!ASSERT_OK_PTR(value1, "tld_get_data")) + goto out; + + value2 = tld_get_data(fd, tld_keys[2]); + if (!ASSERT_OK_PTR(value2, "tld_get_data")) + goto out; + + tid = gettid(); + + *value0 = tid + 0; + *value1 = tid + 1; + value2->a = tid + 2; + value2->b = tid + 3; + value2->c = tid + 4; + value2->d = tid + 5; + + pthread_mutex_lock(&global_mutex); + /* Run task_main that read task local data and save to global variables */ + err = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.task_main), &opts); + ASSERT_OK(err, "run task_main"); + ASSERT_OK(opts.retval, "task_main retval"); + + ASSERT_EQ(skel->bss->test_value0, tid + 0, "tld_get_data value0"); + ASSERT_EQ(skel->bss->test_value1, tid + 1, "tld_get_data value1"); + ASSERT_EQ(skel->bss->test_value2.a, tid + 2, "tld_get_data value2.a"); + ASSERT_EQ(skel->bss->test_value2.b, tid + 3, "tld_get_data value2.b"); + ASSERT_EQ(skel->bss->test_value2.c, tid + 4, "tld_get_data value2.c"); + ASSERT_EQ(skel->bss->test_value2.d, tid + 5, "tld_get_data value2.d"); + pthread_mutex_unlock(&global_mutex); + + /* Make sure valueX are indeed local to threads */ + ASSERT_EQ(*value0, tid + 0, "value0"); + ASSERT_EQ(*value1, tid + 1, "value1"); + ASSERT_EQ(value2->a, tid + 2, "value2.a"); + ASSERT_EQ(value2->b, tid + 3, "value2.b"); + ASSERT_EQ(value2->c, tid + 4, "value2.c"); + ASSERT_EQ(value2->d, tid + 5, "value2.d"); + + *value0 = tid + 5; + *value1 = tid + 4; + value2->a = tid + 3; + value2->b = tid + 2; + value2->c = tid + 1; + value2->d = tid + 0; + + /* Run task_main again */ + pthread_mutex_lock(&global_mutex); + err = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.task_main), &opts); + ASSERT_OK(err, "run task_main"); + ASSERT_OK(opts.retval, "task_main retval"); + + ASSERT_EQ(skel->bss->test_value0, tid + 5, "tld_get_data value0"); + ASSERT_EQ(skel->bss->test_value1, tid + 4, "tld_get_data value1"); + ASSERT_EQ(skel->bss->test_value2.a, tid + 3, "tld_get_data value2.a"); + ASSERT_EQ(skel->bss->test_value2.b, tid + 2, "tld_get_data value2.b"); + ASSERT_EQ(skel->bss->test_value2.c, tid + 1, "tld_get_data value2.c"); + ASSERT_EQ(skel->bss->test_value2.d, tid + 0, "tld_get_data value2.d"); + pthread_mutex_unlock(&global_mutex); + +out: + pthread_exit(NULL); +} + +static void test_task_local_data_basic(void) +{ + struct test_task_local_data *skel; + pthread_t thread[TEST_BASIC_THREAD_NUM]; + char dummy_key_name[TLD_NAME_LEN]; + tld_key_t key; + int i, err; + + reset_tld(); + + ASSERT_OK(pthread_mutex_init(&global_mutex, NULL), "pthread_mutex_init"); + + skel = test_task_local_data__open_and_load(); + if (!ASSERT_OK_PTR(skel, "skel_open_and_load")) + return; + + tld_keys = calloc(TLD_MAX_DATA_CNT, sizeof(tld_key_t)); + if (!ASSERT_OK_PTR(tld_keys, "calloc tld_keys")) + goto out; + + ASSERT_FALSE(tld_key_is_err(value0_key), "TLD_DEFINE_KEY"); + tld_keys[1] = tld_create_key("value1", sizeof(int)); + ASSERT_FALSE(tld_key_is_err(tld_keys[1]), "tld_create_key"); + tld_keys[2] = tld_create_key("value2", sizeof(struct test_tld_struct)); + ASSERT_FALSE(tld_key_is_err(tld_keys[2]), "tld_create_key"); + + /* + * Shouldn't be able to store data exceed a page. Create a TLD just big + * enough to exceed a page. TLDs already created are int value0, int + * value1, and struct test_tld_struct value2. + */ + key = tld_create_key("value_not_exist", + TLD_PAGE_SIZE - 2 * sizeof(int) - sizeof(struct test_tld_struct) + 1); + ASSERT_EQ(tld_key_err_or_zero(key), -E2BIG, "tld_create_key"); + + key = tld_create_key("value2", sizeof(struct test_tld_struct)); + ASSERT_EQ(tld_key_err_or_zero(key), -EEXIST, "tld_create_key"); + + /* Shouldn't be able to create the (TLD_MAX_DATA_CNT+1)-th TLD */ + for (i = 3; i < TLD_MAX_DATA_CNT; i++) { + snprintf(dummy_key_name, TLD_NAME_LEN, "dummy_value%d", i); + tld_keys[i] = tld_create_key(dummy_key_name, sizeof(int)); + ASSERT_FALSE(tld_key_is_err(tld_keys[i]), "tld_create_key"); + } + key = tld_create_key("value_not_exist", sizeof(struct test_tld_struct)); + ASSERT_EQ(tld_key_err_or_zero(key), -ENOSPC, "tld_create_key"); + + /* Access TLDs from multiple threads and check if they are thread-specific */ + for (i = 0; i < TEST_BASIC_THREAD_NUM; i++) { + err = pthread_create(&thread[i], NULL, test_task_local_data_basic_thread, skel); + if (!ASSERT_OK(err, "pthread_create")) + goto out; + } + +out: + for (i = 0; i < TEST_BASIC_THREAD_NUM; i++) + pthread_join(thread[i], NULL); + + if (tld_keys) { + free(tld_keys); + tld_keys = NULL; + } + tld_free(); + test_task_local_data__destroy(skel); +} + +void test_task_local_data(void) +{ + if (test__start_subtest("task_local_data_basic")) + test_task_local_data_basic(); +} diff --git a/tools/testing/selftests/bpf/progs/test_task_local_data.c b/tools/testing/selftests/bpf/progs/test_task_local_data.c new file mode 100644 index 000000000000..fffafc013044 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_task_local_data.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include + +#include "task_local_data.bpf.h" + +struct tld_keys { + tld_key_t value0; + tld_key_t value1; + tld_key_t value2; + tld_key_t value_not_exist; +}; + +struct test_tld_struct { + __u64 a; + __u64 b; + __u64 c; + __u64 d; +}; + +int test_value0; +int test_value1; +struct test_tld_struct test_value2; + +SEC("syscall") +int task_main(void *ctx) +{ + struct tld_object tld_obj; + struct test_tld_struct *struct_p; + struct task_struct *task; + int err, *int_p; + + task = bpf_get_current_task_btf(); + err = tld_object_init(task, &tld_obj); + if (err) + return 1; + + int_p = tld_get_data(&tld_obj, value0, "value0", sizeof(int)); + if (int_p) + test_value0 = *int_p; + else + return 2; + + int_p = tld_get_data(&tld_obj, value1, "value1", sizeof(int)); + if (int_p) + test_value1 = *int_p; + else + return 3; + + struct_p = tld_get_data(&tld_obj, value2, "value2", sizeof(struct test_tld_struct)); + if (struct_p) + test_value2 = *struct_p; + else + return 4; + + int_p = tld_get_data(&tld_obj, value_not_exist, "value_not_exist", sizeof(int)); + if (int_p) + return 5; + + return 0; +} + +char _license[] SEC("license") = "GPL"; From 784181141782204f6dbbeadf01780e81da5fcb29 Mon Sep 17 00:00:00 2001 From: Amery Hung Date: Wed, 30 Jul 2025 11:58:55 -0700 Subject: [PATCH 00010/11391] selftests/bpf: Test concurrent task local data key creation Test thread-safety of tld_create_key(). Since tld_create_key() does not rely on locks but memory barriers and atomic operations to protect the shared metadata, the thread-safety of the function is non-trivial. Make sure concurrent tld_key_create(), both valid and invalid, can not race and corrupt metatada, which may leads to TLDs not being thread- specific or duplicate TLDs with the same name. Signed-off-by: Amery Hung Reviewed-by: Emil Tsalapatis Link: https://lore.kernel.org/r/20250730185903.3574598-5-ameryhung@gmail.com Signed-off-by: Alexei Starovoitov --- .../bpf/prog_tests/test_task_local_data.c | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/test_task_local_data.c b/tools/testing/selftests/bpf/prog_tests/test_task_local_data.c index 2e77d3fa2534..3b5cd2cd89c7 100644 --- a/tools/testing/selftests/bpf/prog_tests/test_task_local_data.c +++ b/tools/testing/selftests/bpf/prog_tests/test_task_local_data.c @@ -185,8 +185,113 @@ static void test_task_local_data_basic(void) test_task_local_data__destroy(skel); } +#define TEST_RACE_THREAD_NUM (TLD_MAX_DATA_CNT - 3) + +void *test_task_local_data_race_thread(void *arg) +{ + int err = 0, id = (intptr_t)arg; + char key_name[32]; + tld_key_t key; + + key = tld_create_key("value_not_exist", TLD_PAGE_SIZE + 1); + if (tld_key_err_or_zero(key) != -E2BIG) { + err = 1; + goto out; + } + + /* Only one thread will succeed in creating value1 */ + key = tld_create_key("value1", sizeof(int)); + if (!tld_key_is_err(key)) + tld_keys[1] = key; + + /* Only one thread will succeed in creating value2 */ + key = tld_create_key("value2", sizeof(struct test_tld_struct)); + if (!tld_key_is_err(key)) + tld_keys[2] = key; + + snprintf(key_name, 32, "thread_%d", id); + tld_keys[id] = tld_create_key(key_name, sizeof(int)); + if (tld_key_is_err(tld_keys[id])) + err = 2; +out: + return (void *)(intptr_t)err; +} + +static void test_task_local_data_race(void) +{ + LIBBPF_OPTS(bpf_test_run_opts, opts); + pthread_t thread[TEST_RACE_THREAD_NUM]; + struct test_task_local_data *skel; + int fd, i, j, err, *data; + void *ret = NULL; + + skel = test_task_local_data__open_and_load(); + if (!ASSERT_OK_PTR(skel, "skel_open_and_load")) + return; + + tld_keys = calloc(TLD_MAX_DATA_CNT, sizeof(tld_key_t)); + if (!ASSERT_OK_PTR(tld_keys, "calloc tld_keys")) + goto out; + + fd = bpf_map__fd(skel->maps.tld_data_map); + + ASSERT_FALSE(tld_key_is_err(value0_key), "TLD_DEFINE_KEY"); + tld_keys[0] = value0_key; + + for (j = 0; j < 100; j++) { + reset_tld(); + + for (i = 0; i < TEST_RACE_THREAD_NUM; i++) { + /* + * Try to make tld_create_key() race with each other. Call + * tld_create_key(), both valid and invalid, from different threads. + */ + err = pthread_create(&thread[i], NULL, test_task_local_data_race_thread, + (void *)(intptr_t)(i + 3)); + if (CHECK_FAIL(err)) + break; + } + + /* Wait for all tld_create_key() to return */ + for (i = 0; i < TEST_RACE_THREAD_NUM; i++) { + pthread_join(thread[i], &ret); + if (CHECK_FAIL(ret)) + break; + } + + /* Write a unique number to each TLD */ + for (i = 0; i < TLD_MAX_DATA_CNT; i++) { + data = tld_get_data(fd, tld_keys[i]); + if (CHECK_FAIL(!data)) + break; + *data = i; + } + + /* Read TLDs and check the value to see if any address collides with another */ + for (i = 0; i < TLD_MAX_DATA_CNT; i++) { + data = tld_get_data(fd, tld_keys[i]); + if (CHECK_FAIL(*data != i)) + break; + } + + /* Run task_main to make sure no invalid TLDs are added */ + err = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.task_main), &opts); + ASSERT_OK(err, "run task_main"); + ASSERT_OK(opts.retval, "task_main retval"); + } +out: + if (tld_keys) { + free(tld_keys); + tld_keys = NULL; + } + tld_free(); + test_task_local_data__destroy(skel); +} + void test_task_local_data(void) { if (test__start_subtest("task_local_data_basic")) test_task_local_data_basic(); + if (test__start_subtest("task_local_data_race")) + test_task_local_data_race(); } From 2d812311c2b28cc9096e29862a957aeb32bfdb76 Mon Sep 17 00:00:00 2001 From: Tao Chen Date: Wed, 23 Jul 2025 22:44:40 +0800 Subject: [PATCH 00011/11391] bpftool: Add bpf_token show Add `bpftool token show` command to get token info from bpffs in /proc/mounts. Example plain output for `token show`: token_info /sys/fs/bpf/token allowed_cmds: map_create prog_load allowed_maps: allowed_progs: kprobe allowed_attachs: xdp token_info /sys/fs/bpf/token2 allowed_cmds: map_create prog_load allowed_maps: allowed_progs: kprobe allowed_attachs: xdp Example json output for `token show`: [{ "token_info": "/sys/fs/bpf/token", "allowed_cmds": ["map_create", "prog_load"], "allowed_maps": [], "allowed_progs": ["kprobe"], "allowed_attachs": ["xdp"] }, { "token_info": "/sys/fs/bpf/token2", "allowed_cmds": ["map_create", "prog_load"], "allowed_maps": [], "allowed_progs": ["kprobe"], "allowed_attachs": ["xdp"] }] Reviewed-by: Quentin Monnet Signed-off-by: Tao Chen Link: https://lore.kernel.org/r/20250723144442.1427943-1-chen.dylane@linux.dev Signed-off-by: Alexei Starovoitov --- tools/bpf/bpftool/main.c | 3 +- tools/bpf/bpftool/main.h | 1 + tools/bpf/bpftool/token.c | 225 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 tools/bpf/bpftool/token.c diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c index 2b7f2bd3a7db..0f1183b2ed0a 100644 --- a/tools/bpf/bpftool/main.c +++ b/tools/bpf/bpftool/main.c @@ -61,7 +61,7 @@ static int do_help(int argc, char **argv) " %s batch file FILE\n" " %s version\n" "\n" - " OBJECT := { prog | map | link | cgroup | perf | net | feature | btf | gen | struct_ops | iter }\n" + " OBJECT := { prog | map | link | cgroup | perf | net | feature | btf | gen | struct_ops | iter | token }\n" " " HELP_SPEC_OPTIONS " |\n" " {-V|--version} }\n" "", @@ -87,6 +87,7 @@ static const struct cmd commands[] = { { "gen", do_gen }, { "struct_ops", do_struct_ops }, { "iter", do_iter }, + { "token", do_token }, { "version", do_version }, { 0 } }; diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h index 6db704fda5c0..a2bb0714b3d6 100644 --- a/tools/bpf/bpftool/main.h +++ b/tools/bpf/bpftool/main.h @@ -166,6 +166,7 @@ int do_tracelog(int argc, char **arg) __weak; int do_feature(int argc, char **argv) __weak; int do_struct_ops(int argc, char **argv) __weak; int do_iter(int argc, char **argv) __weak; +int do_token(int argc, char **argv) __weak; int parse_u32_arg(int *argc, char ***argv, __u32 *val, const char *what); int prog_parse_fd(int *argc, char ***argv); diff --git a/tools/bpf/bpftool/token.c b/tools/bpf/bpftool/token.c new file mode 100644 index 000000000000..6312e662a129 --- /dev/null +++ b/tools/bpf/bpftool/token.c @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2025 Didi Technology Co., Tao Chen */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "json_writer.h" +#include "main.h" + +#define MOUNTS_FILE "/proc/mounts" + +static bool has_delegate_options(const char *mnt_ops) +{ + return strstr(mnt_ops, "delegate_cmds") || + strstr(mnt_ops, "delegate_maps") || + strstr(mnt_ops, "delegate_progs") || + strstr(mnt_ops, "delegate_attachs"); +} + +static char *get_delegate_value(const char *opts, const char *key) +{ + char *token, *rest, *ret = NULL; + char *opts_copy = strdup(opts); + + if (!opts_copy) + return NULL; + + for (token = strtok_r(opts_copy, ",", &rest); token; + token = strtok_r(NULL, ",", &rest)) { + if (strncmp(token, key, strlen(key)) == 0 && + token[strlen(key)] == '=') { + ret = token + strlen(key) + 1; + break; + } + } + free(opts_copy); + + return ret; +} + +static void print_items_per_line(const char *input, int items_per_line) +{ + char *str, *rest, *strs; + int cnt = 0; + + if (!input) + return; + + strs = strdup(input); + if (!strs) + return; + + for (str = strtok_r(strs, ":", &rest); str; + str = strtok_r(NULL, ":", &rest)) { + if (cnt % items_per_line == 0) + printf("\n\t "); + + printf("%-20s", str); + cnt++; + } + + free(strs); +} + +#define ITEMS_PER_LINE 4 +static void show_token_info_plain(struct mntent *mntent) +{ + char *value; + + printf("token_info %s", mntent->mnt_dir); + + printf("\n\tallowed_cmds:"); + value = get_delegate_value(mntent->mnt_opts, "delegate_cmds"); + print_items_per_line(value, ITEMS_PER_LINE); + + printf("\n\tallowed_maps:"); + value = get_delegate_value(mntent->mnt_opts, "delegate_maps"); + print_items_per_line(value, ITEMS_PER_LINE); + + printf("\n\tallowed_progs:"); + value = get_delegate_value(mntent->mnt_opts, "delegate_progs"); + print_items_per_line(value, ITEMS_PER_LINE); + + printf("\n\tallowed_attachs:"); + value = get_delegate_value(mntent->mnt_opts, "delegate_attachs"); + print_items_per_line(value, ITEMS_PER_LINE); + printf("\n"); +} + +static void split_json_array_str(const char *input) +{ + char *str, *rest, *strs; + + if (!input) { + jsonw_start_array(json_wtr); + jsonw_end_array(json_wtr); + return; + } + + strs = strdup(input); + if (!strs) + return; + + jsonw_start_array(json_wtr); + for (str = strtok_r(strs, ":", &rest); str; + str = strtok_r(NULL, ":", &rest)) { + jsonw_string(json_wtr, str); + } + jsonw_end_array(json_wtr); + + free(strs); +} + +static void show_token_info_json(struct mntent *mntent) +{ + char *value; + + jsonw_start_object(json_wtr); + + jsonw_string_field(json_wtr, "token_info", mntent->mnt_dir); + + jsonw_name(json_wtr, "allowed_cmds"); + value = get_delegate_value(mntent->mnt_opts, "delegate_cmds"); + split_json_array_str(value); + + jsonw_name(json_wtr, "allowed_maps"); + value = get_delegate_value(mntent->mnt_opts, "delegate_maps"); + split_json_array_str(value); + + jsonw_name(json_wtr, "allowed_progs"); + value = get_delegate_value(mntent->mnt_opts, "delegate_progs"); + split_json_array_str(value); + + jsonw_name(json_wtr, "allowed_attachs"); + value = get_delegate_value(mntent->mnt_opts, "delegate_attachs"); + split_json_array_str(value); + + jsonw_end_object(json_wtr); +} + +static int __show_token_info(struct mntent *mntent) +{ + if (json_output) + show_token_info_json(mntent); + else + show_token_info_plain(mntent); + + return 0; +} + +static int show_token_info(void) +{ + FILE *fp; + struct mntent *ent; + + fp = setmntent(MOUNTS_FILE, "r"); + if (!fp) { + p_err("Failed to open: %s", MOUNTS_FILE); + return -1; + } + + if (json_output) + jsonw_start_array(json_wtr); + + while ((ent = getmntent(fp)) != NULL) { + if (strncmp(ent->mnt_type, "bpf", 3) == 0) { + if (has_delegate_options(ent->mnt_opts)) + __show_token_info(ent); + } + } + + if (json_output) + jsonw_end_array(json_wtr); + + endmntent(fp); + + return 0; +} + +static int do_show(int argc, char **argv) +{ + if (argc) + return BAD_ARG(); + + return show_token_info(); +} + +static int do_help(int argc, char **argv) +{ + if (json_output) { + jsonw_null(json_wtr); + return 0; + } + + fprintf(stderr, + "Usage: %1$s %2$s { show | list }\n" + " %1$s %2$s help\n" + "\n" + "", + bin_name, argv[-2]); + return 0; +} + +static const struct cmd cmds[] = { + { "show", do_show }, + { "list", do_show }, + { "help", do_help }, + { 0 } +}; + +int do_token(int argc, char **argv) +{ + return cmd_select(cmds, argc, argv, do_help); +} From b7f6400849162b918020c5d10d5b7f378afbf470 Mon Sep 17 00:00:00 2001 From: Tao Chen Date: Wed, 23 Jul 2025 22:44:41 +0800 Subject: [PATCH 00012/11391] bpftool: Add bpftool-token manpage Add bpftool-token manpage with information and examples of token-related commands. Suggested-by: Quentin Monnet Reviewed-by: Quentin Monnet Signed-off-by: Tao Chen Link: https://lore.kernel.org/r/20250723144442.1427943-2-chen.dylane@linux.dev Signed-off-by: Alexei Starovoitov --- .../bpftool/Documentation/bpftool-token.rst | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 tools/bpf/bpftool/Documentation/bpftool-token.rst diff --git a/tools/bpf/bpftool/Documentation/bpftool-token.rst b/tools/bpf/bpftool/Documentation/bpftool-token.rst new file mode 100644 index 000000000000..d082c499cfe3 --- /dev/null +++ b/tools/bpf/bpftool/Documentation/bpftool-token.rst @@ -0,0 +1,64 @@ +.. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) + +================ +bpftool-token +================ +------------------------------------------------------------------------------- +tool for inspection and simple manipulation of eBPF tokens +------------------------------------------------------------------------------- + +:Manual section: 8 + +.. include:: substitutions.rst + +SYNOPSIS +======== + +**bpftool** [*OPTIONS*] **token** *COMMAND* + +*OPTIONS* := { |COMMON_OPTIONS| } + +*COMMANDS* := { **show** | **list** | **help** } + +TOKEN COMMANDS +=============== + +| **bpftool** **token** { **show** | **list** } +| **bpftool** **token help** +| + +DESCRIPTION +=========== +bpftool token { show | list } + List BPF token information for each *bpffs* mount point containing token + information on the system. Information include mount point path, allowed + **bpf**\ () system call commands, maps, programs, and attach types for the + token. + +bpftool prog help + Print short help message. + +OPTIONS +======== +.. include:: common_options.rst + +EXAMPLES +======== +| +| **# mkdir -p /sys/fs/bpf/token** +| **# mount -t bpf bpffs /sys/fs/bpf/token** \ +| **-o delegate_cmds=prog_load:map_create** \ +| **-o delegate_progs=kprobe** \ +| **-o delegate_attachs=xdp** +| **# bpftool token list** + +:: + + token_info /sys/fs/bpf/token + allowed_cmds: + map_create prog_load + allowed_maps: + allowed_progs: + kprobe + allowed_attachs: + xdp From f3af62b6cee8af9f07012051874af2d2a451f0e5 Mon Sep 17 00:00:00 2001 From: Tao Chen Date: Wed, 23 Jul 2025 22:44:42 +0800 Subject: [PATCH 00013/11391] bpftool: Add bash completion for token argument This commit updates the bash completion script with the new token argument. $ bpftool token help list show Reviewed-by: Quentin Monnet Signed-off-by: Tao Chen Link: https://lore.kernel.org/r/20250723144442.1427943-3-chen.dylane@linux.dev Signed-off-by: Alexei Starovoitov --- tools/bpf/bpftool/bash-completion/bpftool | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool index a759ba24471d..527bb47ac462 100644 --- a/tools/bpf/bpftool/bash-completion/bpftool +++ b/tools/bpf/bpftool/bash-completion/bpftool @@ -1215,6 +1215,17 @@ _bpftool() ;; esac ;; + token) + case $command in + show|list) + return 0 + ;; + *) + [[ $prev == $object ]] && \ + COMPREPLY=( $( compgen -W 'help show list' -- "$cur" ) ) + ;; + esac + ;; esac } && complete -F _bpftool bpftool From 1faa0d62a19bb8a4b9022b603472e7127974cb55 Mon Sep 17 00:00:00 2001 From: Akhilesh Patil Date: Fri, 18 Jul 2025 21:00:13 +0530 Subject: [PATCH 00014/11391] drivers: tee: improve sysfs interface by using sysfs_emit() Replace scnprintf() with sysfs_emit() while formatting buffer that is passed to userspace as per the recommendation in Documentation/filesystems/sysfs.rst. sysfs _show() callbacks should use sysfs_emit() or sysfs_emit_at() while returning values to the userspace. This change does not impact functionality, but aligns with sysfs interface usage guidelines for the tee driver. Signed-off-by: Akhilesh Patil Reviewed-by: Sumit Garg Signed-off-by: Jens Wiklander --- drivers/tee/optee/core.c | 2 +- drivers/tee/tee_core.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c index c75fddc83576..ce44e3498d37 100644 --- a/drivers/tee/optee/core.c +++ b/drivers/tee/optee/core.c @@ -72,7 +72,7 @@ static ssize_t rpmb_routing_model_show(struct device *dev, else s = "user"; - return scnprintf(buf, PAGE_SIZE, "%s\n", s); + return sysfs_emit(buf, "%s\n", s); } static DEVICE_ATTR_RO(rpmb_routing_model); diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c index acc7998758ad..944f913f8592 100644 --- a/drivers/tee/tee_core.c +++ b/drivers/tee/tee_core.c @@ -977,7 +977,7 @@ static ssize_t implementation_id_show(struct device *dev, struct tee_ioctl_version_data vers; teedev->desc->ops->get_version(teedev, &vers); - return scnprintf(buf, PAGE_SIZE, "%d\n", vers.impl_id); + return sysfs_emit(buf, "%d\n", vers.impl_id); } static DEVICE_ATTR_RO(implementation_id); From d87a513d093726d121dd5c816e26803111a259d0 Mon Sep 17 00:00:00 2001 From: Amery Hung Date: Wed, 6 Aug 2025 09:25:38 -0700 Subject: [PATCH 00015/11391] bpf: Allow struct_ops to get map id by kdata Add bpf_struct_ops_id() to enable struct_ops implementors to use struct_ops map id as the unique id of a struct_ops in their subsystem. A subsystem that wishes to create a mapping between id and struct_ops instance pointer can update the mapping accordingly during bpf_struct_ops::reg(), unreg(), and update(). Signed-off-by: Amery Hung Signed-off-by: Martin KaFai Lau Link: https://patch.msgid.link/20250806162540.681679-2-ameryhung@gmail.com --- include/linux/bpf.h | 1 + kernel/bpf/bpf_struct_ops.c | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index cc700925b802..e7ee089e8a31 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1985,6 +1985,7 @@ static inline void bpf_module_put(const void *data, struct module *owner) module_put(owner); } int bpf_struct_ops_link_create(union bpf_attr *attr); +u32 bpf_struct_ops_id(const void *kdata); #ifdef CONFIG_NET /* Define it here to avoid the use of forward declaration */ diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c index 687a3e9c76f5..a41e6730edcf 100644 --- a/kernel/bpf/bpf_struct_ops.c +++ b/kernel/bpf/bpf_struct_ops.c @@ -1174,6 +1174,18 @@ void bpf_struct_ops_put(const void *kdata) bpf_map_put(&st_map->map); } +u32 bpf_struct_ops_id(const void *kdata) +{ + struct bpf_struct_ops_value *kvalue; + struct bpf_struct_ops_map *st_map; + + kvalue = container_of(kdata, struct bpf_struct_ops_value, data); + st_map = container_of(kvalue, struct bpf_struct_ops_map, kvalue); + + return st_map->map.id; +} +EXPORT_SYMBOL_GPL(bpf_struct_ops_id); + static bool bpf_struct_ops_valid_to_reg(struct bpf_map *map) { struct bpf_struct_ops_map *st_map = (struct bpf_struct_ops_map *)map; From eeb52b6279cfebae07703f772621fb9d5972e541 Mon Sep 17 00:00:00 2001 From: Amery Hung Date: Wed, 6 Aug 2025 09:25:39 -0700 Subject: [PATCH 00016/11391] selftests/bpf: Add multi_st_ops that supports multiple instances Current struct_ops in bpf_testmod only support attaching single instance. Add multi_st_ops that supports multiple instances. The struct_ops uses map id as the struct_ops id and will reject attachment with an existing id. Signed-off-by: Amery Hung Signed-off-by: Martin KaFai Lau Link: https://patch.msgid.link/20250806162540.681679-3-ameryhung@gmail.com --- .../selftests/bpf/test_kmods/bpf_testmod.c | 112 ++++++++++++++++++ .../selftests/bpf/test_kmods/bpf_testmod.h | 6 + .../bpf/test_kmods/bpf_testmod_kfunc.h | 2 + 3 files changed, 120 insertions(+) diff --git a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c index e9e918cdf31f..2beb9b2fcbd8 100644 --- a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c +++ b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c @@ -1057,6 +1057,8 @@ __bpf_kfunc int bpf_kfunc_st_ops_inc10(struct st_ops_args *args) return args->a; } +__bpf_kfunc int bpf_kfunc_multi_st_ops_test_1(struct st_ops_args *args, u32 id); + BTF_KFUNCS_START(bpf_testmod_check_kfunc_ids) BTF_ID_FLAGS(func, bpf_testmod_test_mod_kfunc) BTF_ID_FLAGS(func, bpf_kfunc_call_test1) @@ -1097,6 +1099,7 @@ BTF_ID_FLAGS(func, bpf_kfunc_st_ops_test_prologue, KF_TRUSTED_ARGS | KF_SLEEPABL BTF_ID_FLAGS(func, bpf_kfunc_st_ops_test_epilogue, KF_TRUSTED_ARGS | KF_SLEEPABLE) BTF_ID_FLAGS(func, bpf_kfunc_st_ops_test_pro_epilogue, KF_TRUSTED_ARGS | KF_SLEEPABLE) BTF_ID_FLAGS(func, bpf_kfunc_st_ops_inc10, KF_TRUSTED_ARGS) +BTF_ID_FLAGS(func, bpf_kfunc_multi_st_ops_test_1, KF_TRUSTED_ARGS) BTF_KFUNCS_END(bpf_testmod_check_kfunc_ids) static int bpf_testmod_ops_init(struct btf *btf) @@ -1528,6 +1531,114 @@ static struct bpf_struct_ops testmod_st_ops = { .owner = THIS_MODULE, }; +struct hlist_head multi_st_ops_list; +static DEFINE_SPINLOCK(multi_st_ops_lock); + +static int multi_st_ops_init(struct btf *btf) +{ + spin_lock_init(&multi_st_ops_lock); + INIT_HLIST_HEAD(&multi_st_ops_list); + + return 0; +} + +static int multi_st_ops_init_member(const struct btf_type *t, + const struct btf_member *member, + void *kdata, const void *udata) +{ + return 0; +} + +static struct bpf_testmod_multi_st_ops *multi_st_ops_find_nolock(u32 id) +{ + struct bpf_testmod_multi_st_ops *st_ops; + + hlist_for_each_entry(st_ops, &multi_st_ops_list, node) { + if (st_ops->id == id) + return st_ops; + } + + return NULL; +} + +int bpf_kfunc_multi_st_ops_test_1(struct st_ops_args *args, u32 id) +{ + struct bpf_testmod_multi_st_ops *st_ops; + unsigned long flags; + int ret = -1; + + spin_lock_irqsave(&multi_st_ops_lock, flags); + st_ops = multi_st_ops_find_nolock(id); + if (st_ops) + ret = st_ops->test_1(args); + spin_unlock_irqrestore(&multi_st_ops_lock, flags); + + return ret; +} + +static int multi_st_ops_reg(void *kdata, struct bpf_link *link) +{ + struct bpf_testmod_multi_st_ops *st_ops = + (struct bpf_testmod_multi_st_ops *)kdata; + unsigned long flags; + int err = 0; + u32 id; + + if (!st_ops->test_1) + return -EINVAL; + + id = bpf_struct_ops_id(kdata); + + spin_lock_irqsave(&multi_st_ops_lock, flags); + if (multi_st_ops_find_nolock(id)) { + pr_err("multi_st_ops(id:%d) has already been registered\n", id); + err = -EEXIST; + goto unlock; + } + + st_ops->id = id; + hlist_add_head(&st_ops->node, &multi_st_ops_list); +unlock: + spin_unlock_irqrestore(&multi_st_ops_lock, flags); + + return err; +} + +static void multi_st_ops_unreg(void *kdata, struct bpf_link *link) +{ + struct bpf_testmod_multi_st_ops *st_ops; + unsigned long flags; + u32 id; + + id = bpf_struct_ops_id(kdata); + + spin_lock_irqsave(&multi_st_ops_lock, flags); + st_ops = multi_st_ops_find_nolock(id); + if (st_ops) + hlist_del(&st_ops->node); + spin_unlock_irqrestore(&multi_st_ops_lock, flags); +} + +static int bpf_testmod_multi_st_ops__test_1(struct st_ops_args *args) +{ + return 0; +} + +static struct bpf_testmod_multi_st_ops multi_st_ops_cfi_stubs = { + .test_1 = bpf_testmod_multi_st_ops__test_1, +}; + +struct bpf_struct_ops testmod_multi_st_ops = { + .verifier_ops = &bpf_testmod_verifier_ops, + .init = multi_st_ops_init, + .init_member = multi_st_ops_init_member, + .reg = multi_st_ops_reg, + .unreg = multi_st_ops_unreg, + .cfi_stubs = &multi_st_ops_cfi_stubs, + .name = "bpf_testmod_multi_st_ops", + .owner = THIS_MODULE, +}; + extern int bpf_fentry_test1(int a); static int bpf_testmod_init(void) @@ -1550,6 +1661,7 @@ static int bpf_testmod_init(void) ret = ret ?: register_bpf_struct_ops(&bpf_testmod_ops2, bpf_testmod_ops2); ret = ret ?: register_bpf_struct_ops(&bpf_testmod_ops3, bpf_testmod_ops3); ret = ret ?: register_bpf_struct_ops(&testmod_st_ops, bpf_testmod_st_ops); + ret = ret ?: register_bpf_struct_ops(&testmod_multi_st_ops, bpf_testmod_multi_st_ops); ret = ret ?: register_btf_id_dtor_kfuncs(bpf_testmod_dtors, ARRAY_SIZE(bpf_testmod_dtors), THIS_MODULE); diff --git a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.h b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.h index c9fab51f16e2..f6e492f9d042 100644 --- a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.h +++ b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.h @@ -116,4 +116,10 @@ struct bpf_testmod_st_ops { struct module *owner; }; +struct bpf_testmod_multi_st_ops { + int (*test_1)(struct st_ops_args *args); + struct hlist_node node; + int id; +}; + #endif /* _BPF_TESTMOD_H */ diff --git a/tools/testing/selftests/bpf/test_kmods/bpf_testmod_kfunc.h b/tools/testing/selftests/bpf/test_kmods/bpf_testmod_kfunc.h index b58817938deb..286e7faa4754 100644 --- a/tools/testing/selftests/bpf/test_kmods/bpf_testmod_kfunc.h +++ b/tools/testing/selftests/bpf/test_kmods/bpf_testmod_kfunc.h @@ -159,4 +159,6 @@ void bpf_kfunc_trusted_task_test(struct task_struct *ptr) __ksym; void bpf_kfunc_trusted_num_test(int *ptr) __ksym; void bpf_kfunc_rcu_task_test(struct task_struct *ptr) __ksym; +int bpf_kfunc_multi_st_ops_test_1(struct st_ops_args *args, u32 id) __ksym; + #endif /* _BPF_TESTMOD_KFUNC_H */ From ba7000f1c360f34286f48bd5e670cefbab77ce8f Mon Sep 17 00:00:00 2001 From: Amery Hung Date: Wed, 6 Aug 2025 09:25:40 -0700 Subject: [PATCH 00017/11391] selftests/bpf: Test multi_st_ops and calling kfuncs from different programs Test multi_st_ops and demonstrate how different bpf programs can call a kfuncs that refers to the struct_ops instance in the same source file by id. The id is defined as a global vairable and initialized before attaching the skeleton. Kfuncs that take the id can hide the argument with a macro to make it almost transparent to bpf program developers. The test involves two struct_ops returning different values from .test_1. In syscall and tracing programs, check if the correct value is returned by a kfunc that calls .test_1. Signed-off-by: Amery Hung Signed-off-by: Martin KaFai Lau Link: https://patch.msgid.link/20250806162540.681679-4-ameryhung@gmail.com --- .../test_struct_ops_id_ops_mapping.c | 74 +++++++++++++++++++ .../bpf/progs/struct_ops_id_ops_mapping1.c | 59 +++++++++++++++ .../bpf/progs/struct_ops_id_ops_mapping2.c | 59 +++++++++++++++ 3 files changed, 192 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/test_struct_ops_id_ops_mapping.c create mode 100644 tools/testing/selftests/bpf/progs/struct_ops_id_ops_mapping1.c create mode 100644 tools/testing/selftests/bpf/progs/struct_ops_id_ops_mapping2.c diff --git a/tools/testing/selftests/bpf/prog_tests/test_struct_ops_id_ops_mapping.c b/tools/testing/selftests/bpf/prog_tests/test_struct_ops_id_ops_mapping.c new file mode 100644 index 000000000000..fd8762ba4b67 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/test_struct_ops_id_ops_mapping.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include "struct_ops_id_ops_mapping1.skel.h" +#include "struct_ops_id_ops_mapping2.skel.h" + +static void test_st_ops_id_ops_mapping(void) +{ + struct struct_ops_id_ops_mapping1 *skel1 = NULL; + struct struct_ops_id_ops_mapping2 *skel2 = NULL; + struct bpf_map_info info = {}; + __u32 len = sizeof(info); + int err, pid, prog1_fd, prog2_fd; + + skel1 = struct_ops_id_ops_mapping1__open_and_load(); + if (!ASSERT_OK_PTR(skel1, "struct_ops_id_ops_mapping1__open")) + goto out; + + skel2 = struct_ops_id_ops_mapping2__open_and_load(); + if (!ASSERT_OK_PTR(skel2, "struct_ops_id_ops_mapping2__open")) + goto out; + + err = bpf_map_get_info_by_fd(bpf_map__fd(skel1->maps.st_ops_map), + &info, &len); + if (!ASSERT_OK(err, "bpf_map_get_info_by_fd")) + goto out; + + skel1->bss->st_ops_id = info.id; + + err = bpf_map_get_info_by_fd(bpf_map__fd(skel2->maps.st_ops_map), + &info, &len); + if (!ASSERT_OK(err, "bpf_map_get_info_by_fd")) + goto out; + + skel2->bss->st_ops_id = info.id; + + err = struct_ops_id_ops_mapping1__attach(skel1); + if (!ASSERT_OK(err, "struct_ops_id_ops_mapping1__attach")) + goto out; + + err = struct_ops_id_ops_mapping2__attach(skel2); + if (!ASSERT_OK(err, "struct_ops_id_ops_mapping2__attach")) + goto out; + + /* run tracing prog that calls .test_1 and checks return */ + pid = getpid(); + skel1->bss->test_pid = pid; + skel2->bss->test_pid = pid; + sys_gettid(); + skel1->bss->test_pid = 0; + skel2->bss->test_pid = 0; + + /* run syscall_prog that calls .test_1 and checks return */ + prog1_fd = bpf_program__fd(skel1->progs.syscall_prog); + err = bpf_prog_test_run_opts(prog1_fd, NULL); + ASSERT_OK(err, "bpf_prog_test_run_opts"); + + prog2_fd = bpf_program__fd(skel2->progs.syscall_prog); + err = bpf_prog_test_run_opts(prog2_fd, NULL); + ASSERT_OK(err, "bpf_prog_test_run_opts"); + + ASSERT_EQ(skel1->bss->test_err, 0, "skel1->bss->test_err"); + ASSERT_EQ(skel2->bss->test_err, 0, "skel2->bss->test_err"); + +out: + struct_ops_id_ops_mapping1__destroy(skel1); + struct_ops_id_ops_mapping2__destroy(skel2); +} + +void test_struct_ops_id_ops_mapping(void) +{ + if (test__start_subtest("st_ops_id_ops_mapping")) + test_st_ops_id_ops_mapping(); +} diff --git a/tools/testing/selftests/bpf/progs/struct_ops_id_ops_mapping1.c b/tools/testing/selftests/bpf/progs/struct_ops_id_ops_mapping1.c new file mode 100644 index 000000000000..ad8bb546c9bf --- /dev/null +++ b/tools/testing/selftests/bpf/progs/struct_ops_id_ops_mapping1.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include "bpf_misc.h" +#include "../test_kmods/bpf_testmod.h" +#include "../test_kmods/bpf_testmod_kfunc.h" + +char _license[] SEC("license") = "GPL"; + +#define bpf_kfunc_multi_st_ops_test_1(args) bpf_kfunc_multi_st_ops_test_1(args, st_ops_id) +int st_ops_id; + +int test_pid; +int test_err; + +#define MAP1_MAGIC 1234 + +SEC("struct_ops") +int BPF_PROG(test_1, struct st_ops_args *args) +{ + return MAP1_MAGIC; +} + +SEC("tp_btf/sys_enter") +int BPF_PROG(sys_enter, struct pt_regs *regs, long id) +{ + struct st_ops_args args = {}; + struct task_struct *task; + int ret; + + task = bpf_get_current_task_btf(); + if (!test_pid || task->pid != test_pid) + return 0; + + ret = bpf_kfunc_multi_st_ops_test_1(&args); + if (ret != MAP1_MAGIC) + test_err++; + + return 0; +} + +SEC("syscall") +int syscall_prog(void *ctx) +{ + struct st_ops_args args = {}; + int ret; + + ret = bpf_kfunc_multi_st_ops_test_1(&args); + if (ret != MAP1_MAGIC) + test_err++; + + return 0; +} + +SEC(".struct_ops.link") +struct bpf_testmod_multi_st_ops st_ops_map = { + .test_1 = (void *)test_1, +}; diff --git a/tools/testing/selftests/bpf/progs/struct_ops_id_ops_mapping2.c b/tools/testing/selftests/bpf/progs/struct_ops_id_ops_mapping2.c new file mode 100644 index 000000000000..cea1a2f4b62f --- /dev/null +++ b/tools/testing/selftests/bpf/progs/struct_ops_id_ops_mapping2.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include "bpf_misc.h" +#include "../test_kmods/bpf_testmod.h" +#include "../test_kmods/bpf_testmod_kfunc.h" + +char _license[] SEC("license") = "GPL"; + +#define bpf_kfunc_multi_st_ops_test_1(args) bpf_kfunc_multi_st_ops_test_1(args, st_ops_id) +int st_ops_id; + +int test_pid; +int test_err; + +#define MAP2_MAGIC 4567 + +SEC("struct_ops") +int BPF_PROG(test_1, struct st_ops_args *args) +{ + return MAP2_MAGIC; +} + +SEC("tp_btf/sys_enter") +int BPF_PROG(sys_enter, struct pt_regs *regs, long id) +{ + struct st_ops_args args = {}; + struct task_struct *task; + int ret; + + task = bpf_get_current_task_btf(); + if (!test_pid || task->pid != test_pid) + return 0; + + ret = bpf_kfunc_multi_st_ops_test_1(&args); + if (ret != MAP2_MAGIC) + test_err++; + + return 0; +} + +SEC("syscall") +int syscall_prog(void *ctx) +{ + struct st_ops_args args = {}; + int ret; + + ret = bpf_kfunc_multi_st_ops_test_1(&args); + if (ret != MAP2_MAGIC) + test_err++; + + return 0; +} + +SEC(".struct_ops.link") +struct bpf_testmod_multi_st_ops st_ops_map = { + .test_1 = (void *)test_1, +}; From cb070a8156c16383cad5e4d9f678b7273f0208cd Mon Sep 17 00:00:00 2001 From: Eduard Zingerman Date: Wed, 6 Aug 2025 18:02:04 -0700 Subject: [PATCH 00018/11391] bpf: removed unused 'env' parameter from is_reg64 and insn_has_def32 Parameter 'env' is not used by is_reg64() and insn_has_def32() functions. Remove the parameter to make it clear that neither function depends on 'env' state, e.g. env->insn_aux_data. Signed-off-by: Eduard Zingerman Acked-by: Kumar Kartikeya Dwivedi Link: https://lore.kernel.org/r/20250807010205.3210608-2-eddyz87@gmail.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 0806295945e4..69eb2b5c2218 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -3663,7 +3663,7 @@ static int mark_irq_flag_read(struct bpf_verifier_env *env, struct bpf_reg_state * code only. It returns TRUE if the source or destination register operates * on 64-bit, otherwise return FALSE. */ -static bool is_reg64(struct bpf_verifier_env *env, struct bpf_insn *insn, +static bool is_reg64(struct bpf_insn *insn, u32 regno, struct bpf_reg_state *reg, enum reg_arg_type t) { u8 code, class, op; @@ -3774,14 +3774,14 @@ static int insn_def_regno(const struct bpf_insn *insn) } /* Return TRUE if INSN has defined any 32-bit value explicitly. */ -static bool insn_has_def32(struct bpf_verifier_env *env, struct bpf_insn *insn) +static bool insn_has_def32(struct bpf_insn *insn) { int dst_reg = insn_def_regno(insn); if (dst_reg == -1) return false; - return !is_reg64(env, insn, dst_reg, NULL, DST_OP); + return !is_reg64(insn, dst_reg, NULL, DST_OP); } static void mark_insn_zext(struct bpf_verifier_env *env, @@ -3812,7 +3812,7 @@ static int __check_reg_arg(struct bpf_verifier_env *env, struct bpf_reg_state *r mark_reg_scratched(env, regno); reg = ®s[regno]; - rw64 = is_reg64(env, insn, regno, reg, t); + rw64 = is_reg64(insn, regno, reg, t); if (t == SRC_OP) { /* check whether register used as source operand can be read */ if (reg->type == NOT_INIT) { @@ -20712,7 +20712,7 @@ static void adjust_insn_aux_data(struct bpf_verifier_env *env, * (cnt == 1) is taken or not. There is no guarantee INSN at OFF is the * original insn at old prog. */ - old_data[off].zext_dst = insn_has_def32(env, insn + off + cnt - 1); + old_data[off].zext_dst = insn_has_def32(insn + off + cnt - 1); if (cnt == 1) return; @@ -20724,7 +20724,7 @@ static void adjust_insn_aux_data(struct bpf_verifier_env *env, for (i = off; i < off + cnt - 1; i++) { /* Expand insni[off]'s seen count to the patched range. */ new_data[i].seen = old_seen; - new_data[i].zext_dst = insn_has_def32(env, insn + i); + new_data[i].zext_dst = insn_has_def32(insn + i); } env->insn_aux_data = new_data; vfree(old_data); @@ -21131,7 +21131,7 @@ static int opt_subreg_zext_lo32_rnd_hi32(struct bpf_verifier_env *env, * BPF_STX + SRC_OP, so it is safe to pass NULL * here. */ - if (is_reg64(env, &insn, load_reg, NULL, DST_OP)) { + if (is_reg64(&insn, load_reg, NULL, DST_OP)) { if (class == BPF_LD && BPF_MODE(code) == BPF_IMM) i++; From 77620d1267392b1a34bfc437d2adea3006f95865 Mon Sep 17 00:00:00 2001 From: Eduard Zingerman Date: Wed, 6 Aug 2025 18:02:05 -0700 Subject: [PATCH 00019/11391] bpf: use realloc in bpf_patch_insn_data Avoid excessive vzalloc/vfree calls when patching instructions in do_misc_fixups(). bpf_patch_insn_data() uses vzalloc to allocate new memory for env->insn_aux_data for each patch as follows: struct bpf_prog *bpf_patch_insn_data(env, ...) { ... new_data = vzalloc(... O(program size) ...); ... adjust_insn_aux_data(env, new_data, ...); ... } void adjust_insn_aux_data(env, new_data, ...) { ... memcpy(new_data, env->insn_aux_data); vfree(env->insn_aux_data); env->insn_aux_data = new_data; ... } The vzalloc/vfree pair is hot in perf report collected for e.g. pyperf180 test case. It can be replaced with a call to vrealloc in order to reduce the number of actual memory allocations. This is a stop-gap solution, as bpf_patch_insn_data is still hot in the profile. More comprehansive solutions had been discussed before e.g. as in [1]. [1] https://lore.kernel.org/bpf/CAEf4BzY_E8MSL4mD0UPuuiDcbJhh9e2xQo2=5w+ppRWWiYSGvQ@mail.gmail.com/ Suggested-by: Alexei Starovoitov Signed-off-by: Eduard Zingerman Acked-by: Kumar Kartikeya Dwivedi Tested-by: Anton Protopopov Link: https://lore.kernel.org/r/20250807010205.3210608-3-eddyz87@gmail.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 69eb2b5c2218..a61d57996692 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -20699,12 +20699,11 @@ static void convert_pseudo_ld_imm64(struct bpf_verifier_env *env) * [0, off) and [off, end) to new locations, so the patched range stays zero */ static void adjust_insn_aux_data(struct bpf_verifier_env *env, - struct bpf_insn_aux_data *new_data, struct bpf_prog *new_prog, u32 off, u32 cnt) { - struct bpf_insn_aux_data *old_data = env->insn_aux_data; + struct bpf_insn_aux_data *data = env->insn_aux_data; struct bpf_insn *insn = new_prog->insnsi; - u32 old_seen = old_data[off].seen; + u32 old_seen = data[off].seen; u32 prog_len; int i; @@ -20712,22 +20711,20 @@ static void adjust_insn_aux_data(struct bpf_verifier_env *env, * (cnt == 1) is taken or not. There is no guarantee INSN at OFF is the * original insn at old prog. */ - old_data[off].zext_dst = insn_has_def32(insn + off + cnt - 1); + data[off].zext_dst = insn_has_def32(insn + off + cnt - 1); if (cnt == 1) return; prog_len = new_prog->len; - memcpy(new_data, old_data, sizeof(struct bpf_insn_aux_data) * off); - memcpy(new_data + off + cnt - 1, old_data + off, - sizeof(struct bpf_insn_aux_data) * (prog_len - off - cnt + 1)); + memmove(data + off + cnt - 1, data + off, + sizeof(struct bpf_insn_aux_data) * (prog_len - off - cnt + 1)); + memset(data + off, 0, sizeof(struct bpf_insn_aux_data) * (cnt - 1)); for (i = off; i < off + cnt - 1; i++) { /* Expand insni[off]'s seen count to the patched range. */ - new_data[i].seen = old_seen; - new_data[i].zext_dst = insn_has_def32(insn + i); + data[i].seen = old_seen; + data[i].zext_dst = insn_has_def32(insn + i); } - env->insn_aux_data = new_data; - vfree(old_data); } static void adjust_subprog_starts(struct bpf_verifier_env *env, u32 off, u32 len) @@ -20765,10 +20762,14 @@ static struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 of struct bpf_insn_aux_data *new_data = NULL; if (len > 1) { - new_data = vzalloc(array_size(env->prog->len + len - 1, - sizeof(struct bpf_insn_aux_data))); + new_data = vrealloc(env->insn_aux_data, + array_size(env->prog->len + len - 1, + sizeof(struct bpf_insn_aux_data)), + GFP_KERNEL_ACCOUNT | __GFP_ZERO); if (!new_data) return NULL; + + env->insn_aux_data = new_data; } new_prog = bpf_patch_insn_single(env->prog, off, patch, len); @@ -20780,7 +20781,7 @@ static struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 of vfree(new_data); return NULL; } - adjust_insn_aux_data(env, new_data, new_prog, off, len); + adjust_insn_aux_data(env, new_prog, off, len); adjust_subprog_starts(env, off, len); adjust_poke_descs(new_prog, off, len); return new_prog; From fa479132845e94b60068fad01c2a9979b3efe2dc Mon Sep 17 00:00:00 2001 From: Li Jun Date: Wed, 30 Jul 2025 18:50:19 +0800 Subject: [PATCH 00020/11391] bpf: Standardize function declaration style 'noinlne' after 'int' cause "ERROR: inline keyword should sit between storage class and type" by checkpatch.pl - Standardize function declaration style by moving 'noinline' modifier - Fix asm volatile statement formatting Signed-off-by: Li Jun Link: https://lore.kernel.org/r/20250730105019.436235-1-lijun01@kylinos.cn Signed-off-by: Alexei Starovoitov --- net/bpf/test_run.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c index 9728dbd4c66c..4a862d605386 100644 --- a/net/bpf/test_run.c +++ b/net/bpf/test_run.c @@ -524,27 +524,27 @@ __bpf_kfunc int bpf_fentry_test1(int a) } EXPORT_SYMBOL_GPL(bpf_fentry_test1); -int noinline bpf_fentry_test2(int a, u64 b) +noinline int bpf_fentry_test2(int a, u64 b) { return a + b; } -int noinline bpf_fentry_test3(char a, int b, u64 c) +noinline int bpf_fentry_test3(char a, int b, u64 c) { return a + b + c; } -int noinline bpf_fentry_test4(void *a, char b, int c, u64 d) +noinline int bpf_fentry_test4(void *a, char b, int c, u64 d) { return (long)a + b + c + d; } -int noinline bpf_fentry_test5(u64 a, void *b, short c, int d, u64 e) +noinline int bpf_fentry_test5(u64 a, void *b, short c, int d, u64 e) { return a + (long)b + c + d + e; } -int noinline bpf_fentry_test6(u64 a, void *b, short c, int d, void *e, u64 f) +noinline int bpf_fentry_test6(u64 a, void *b, short c, int d, void *e, u64 f) { return a + (long)b + c + d + (long)e + f; } @@ -553,13 +553,13 @@ struct bpf_fentry_test_t { struct bpf_fentry_test_t *a; }; -int noinline bpf_fentry_test7(struct bpf_fentry_test_t *arg) +noinline int bpf_fentry_test7(struct bpf_fentry_test_t *arg) { - asm volatile ("": "+r"(arg)); + asm volatile ("" : "+r"(arg)); return (long)arg; } -int noinline bpf_fentry_test8(struct bpf_fentry_test_t *arg) +noinline int bpf_fentry_test8(struct bpf_fentry_test_t *arg) { return (long)arg->a; } @@ -569,12 +569,12 @@ __bpf_kfunc u32 bpf_fentry_test9(u32 *a) return *a; } -int noinline bpf_fentry_test10(const void *a) +noinline int bpf_fentry_test10(const void *a) { return (long)a; } -void noinline bpf_fentry_test_sinfo(struct skb_shared_info *sinfo) +noinline void bpf_fentry_test_sinfo(struct skb_shared_info *sinfo) { } @@ -598,7 +598,7 @@ __bpf_kfunc int bpf_modify_return_test_tp(int nonce) return nonce; } -int noinline bpf_fentry_shadow_test(int a) +noinline int bpf_fentry_shadow_test(int a) { return a + 1; } From 68e01988b2088ff5b8152cc7a8576e2b7930621a Mon Sep 17 00:00:00 2001 From: Nick Chan Date: Tue, 10 Jun 2025 21:45:21 +0800 Subject: [PATCH 00021/11391] arm64: dts: apple: s5l8960x: Add I2C nodes Add I2C nodes for Apple A7 SoC. Signed-off-by: Nick Chan Link: https://lore.kernel.org/r/20250610-i2c-no-t2-v2-2-a5a71080fba9@gmail.com Signed-off-by: Sven Peter --- arch/arm64/boot/dts/apple/s5l8960x.dtsi | 76 +++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/arch/arm64/boot/dts/apple/s5l8960x.dtsi b/arch/arm64/boot/dts/apple/s5l8960x.dtsi index 5b5175d6978c..462ffdd348fc 100644 --- a/arch/arm64/boot/dts/apple/s5l8960x.dtsi +++ b/arch/arm64/boot/dts/apple/s5l8960x.dtsi @@ -89,6 +89,62 @@ serial0: serial@20a0a0000 { status = "disabled"; }; + i2c0: i2c@20a110000 { + compatible = "apple,s5l8960x-i2c", "apple,i2c"; + reg = <0x2 0x0a110000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c0_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c1: i2c@20a111000 { + compatible = "apple,s5l8960x-i2c", "apple,i2c"; + reg = <0x2 0x0a111000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c1_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c2: i2c@20a112000 { + compatible = "apple,s5l8960x-i2c", "apple,i2c"; + reg = <0x2 0x0a112000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c2_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c2>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c3: i2c@20a113000 { + compatible = "apple,s5l8960x-i2c", "apple,i2c"; + reg = <0x2 0x0a113000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c3_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c3>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + pmgr: power-management@20e000000 { compatible = "apple,s5l8960x-pmgr", "apple,pmgr", "syscon", "simple-mfd"; #address-cells = <1>; @@ -140,6 +196,26 @@ pinctrl: pinctrl@20e300000 { , , ; + + i2c0_pins: i2c0-pins { + pinmux = , + ; + }; + + i2c1_pins: i2c1-pins { + pinmux = , + ; + }; + + i2c2_pins: i2c2-pins { + pinmux = , + ; + }; + + i2c3_pins: i2c3-pins { + pinmux = , + ; + }; }; }; From 5b1ab37ccc605f20e5309f7ba45eea2aec6054d1 Mon Sep 17 00:00:00 2001 From: Nick Chan Date: Tue, 10 Jun 2025 21:45:22 +0800 Subject: [PATCH 00022/11391] arm64: dts: apple: t7000: Add I2C nodes Add I2C nodes for Apple A8 SoC. Signed-off-by: Nick Chan Link: https://lore.kernel.org/r/20250610-i2c-no-t2-v2-3-a5a71080fba9@gmail.com Signed-off-by: Sven Peter --- arch/arm64/boot/dts/apple/t7000.dtsi | 76 ++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t7000.dtsi b/arch/arm64/boot/dts/apple/t7000.dtsi index 52edc8d776a9..0342455d3444 100644 --- a/arch/arm64/boot/dts/apple/t7000.dtsi +++ b/arch/arm64/boot/dts/apple/t7000.dtsi @@ -144,6 +144,62 @@ serial6: serial@20a0d8000 { status = "disabled"; }; + i2c0: i2c@20a110000 { + compatible = "apple,t7000-i2c", "apple,i2c"; + reg = <0x2 0x0a110000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c0_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c1: i2c@20a111000 { + compatible = "apple,t7000-i2c", "apple,i2c"; + reg = <0x2 0x0a111000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c1_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c2: i2c@20a112000 { + compatible = "apple,t7000-i2c", "apple,i2c"; + reg = <0x2 0x0a112000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c2_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c2>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c3: i2c@20a113000 { + compatible = "apple,t7000-i2c", "apple,i2c"; + reg = <0x2 0x0a113000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c3_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c3>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + pmgr: power-management@20e000000 { compatible = "apple,t7000-pmgr", "apple,pmgr", "syscon", "simple-mfd"; #address-cells = <1>; @@ -195,6 +251,26 @@ pinctrl: pinctrl@20e300000 { , , ; + + i2c0_pins: i2c0-pins { + pinmux = , + ; + }; + + i2c1_pins: i2c1-pins { + pinmux = , + ; + }; + + i2c2_pins: i2c2-pins { + pinmux = , + ; + }; + + i2c3_pins: i2c3-pins { + pinmux = , + ; + }; }; }; From a56771d333edb1d1d5631e296fb2b021a39b3940 Mon Sep 17 00:00:00 2001 From: Nick Chan Date: Tue, 10 Jun 2025 21:45:23 +0800 Subject: [PATCH 00023/11391] arm64: dts: apple: t7001: Add I2C nodes Add I2C nodes for Apple A8X SoC. Signed-off-by: Nick Chan Link: https://lore.kernel.org/r/20250610-i2c-no-t2-v2-4-a5a71080fba9@gmail.com Signed-off-by: Sven Peter --- arch/arm64/boot/dts/apple/t7001.dtsi | 76 ++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t7001.dtsi b/arch/arm64/boot/dts/apple/t7001.dtsi index a2efa81305df..e1afb0542369 100644 --- a/arch/arm64/boot/dts/apple/t7001.dtsi +++ b/arch/arm64/boot/dts/apple/t7001.dtsi @@ -144,6 +144,62 @@ serial0: serial@20a0c0000 { status = "disabled"; }; + i2c0: i2c@20a110000 { + compatible = "apple,t7000-i2c", "apple,i2c"; + reg = <0x2 0x0a110000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c0_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c1: i2c@20a111000 { + compatible = "apple,t7000-i2c", "apple,i2c"; + reg = <0x2 0x0a111000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c1_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c2: i2c@20a112000 { + compatible = "apple,t7000-i2c", "apple,i2c"; + reg = <0x2 0x0a112000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c2_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c2>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c3: i2c@20a113000 { + compatible = "apple,t7000-i2c", "apple,i2c"; + reg = <0x2 0x0a113000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c3_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c3>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + pmgr: power-management@20e000000 { compatible = "apple,t7000-pmgr", "apple,pmgr", "syscon", "simple-mfd"; #address-cells = <1>; @@ -188,6 +244,26 @@ pinctrl: pinctrl@20e300000 { , , ; + + i2c0_pins: i2c0-pins { + pinmux = , + ; + }; + + i2c1_pins: i2c1-pins { + pinmux = , + ; + }; + + i2c2_pins: i2c2-pins { + pinmux = , + ; + }; + + i2c3_pins: i2c3-pins { + pinmux = , + ; + }; }; }; From 5bee6cb9d9df55125eddd63345054ff08a0d44e9 Mon Sep 17 00:00:00 2001 From: Nick Chan Date: Tue, 10 Jun 2025 21:45:24 +0800 Subject: [PATCH 00024/11391] arm64: dts: apple: s800-0-3: Add I2C nodes Add I2C nodes for Apple A9 SoC. There is actually an i2c3 on this SoC but the SCL and SDA lines appears to be not connected and no peripherals are expected to be connected to it, so there is no node for it. Signed-off-by: Nick Chan Link: https://lore.kernel.org/r/20250610-i2c-no-t2-v2-5-a5a71080fba9@gmail.com Signed-off-by: Sven Peter --- arch/arm64/boot/dts/apple/s800-0-3.dtsi | 57 +++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/arch/arm64/boot/dts/apple/s800-0-3.dtsi b/arch/arm64/boot/dts/apple/s800-0-3.dtsi index 09db4ed64054..bb38662b7d2e 100644 --- a/arch/arm64/boot/dts/apple/s800-0-3.dtsi +++ b/arch/arm64/boot/dts/apple/s800-0-3.dtsi @@ -88,6 +88,48 @@ serial0: serial@20a0c0000 { status = "disabled"; }; + i2c0: i2c@20a110000 { + compatible = "apple,s8000-i2c", "apple,i2c"; + reg = <0x2 0x0a110000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c0_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c1: i2c@20a111000 { + compatible = "apple,s8000-i2c", "apple,i2c"; + reg = <0x2 0x0a111000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c1_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c2: i2c@20a112000 { + compatible = "apple,s8000-i2c", "apple,i2c"; + reg = <0x2 0x0a112000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c2_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c2>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + pmgr: power-management@20e000000 { compatible = "apple,s8000-pmgr", "apple,pmgr", "syscon", "simple-mfd"; #address-cells = <1>; @@ -131,6 +173,21 @@ pinctrl_ap: pinctrl@20f100000 { , , ; + + i2c0_pins: i2c0-pins { + pinmux = , + ; + }; + + i2c1_pins: i2c1-pins { + pinmux = , + ; + }; + + i2c2_pins: i2c2-pins { + pinmux = , + ; + }; }; pinctrl_aop: pinctrl@2100f0000 { From baf703b08374b10cd4d3dbbf7410569fee2e8cb1 Mon Sep 17 00:00:00 2001 From: Nick Chan Date: Tue, 10 Jun 2025 21:45:25 +0800 Subject: [PATCH 00025/11391] arm64: dts: apple: s8001: Add I2C nodes Add I2C nodes for Apple A9 SoC. Signed-off-by: Nick Chan Link: https://lore.kernel.org/r/20250610-i2c-no-t2-v2-6-a5a71080fba9@gmail.com Signed-off-by: Sven Peter --- arch/arm64/boot/dts/apple/s8001.dtsi | 76 ++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/arch/arm64/boot/dts/apple/s8001.dtsi b/arch/arm64/boot/dts/apple/s8001.dtsi index fee350765894..b5b00dca6ffa 100644 --- a/arch/arm64/boot/dts/apple/s8001.dtsi +++ b/arch/arm64/boot/dts/apple/s8001.dtsi @@ -137,6 +137,62 @@ serial0: serial@20a0c0000 { status = "disabled"; }; + i2c0: i2c@20a110000 { + compatible = "apple,s8000-i2c", "apple,i2c"; + reg = <0x2 0x0a110000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c0_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c1: i2c@20a111000 { + compatible = "apple,s8000-i2c", "apple,i2c"; + reg = <0x2 0x0a111000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c1_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c2: i2c@20a112000 { + compatible = "apple,s8000-i2c", "apple,i2c"; + reg = <0x2 0x0a112000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c2_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c2>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c3: i2c@20a113000 { + compatible = "apple,s8000-i2c", "apple,i2c"; + reg = <0x2 0x0a113000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c3_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c3>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + pmgr: power-management@20e000000 { compatible = "apple,s8000-pmgr", "apple,pmgr", "syscon", "simple-mfd"; #address-cells = <1>; @@ -173,6 +229,26 @@ pinctrl_ap: pinctrl@20f100000 { , , ; + + i2c0_pins: i2c0-pins { + pinmux = , + ; + }; + + i2c1_pins: i2c1-pins { + pinmux = , + ; + }; + + i2c2_pins: i2c2-pins { + pinmux = , + ; + }; + + i2c3_pins: i2c3-pins { + pinmux = , + ; + }; }; pinctrl_aop: pinctrl@2100f0000 { From 9f286293541e20c904ce59ad7ea26f8b6cab126a Mon Sep 17 00:00:00 2001 From: Nick Chan Date: Tue, 10 Jun 2025 21:45:26 +0800 Subject: [PATCH 00026/11391] arm64: dts: apple: t8010: Add I2C nodes Add I2C nodes for Apple A10 SoC. Signed-off-by: Nick Chan Link: https://lore.kernel.org/r/20250610-i2c-no-t2-v2-7-a5a71080fba9@gmail.com Signed-off-by: Sven Peter --- arch/arm64/boot/dts/apple/t8010.dtsi | 76 ++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8010.dtsi b/arch/arm64/boot/dts/apple/t8010.dtsi index b961d4f65bc3..522b3896aa87 100644 --- a/arch/arm64/boot/dts/apple/t8010.dtsi +++ b/arch/arm64/boot/dts/apple/t8010.dtsi @@ -164,6 +164,62 @@ serial0: serial@20a0c0000 { status = "disabled"; }; + i2c0: i2c@20a110000 { + compatible = "apple,t8010-i2c", "apple,i2c"; + reg = <0x2 0x0a110000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c0_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c1: i2c@20a111000 { + compatible = "apple,t8010-i2c", "apple,i2c"; + reg = <0x2 0x0a111000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c1_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c2: i2c@20a112000 { + compatible = "apple,t8010-i2c", "apple,i2c"; + reg = <0x2 0x0a112000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c2_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c2>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c3: i2c@20a113000 { + compatible = "apple,t8010-i2c", "apple,i2c"; + reg = <0x2 0x0a113000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c3_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c3>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + pmgr: power-management@20e000000 { compatible = "apple,t8010-pmgr", "apple,pmgr", "syscon", "simple-mfd"; #address-cells = <1>; @@ -207,6 +263,26 @@ pinctrl_ap: pinctrl@20f100000 { , , ; + + i2c0_pins: i2c0-pins { + pinmux = , + ; + }; + + i2c1_pins: i2c1-pins { + pinmux = , + ; + }; + + i2c2_pins: i2c2-pins { + pinmux = , + ; + }; + + i2c3_pins: i2c3-pins { + pinmux = , + ; + }; }; pinctrl_aop: pinctrl@2100f0000 { From 1d16ae50cb1bdcfe15319d946e3418dcbdcd8509 Mon Sep 17 00:00:00 2001 From: Nick Chan Date: Tue, 10 Jun 2025 21:45:27 +0800 Subject: [PATCH 00027/11391] arm64: dts: apple: t8011: Add I2C nodes Add I2C nodes for Apple A10X SoC. Signed-off-by: Nick Chan Link: https://lore.kernel.org/r/20250610-i2c-no-t2-v2-8-a5a71080fba9@gmail.com Signed-off-by: Sven Peter --- arch/arm64/boot/dts/apple/t8011.dtsi | 76 ++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8011.dtsi b/arch/arm64/boot/dts/apple/t8011.dtsi index 974f78cc77cf..039aa4d1e887 100644 --- a/arch/arm64/boot/dts/apple/t8011.dtsi +++ b/arch/arm64/boot/dts/apple/t8011.dtsi @@ -168,6 +168,62 @@ serial0: serial@20a0c0000 { status = "disabled"; }; + i2c0: i2c@20a110000 { + compatible = "apple,t8010-i2c", "apple,i2c"; + reg = <0x2 0x0a110000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c0_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c1: i2c@20a111000 { + compatible = "apple,t8010-i2c", "apple,i2c"; + reg = <0x2 0x0a111000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c1_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c2: i2c@20a112000 { + compatible = "apple,t8010-i2c", "apple,i2c"; + reg = <0x2 0x0a112000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c2_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c2>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c3: i2c@20a113000 { + compatible = "apple,t8010-i2c", "apple,i2c"; + reg = <0x2 0x0a113000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c3_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c3>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + pmgr: power-management@20e000000 { compatible = "apple,t8010-pmgr", "apple,pmgr", "syscon", "simple-mfd"; #address-cells = <1>; @@ -204,6 +260,26 @@ pinctrl_ap: pinctrl@20f100000 { , , ; + + i2c0_pins: i2c0-pins { + pinmux = , + ; + }; + + i2c1_pins: i2c1-pins { + pinmux = , + ; + }; + + i2c2_pins: i2c2-pins { + pinmux = , + ; + }; + + i2c3_pins: i2c3-pins { + pinmux = , + ; + }; }; pinctrl_aop: pinctrl@2100f0000 { From e1313c2185d22c2f8db508db61d3e2c0e62193d7 Mon Sep 17 00:00:00 2001 From: Nick Chan Date: Tue, 10 Jun 2025 21:45:28 +0800 Subject: [PATCH 00028/11391] arm64: dts: apple: t8015: Add I2C nodes Add I2C nodes for Apple A11 SoC. Signed-off-by: Nick Chan Link: https://lore.kernel.org/r/20250610-i2c-no-t2-v2-9-a5a71080fba9@gmail.com Signed-off-by: Sven Peter --- arch/arm64/boot/dts/apple/t8015.dtsi | 76 ++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8015.dtsi b/arch/arm64/boot/dts/apple/t8015.dtsi index 12acf8fc8bc6..e002ecee3390 100644 --- a/arch/arm64/boot/dts/apple/t8015.dtsi +++ b/arch/arm64/boot/dts/apple/t8015.dtsi @@ -265,6 +265,62 @@ cpufreq_p: performance-controller@208ea0000 { #performance-domain-cells = <0>; }; + i2c0: i2c@22e200000 { + compatible = "apple,t8015-i2c", "apple,i2c"; + reg = <0x2 0x2e200000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c0_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c1: i2c@22e204000 { + compatible = "apple,t8015-i2c", "apple,i2c"; + reg = <0x2 0x2e204000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c1_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c2: i2c@22e208000 { + compatible = "apple,t8015-i2c", "apple,i2c"; + reg = <0x2 0x2e208000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c2_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c2>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c3: i2c@22e20c000 { + compatible = "apple,t8015-i2c", "apple,i2c"; + reg = <0x2 0x2e20c000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c3_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c3>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + serial0: serial@22e600000 { compatible = "apple,s5l-uart"; reg = <0x2 0x2e600000 0x0 0x4000>; @@ -321,6 +377,26 @@ pinctrl_ap: pinctrl@233100000 { , , ; + + i2c0_pins: i2c0-pins { + pinmux = , + ; + }; + + i2c1_pins: i2c1-pins { + pinmux = , + ; + }; + + i2c2_pins: i2c2-pins { + pinmux = , + ; + }; + + i2c3_pins: i2c3-pins { + pinmux = , + ; + }; }; pinctrl_aop: pinctrl@2340f0000 { From 6101fe95b1ee551b7f5d03a9edd80edc7d446be9 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Tue, 10 Jun 2025 15:29:49 +0000 Subject: [PATCH 00029/11391] arm64: dts: apple: t8103: Add SMC node Signed-off-by: Hector Martin Reviewed-by: Linus Walleij Reviewed-by: Sven Peter Signed-off-by: Russell King (Oracle) Reviewed-by: Alyssa Rosenzweig Reviewed-by: Neal Gompa Link: https://lore.kernel.org/r/20250610-smc-6-15-v7-8-556cafd771d3@kernel.org Signed-off-by: Sven Peter --- arch/arm64/boot/dts/apple/t8103.dtsi | 35 ++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi index 589ddc039799..8b7b27887968 100644 --- a/arch/arm64/boot/dts/apple/t8103.dtsi +++ b/arch/arm64/boot/dts/apple/t8103.dtsi @@ -896,6 +896,41 @@ wdt: watchdog@23d2b0000 { interrupts = ; }; + smc: smc@23e400000 { + compatible = "apple,t8103-smc", "apple,smc"; + reg = <0x2 0x3e400000 0x0 0x4000>, + <0x2 0x3fe00000 0x0 0x100000>; + reg-names = "smc", "sram"; + mboxes = <&smc_mbox>; + + smc_gpio: gpio { + compatible = "apple,smc-gpio"; + gpio-controller; + #gpio-cells = <2>; + }; + + smc_reboot: reboot { + compatible = "apple,smc-reboot"; + nvmem-cells = <&shutdown_flag>, <&boot_stage>, + <&boot_error_count>, <&panic_count>; + nvmem-cell-names = "shutdown_flag", "boot_stage", + "boot_error_count", "panic_count"; + }; + }; + + smc_mbox: mbox@23e408000 { + compatible = "apple,t8103-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0x3e408000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + }; + pinctrl_smc: pinctrl@23e820000 { compatible = "apple,t8103-pinctrl", "apple,pinctrl"; reg = <0x2 0x3e820000 0x0 0x4000>; From 49765a617a54837910b26978bb0dc01908a673e2 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Tue, 10 Jun 2025 15:29:50 +0000 Subject: [PATCH 00030/11391] arm64: dts: apple: t8112: Add SMC node Signed-off-by: Hector Martin Reviewed-by: Alyssa Rosenzweig Reviewed-by: Neal Gompa Link: https://lore.kernel.org/r/20250610-smc-6-15-v7-9-556cafd771d3@kernel.org Signed-off-by: Sven Peter --- arch/arm64/boot/dts/apple/t8112.dtsi | 35 ++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi index b36b345861b6..3f79878b25af 100644 --- a/arch/arm64/boot/dts/apple/t8112.dtsi +++ b/arch/arm64/boot/dts/apple/t8112.dtsi @@ -899,6 +899,41 @@ rtc_offset: rtc-offset@f900 { }; }; + smc: smc@23e400000 { + compatible = "apple,t8112-smc", "apple,smc"; + reg = <0x2 0x3e400000 0x0 0x4000>, + <0x2 0x3fe00000 0x0 0x100000>; + reg-names = "smc", "sram"; + mboxes = <&smc_mbox>; + + smc_gpio: gpio { + compatible = "apple,smc-gpio"; + gpio-controller; + #gpio-cells = <2>; + }; + + smc_reboot: reboot { + compatible = "apple,smc-reboot"; + nvmem-cells = <&shutdown_flag>, <&boot_stage>, + <&boot_error_count>, <&panic_count>; + nvmem-cell-names = "shutdown_flag", "boot_stage", + "boot_error_count", "panic_count"; + }; + }; + + smc_mbox: mbox@23e408000 { + compatible = "apple,t8112-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0x3e408000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + }; + pinctrl_smc: pinctrl@23e820000 { compatible = "apple,t8112-pinctrl", "apple,pinctrl"; reg = <0x2 0x3e820000 0x0 0x4000>; From 4379305ffbc2eebe3de673fc965145d441c89b8f Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Tue, 10 Jun 2025 15:29:51 +0000 Subject: [PATCH 00031/11391] arm64: dts: apple: t600x: Add SMC node Signed-off-by: Hector Martin Reviewed-by: Alyssa Rosenzweig Reviewed-by: Neal Gompa Link: https://lore.kernel.org/r/20250610-smc-6-15-v7-10-556cafd771d3@kernel.org Signed-off-by: Sven Peter --- arch/arm64/boot/dts/apple/t600x-die0.dtsi | 35 +++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi index 1563b3ce1ff6..3603b276a2ab 100644 --- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi @@ -24,6 +24,41 @@ aic: interrupt-controller@28e100000 { power-domains = <&ps_aic>; }; + smc: smc@290400000 { + compatible = "apple,t6000-smc", "apple,smc"; + reg = <0x2 0x90400000 0x0 0x4000>, + <0x2 0x91e00000 0x0 0x100000>; + reg-names = "smc", "sram"; + mboxes = <&smc_mbox>; + + smc_gpio: gpio { + compatible = "apple,smc-gpio"; + gpio-controller; + #gpio-cells = <2>; + }; + + smc_reboot: reboot { + compatible = "apple,smc-reboot"; + nvmem-cells = <&shutdown_flag>, <&boot_stage>, + <&boot_error_count>, <&panic_count>; + nvmem-cell-names = "shutdown_flag", "boot_stage", + "boot_error_count", "panic_count"; + }; + }; + + smc_mbox: mbox@290408000 { + compatible = "apple,t6000-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0x90408000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + }; + pinctrl_smc: pinctrl@290820000 { compatible = "apple,t6000-pinctrl", "apple,pinctrl"; reg = <0x2 0x90820000 0x0 0x4000>; From ec437f9ba3335ffa14b3d0774d267059636d4778 Mon Sep 17 00:00:00 2001 From: Sven Peter Date: Thu, 12 Jun 2025 21:11:26 +0000 Subject: [PATCH 00032/11391] soc: apple: Drop default ARCH_APPLE in Kconfig When the first driver for Apple Silicon was upstreamed we accidentally included `default ARCH_APPLE` in its Kconfig which then spread to almost every subsequent driver. As soon as ARCH_APPLE is set to y this will pull in many drivers as built-ins which is not what we want. Thus, drop `default ARCH_APPLE` from Kconfig. Reviewed-by: Janne Grunau Link: https://lore.kernel.org/r/20250612-apple-kconfig-defconfig-v1-2-0e6f9cb512c1@kernel.org Signed-off-by: Sven Peter --- drivers/soc/apple/Kconfig | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/soc/apple/Kconfig b/drivers/soc/apple/Kconfig index 6388cbe1e56b..ad6736889231 100644 --- a/drivers/soc/apple/Kconfig +++ b/drivers/soc/apple/Kconfig @@ -8,7 +8,6 @@ config APPLE_MAILBOX tristate "Apple SoC mailboxes" depends on PM depends on ARCH_APPLE || (64BIT && COMPILE_TEST) - default ARCH_APPLE help Apple SoCs have various co-processors required for certain peripherals to work (NVMe, display controller, etc.). This @@ -21,7 +20,6 @@ config APPLE_RTKIT tristate "Apple RTKit co-processor IPC protocol" depends on APPLE_MAILBOX depends on ARCH_APPLE || COMPILE_TEST - default ARCH_APPLE help Apple SoCs such as the M1 come with various co-processors running their proprietary RTKit operating system. This option enables support @@ -33,7 +31,6 @@ config APPLE_RTKIT config APPLE_SART tristate "Apple SART DMA address filter" depends on ARCH_APPLE || COMPILE_TEST - default ARCH_APPLE help Apple SART is a simple DMA address filter used on Apple SoCs such as the M1. It is usually required for the NVMe coprocessor which does From 8bcfcb3bd3e38b8f3bb7e5eb3acb4120500994a0 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 29 Jul 2025 15:06:32 +0200 Subject: [PATCH 00033/11391] ASoC: Intel: avs: Parse conditional path tuples MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Conditional paths need information about their source and sink paths to be created which is then stored to keep track of who their parents are. That information allows to change their state accordingly to what is currently happening to their parent paths. Signed-off-by: Amadeusz Sławiński Signed-off-by: Cezary Rojewski Link: https://patch.msgid.link/20250729130633.310388-2-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- include/uapi/sound/intel/avs/tokens.h | 15 ++++ sound/soc/intel/avs/topology.c | 110 ++++++++++++++++++++++++++ sound/soc/intel/avs/topology.h | 8 ++ 3 files changed, 133 insertions(+) diff --git a/include/uapi/sound/intel/avs/tokens.h b/include/uapi/sound/intel/avs/tokens.h index c9f845b3c523..f3ff6aae09a9 100644 --- a/include/uapi/sound/intel/avs/tokens.h +++ b/include/uapi/sound/intel/avs/tokens.h @@ -133,6 +133,21 @@ enum avs_tplg_token { AVS_TKN_PATH_FE_FMT_ID_U32 = 1902, AVS_TKN_PATH_BE_FMT_ID_U32 = 1903, + /* struct avs_tplg_path_template (conditional) */ + AVS_TKN_CONDPATH_TMPL_ID_U32 = 1801, + AVS_TKN_CONDPATH_TMPL_SOURCE_TPLG_NAME_STRING = 2002, + AVS_TKN_CONDPATH_TMPL_SOURCE_PATH_TMPL_ID_U32 = 2003, + AVS_TKN_CONDPATH_TMPL_SINK_TPLG_NAME_STRING = 2004, + AVS_TKN_CONDPATH_TMPL_SINK_PATH_TMPL_ID_U32 = 2005, + AVS_TKN_CONDPATH_TMPL_COND_TYPE_U32 = 2006, + AVS_TKN_CONDPATH_TMPL_OVERRIDABLE_BOOL = 2007, + AVS_TKN_CONDPATH_TMPL_PRIORITY_U8 = 2008, + + /* struct avs_tplg_path (conditional) */ + AVS_TKN_CONDPATH_ID_U32 = 1901, + AVS_TKN_CONDPATH_SOURCE_PATH_ID_U32 = 2102, + AVS_TKN_CONDPATH_SINK_PATH_ID_U32 = 2103, + /* struct avs_tplg_pin_format */ AVS_TKN_PIN_FMT_INDEX_U32 = 2201, AVS_TKN_PIN_FMT_IOBS_U32 = 2202, diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c index f2e4ad8b8e14..dfe8cf505381 100644 --- a/sound/soc/intel/avs/topology.c +++ b/sound/soc/intel/avs/topology.c @@ -1387,6 +1387,27 @@ static const struct avs_tplg_token_parser path_parsers[] = { }, }; +static const struct avs_tplg_token_parser condpath_parsers[] = { + { + .token = AVS_TKN_CONDPATH_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_path, id), + .parse = avs_parse_word_token, + }, + { + .token = AVS_TKN_CONDPATH_SOURCE_PATH_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_path, source_path_id), + .parse = avs_parse_word_token, + }, + { + .token = AVS_TKN_CONDPATH_SINK_PATH_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_path, sink_path_id), + .parse = avs_parse_word_token, + }, +}; + static struct avs_tplg_path * avs_tplg_path_create(struct snd_soc_component *comp, struct avs_tplg_path_template *owner, struct snd_soc_tplg_vendor_array *tuples, u32 block_size, @@ -1454,6 +1475,39 @@ static const struct avs_tplg_token_parser path_tmpl_parsers[] = { }, }; +static const struct avs_tplg_token_parser condpath_tmpl_parsers[] = { + { + .token = AVS_TKN_CONDPATH_TMPL_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_path_template, id), + .parse = avs_parse_word_token, + }, + { + .token = AVS_TKN_CONDPATH_TMPL_SOURCE_TPLG_NAME_STRING, + .type = SND_SOC_TPLG_TUPLE_TYPE_STRING, + .offset = offsetof(struct avs_tplg_path_template, source.tplg_name), + .parse = avs_parse_string_token, + }, + { + .token = AVS_TKN_CONDPATH_TMPL_SOURCE_PATH_TMPL_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_path_template, source.id), + .parse = avs_parse_word_token, + }, + { + .token = AVS_TKN_CONDPATH_TMPL_SINK_TPLG_NAME_STRING, + .type = SND_SOC_TPLG_TUPLE_TYPE_STRING, + .offset = offsetof(struct avs_tplg_path_template, sink.tplg_name), + .parse = avs_parse_string_token, + }, + { + .token = AVS_TKN_CONDPATH_TMPL_SINK_PATH_TMPL_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_path_template, sink.id), + .parse = avs_parse_word_token, + }, +}; + static int parse_path_template(struct snd_soc_component *comp, struct snd_soc_tplg_vendor_array *tuples, u32 block_size, struct avs_tplg_path_template *template, @@ -1524,6 +1578,56 @@ avs_tplg_path_template_create(struct snd_soc_component *comp, struct avs_tplg *o return template; } +static int avs_tplg_parse_condpath_templates(struct snd_soc_component *comp, + struct snd_soc_tplg_vendor_array *tuples, + u32 block_size) +{ + struct avs_soc_component *acomp = to_avs_soc_component(comp); + struct avs_tplg *tplg = acomp->tplg; + int ret, i; + + ret = parse_dictionary_header(comp, tuples, (void **)&tplg->condpath_tmpls, + &tplg->num_condpath_tmpls, + sizeof(*tplg->condpath_tmpls), + AVS_TKN_MANIFEST_NUM_CONDPATH_TMPLS_U32); + if (ret) + return ret; + + block_size -= le32_to_cpu(tuples->size); + /* With header parsed, move on to parsing entries. */ + tuples = avs_tplg_vendor_array_next(tuples); + + for (i = 0; i < tplg->num_condpath_tmpls; i++) { + struct avs_tplg_path_template *template; + u32 esize; + + template = &tplg->condpath_tmpls[i]; + template->owner = tplg; /* Used when building sysfs hierarchy. */ + INIT_LIST_HEAD(&template->path_list); + INIT_LIST_HEAD(&template->node); + + ret = avs_tplg_vendor_entry_size(tuples, block_size, + AVS_TKN_CONDPATH_TMPL_ID_U32, &esize); + if (ret) + return ret; + + ret = parse_path_template(comp, tuples, esize, template, + condpath_tmpl_parsers, + ARRAY_SIZE(condpath_tmpl_parsers), + condpath_parsers, + ARRAY_SIZE(condpath_parsers)); + if (ret < 0) { + dev_err(comp->dev, "parse condpath_tmpl: %d failed: %d\n", i, ret); + return ret; + } + + block_size -= esize; + tuples = avs_tplg_vendor_array_at(tuples, esize); + } + + return 0; +} + static const struct avs_tplg_token_parser mod_init_config_parsers[] = { { .token = AVS_TKN_INIT_CONFIG_ID_U32, @@ -1891,6 +1995,12 @@ static int avs_manifest(struct snd_soc_component *comp, int index, return ret; } + /* Condpaths dictionary. */ + ret = avs_tplg_parse_condpath_templates(comp, tuples, + has_init_config ? offset : remaining); + if (ret < 0) + return ret; + if (!has_init_config) return 0; diff --git a/sound/soc/intel/avs/topology.h b/sound/soc/intel/avs/topology.h index f5601a4e3ec8..1e83fccf2ea2 100644 --- a/sound/soc/intel/avs/topology.h +++ b/sound/soc/intel/avs/topology.h @@ -33,6 +33,7 @@ struct avs_tplg { u32 num_pplcfgs; struct avs_tplg_binding *bindings; u32 num_bindings; + struct avs_tplg_path_template *condpath_tmpls; u32 num_condpath_tmpls; struct avs_tplg_init_config *init_configs; u32 num_init_configs; @@ -155,6 +156,10 @@ struct avs_tplg_path_template { struct snd_soc_dapm_widget *w; + /* Conditional path. */ + struct avs_tplg_path_template_id source; + struct avs_tplg_path_template_id sink; + struct list_head path_list; struct avs_tplg *owner; @@ -176,6 +181,9 @@ struct avs_tplg_path { /* Path format requirements. */ struct avs_audio_format *fe_fmt; struct avs_audio_format *be_fmt; + /* Condpath path-variant requirements. */ + u32 source_path_id; + u32 sink_path_id; struct list_head ppl_list; From 595b7f155b926460a00776cc581e4dcd01220006 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 29 Jul 2025 15:06:33 +0200 Subject: [PATCH 00034/11391] ASoC: Intel: avs: Conditional-path support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Compared to standard paths, conditional paths are not invoked by the means of FE being opened by userspace and thus their variant selection is not FE/BE audio format based. These are a side effect of standard path creation if specific criteria are met. Algorithm is implemented to walk on all existing runtime paths and match them against conditions provided by topology. These conditions are based on source and sink path formats, rather than formats provided from userspace app or present on the codec. If match is found, new path is created and tied to those which brought it into existence: source and sink path. If any of its parents perishes, so does the conditional path. Conditional paths are used to enable any complex, modern audio scenario which involves usage of KPB, AEC and WoV modules and more. Signed-off-by: Amadeusz Sławiński Signed-off-by: Cezary Rojewski Link: https://patch.msgid.link/20250729130633.310388-3-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/path.c | 267 +++++++++++++++++++++++++++++++++++++ sound/soc/intel/avs/path.h | 13 ++ 2 files changed, 280 insertions(+) diff --git a/sound/soc/intel/avs/path.c b/sound/soc/intel/avs/path.c index e8e6b1c7fc90..7aa20fcf1a33 100644 --- a/sound/soc/intel/avs/path.c +++ b/sound/soc/intel/avs/path.c @@ -115,6 +115,55 @@ avs_path_find_variant(struct avs_dev *adev, return NULL; } +static struct avs_tplg_path *avs_condpath_find_variant(struct avs_dev *adev, + struct avs_tplg_path_template *template, + struct avs_path *source, + struct avs_path *sink) +{ + struct avs_tplg_path *variant; + + list_for_each_entry(variant, &template->path_list, node) { + if (variant->source_path_id == source->template->id && + variant->sink_path_id == sink->template->id) + return variant; + } + + return NULL; +} + +static bool avs_tplg_path_template_id_equal(struct avs_tplg_path_template_id *id, + struct avs_tplg_path_template_id *id2) +{ + return id->id == id2->id && !strcmp(id->tplg_name, id2->tplg_name); +} + +static struct avs_path *avs_condpath_find_match(struct avs_dev *adev, + struct avs_tplg_path_template *template, + struct avs_path *path, int dir) +{ + struct avs_tplg_path_template_id *id, *id2; + + if (dir) { + id = &template->source; + id2 = &template->sink; + } else { + id = &template->sink; + id2 = &template->source; + } + + /* Check whether this path is either source or sink of condpath template. */ + if (id->id != path->template->owner->id || + strcmp(id->tplg_name, path->template->owner->owner->name)) + return NULL; + + /* Unidirectional condpaths are allowed. */ + if (avs_tplg_path_template_id_equal(id, id2)) + return path; + + /* Now find the counterpart. */ + return avs_path_find_path(adev, id2->tplg_name, id2->id); +} + static struct acpi_nhlt_config * avs_nhlt_config_or_default(struct avs_dev *adev, struct avs_tplg_module *t); @@ -1051,6 +1100,10 @@ static int avs_path_init(struct avs_dev *adev, struct avs_path *path, path->dma_id = dma_id; INIT_LIST_HEAD(&path->ppl_list); INIT_LIST_HEAD(&path->node); + INIT_LIST_HEAD(&path->source_list); + INIT_LIST_HEAD(&path->sink_list); + INIT_LIST_HEAD(&path->source_node); + INIT_LIST_HEAD(&path->sink_node); /* create all the pipelines */ list_for_each_entry(tppl, &template->ppl_list, node) { @@ -1134,12 +1187,129 @@ static struct avs_path *avs_path_create_unlocked(struct avs_dev *adev, u32 dma_i return ERR_PTR(ret); } +static void avs_condpath_free(struct avs_dev *adev, struct avs_path *path) +{ + int ret; + + list_del(&path->source_node); + list_del(&path->sink_node); + + ret = avs_path_reset(path); + if (ret < 0) + dev_err(adev->dev, "reset condpath failed: %d\n", ret); + + ret = avs_path_unbind(path); + if (ret < 0) + dev_err(adev->dev, "unbind condpath failed: %d\n", ret); + + avs_path_free_unlocked(path); +} + +static struct avs_path *avs_condpath_create(struct avs_dev *adev, + struct avs_tplg_path *template, + struct avs_path *source, + struct avs_path *sink) +{ + struct avs_path *path; + int ret; + + path = avs_path_create_unlocked(adev, 0, template); + if (IS_ERR(path)) + return path; + + ret = avs_path_bind(path); + if (ret) + goto err_bind; + + ret = avs_path_reset(path); + if (ret) + goto err_reset; + + path->source = source; + path->sink = sink; + list_add_tail(&path->source_node, &source->source_list); + list_add_tail(&path->sink_node, &sink->sink_list); + + return path; + +err_reset: + avs_path_unbind(path); +err_bind: + avs_path_free_unlocked(path); + return ERR_PTR(ret); +} + +static int avs_condpaths_walk(struct avs_dev *adev, struct avs_path *path, int dir) +{ + struct avs_soc_component *acomp; + struct avs_path *source, *sink; + struct avs_path **other; + + if (dir) { + source = path; + other = &sink; + } else { + sink = path; + other = &source; + } + + list_for_each_entry(acomp, &adev->comp_list, node) { + for (int i = 0; i < acomp->tplg->num_condpath_tmpls; i++) { + struct avs_tplg_path_template *template; + struct avs_tplg_path *variant; + struct avs_path *cpath; + + template = &acomp->tplg->condpath_tmpls[i]; + + /* Do not create unidirectional condpaths twice. */ + if (avs_tplg_path_template_id_equal(&template->source, + &template->sink) && dir) + continue; + + *other = avs_condpath_find_match(adev, template, path, dir); + if (!*other) + continue; + + variant = avs_condpath_find_variant(adev, template, source, sink); + if (!variant) + continue; + + cpath = avs_condpath_create(adev, variant, source, sink); + if (IS_ERR(cpath)) + return PTR_ERR(cpath); + } + } + + return 0; +} + +/* Caller responsible for holding adev->path_mutex. */ +static int avs_condpaths_walk_all(struct avs_dev *adev, struct avs_path *path) +{ + int ret; + + ret = avs_condpaths_walk(adev, path, SNDRV_PCM_STREAM_CAPTURE); + if (ret) + return ret; + + return avs_condpaths_walk(adev, path, SNDRV_PCM_STREAM_PLAYBACK); +} + void avs_path_free(struct avs_path *path) { + struct avs_path *cpath, *csave; struct avs_dev *adev = path->owner; mutex_lock(&adev->path_mutex); + + /* Free all condpaths this path spawned. */ + list_for_each_entry_safe(cpath, csave, &path->source_list, source_node) + avs_condpath_free(path->owner, cpath); + list_for_each_entry_safe(cpath, csave, &path->sink_list, sink_node) + avs_condpath_free(path->owner, cpath); + avs_path_free_unlocked(path); + mutex_unlock(&adev->path_mutex); } @@ -1150,6 +1320,7 @@ struct avs_path *avs_path_create(struct avs_dev *adev, u32 dma_id, { struct avs_tplg_path *variant; struct avs_path *path; + int ret; variant = avs_path_find_variant(adev, template, fe_params, be_params); if (!variant) { @@ -1163,7 +1334,16 @@ struct avs_path *avs_path_create(struct avs_dev *adev, u32 dma_id, mutex_lock(&adev->comp_list_mutex); path = avs_path_create_unlocked(adev, dma_id, variant); + if (IS_ERR(path)) + goto exit; + ret = avs_condpaths_walk_all(adev, path); + if (ret) { + avs_path_free_unlocked(path); + path = ERR_PTR(ret); + } + +exit: mutex_unlock(&adev->comp_list_mutex); mutex_unlock(&adev->path_mutex); @@ -1286,6 +1466,42 @@ int avs_path_reset(struct avs_path *path) return 0; } +static int avs_condpath_pause(struct avs_dev *adev, struct avs_path *cpath) +{ + struct avs_path_pipeline *ppl; + int ret; + + if (cpath->state == AVS_PPL_STATE_PAUSED) + return 0; + + list_for_each_entry_reverse(ppl, &cpath->ppl_list, node) { + ret = avs_ipc_set_pipeline_state(adev, ppl->instance_id, AVS_PPL_STATE_PAUSED); + if (ret) { + dev_err(adev->dev, "pause cpath failed: %d\n", ret); + cpath->state = AVS_PPL_STATE_INVALID; + return AVS_IPC_RET(ret); + } + } + + cpath->state = AVS_PPL_STATE_PAUSED; + return 0; +} + +static void avs_condpaths_pause(struct avs_dev *adev, struct avs_path *path) +{ + struct avs_path *cpath; + + mutex_lock(&adev->path_mutex); + + /* If either source or sink stops, so do the attached conditional paths. */ + list_for_each_entry(cpath, &path->source_list, source_node) + avs_condpath_pause(adev, cpath); + list_for_each_entry(cpath, &path->sink_list, sink_node) + avs_condpath_pause(adev, cpath); + + mutex_unlock(&adev->path_mutex); +} + int avs_path_pause(struct avs_path *path) { struct avs_path_pipeline *ppl; @@ -1295,6 +1511,8 @@ int avs_path_pause(struct avs_path *path) if (path->state == AVS_PPL_STATE_PAUSED) return 0; + avs_condpaths_pause(adev, path); + list_for_each_entry_reverse(ppl, &path->ppl_list, node) { ret = avs_ipc_set_pipeline_state(adev, ppl->instance_id, AVS_PPL_STATE_PAUSED); @@ -1309,6 +1527,50 @@ int avs_path_pause(struct avs_path *path) return 0; } +static int avs_condpath_run(struct avs_dev *adev, struct avs_path *cpath, int trigger) +{ + struct avs_path_pipeline *ppl; + int ret; + + if (cpath->state == AVS_PPL_STATE_RUNNING) + return 0; + + list_for_each_entry(ppl, &cpath->ppl_list, node) { + if (ppl->template->cfg->trigger != trigger) + continue; + + ret = avs_ipc_set_pipeline_state(adev, ppl->instance_id, AVS_PPL_STATE_RUNNING); + if (ret) { + dev_err(adev->dev, "run cpath failed: %d\n", ret); + cpath->state = AVS_PPL_STATE_INVALID; + return AVS_IPC_RET(ret); + } + } + + cpath->state = AVS_PPL_STATE_RUNNING; + return 0; +} + +static void avs_condpaths_run(struct avs_dev *adev, struct avs_path *path, int trigger) +{ + struct avs_path *cpath; + + mutex_lock(&adev->path_mutex); + + /* Run conditional paths only if source and sink are both running. */ + list_for_each_entry(cpath, &path->source_list, source_node) + if (cpath->source->state == AVS_PPL_STATE_RUNNING && + cpath->sink->state == AVS_PPL_STATE_RUNNING) + avs_condpath_run(adev, cpath, trigger); + + list_for_each_entry(cpath, &path->sink_list, sink_node) + if (cpath->source->state == AVS_PPL_STATE_RUNNING && + cpath->sink->state == AVS_PPL_STATE_RUNNING) + avs_condpath_run(adev, cpath, trigger); + + mutex_unlock(&adev->path_mutex); +} + int avs_path_run(struct avs_path *path, int trigger) { struct avs_path_pipeline *ppl; @@ -1332,5 +1594,10 @@ int avs_path_run(struct avs_path *path, int trigger) } path->state = AVS_PPL_STATE_RUNNING; + + /* Granular pipeline triggering not intended for conditional paths. */ + if (trigger == AVS_TPLG_TRIGGER_AUTO) + avs_condpaths_run(adev, path, trigger); + return 0; } diff --git a/sound/soc/intel/avs/path.h b/sound/soc/intel/avs/path.h index c65ed84aa853..ceb89971a902 100644 --- a/sound/soc/intel/avs/path.h +++ b/sound/soc/intel/avs/path.h @@ -13,11 +13,24 @@ #include "avs.h" #include "topology.h" +#define AVS_COND_TYPE_NONE 0 +#define AVS_COND_TYPE_AECREF 1 + struct avs_path { u32 dma_id; struct list_head ppl_list; u32 state; + /* condpath navigation for standard paths */ + struct list_head source_list; + struct list_head sink_list; + + /* conditional path fields */ + struct avs_path *source; + struct avs_path *sink; + struct list_head source_node; + struct list_head sink_node; + struct avs_tplg_path *template; struct avs_dev *owner; /* device path management */ From 40229ea9fa437d6a1feb86be9dd419e843ec754c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 6 Aug 2025 04:41:41 +0000 Subject: [PATCH 00035/11391] ASoC: soc-dapm: move snd_soc_dapm_get_bias_level() to soc-dpcm Because struct snd_soc_dapm_context is soc-dapm framework specific, user driver don't need to access its member directly, we would like to hide them. struct snd_soc_dapm_context will be removed from header in the future. Because dapm will not be used on user driver in the future, Let's move snd_soc_dapm_get_bias_level() to soc-dpcm.c Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/874iul83ju.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 13 +------------ sound/soc/soc-dapm.c | 12 ++++++++++++ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 0b5c7e6a90c8..f1318cdcf7e4 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -722,6 +722,7 @@ struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(struct snd_kcontrol *kco struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_widget(struct snd_kcontrol *kcontrol); int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level); +enum snd_soc_bias_level snd_soc_dapm_get_bias_level(struct snd_soc_dapm_context *dapm); #define for_each_dapm_widgets(list, i, widget) \ for ((i) = 0; \ @@ -747,18 +748,6 @@ static inline void snd_soc_dapm_init_bias_level( dapm->bias_level = level; } -/** - * snd_soc_dapm_get_bias_level() - Get current DAPM bias level - * @dapm: The context for which to get the bias level - * - * Returns: The current bias level of the passed DAPM context. - */ -static inline enum snd_soc_bias_level snd_soc_dapm_get_bias_level( - struct snd_soc_dapm_context *dapm) -{ - return dapm->bias_level; -} - /** * snd_soc_dapm_widget_for_each_path - Iterates over all paths in the * specified direction of a widget diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index a37d44cd04c6..6ee03cf16171 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1037,6 +1037,18 @@ static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm, return ret; } +/** + * snd_soc_dapm_get_bias_level() - Get current DAPM bias level + * @dapm: The context for which to get the bias level + * + * Returns: The current bias level of the passed DAPM context. + */ +enum snd_soc_bias_level snd_soc_dapm_get_bias_level(struct snd_soc_dapm_context *dapm) +{ + return dapm->bias_level; +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_get_bias_level); + static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm, struct snd_soc_dapm_widget *kcontrolw, const struct snd_kcontrol_new *kcontrol_new, From e93703687cd75a0c7d330e15a3d9ff20b12f3d1d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 6 Aug 2025 04:41:46 +0000 Subject: [PATCH 00036/11391] ASoC: soc-dapm: move snd_soc_dapm_init_bias_level() to soc-dpcm Because struct snd_soc_dapm_context is soc-dapm framework specific, user driver don't need to access its member directly, we would like to hide them. struct snd_soc_dapm_context will be removed from header in the future. Because dapm will not be used on user driver in the future, Let's move snd_soc_dapm_init_bias_level() to soc-dpcm.c Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/8734a583jp.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 20 +------------------- sound/soc/soc-dapm.c | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index f1318cdcf7e4..53bf6590bd4b 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -723,31 +723,13 @@ struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_widget(struct snd_kcontrol *kc int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level); enum snd_soc_bias_level snd_soc_dapm_get_bias_level(struct snd_soc_dapm_context *dapm); +void snd_soc_dapm_init_bias_level(struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level); #define for_each_dapm_widgets(list, i, widget) \ for ((i) = 0; \ (i) < list->num_widgets && (widget = list->widgets[i]); \ (i)++) -/** - * snd_soc_dapm_init_bias_level() - Initialize DAPM bias level - * @dapm: The DAPM context to initialize - * @level: The DAPM level to initialize to - * - * This function only sets the driver internal state of the DAPM level and will - * not modify the state of the device. Hence it should not be used during normal - * operation, but only to synchronize the internal state to the device state. - * E.g. during driver probe to set the DAPM level to the one corresponding with - * the power-on reset state of the device. - * - * To change the DAPM state of the device use snd_soc_dapm_set_bias_level(). - */ -static inline void snd_soc_dapm_init_bias_level( - struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) -{ - dapm->bias_level = level; -} - /** * snd_soc_dapm_widget_for_each_path - Iterates over all paths in the * specified direction of a widget diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 6ee03cf16171..6782a0d6cd47 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -999,6 +999,25 @@ int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm, } EXPORT_SYMBOL_GPL(snd_soc_dapm_force_bias_level); +/** + * snd_soc_dapm_init_bias_level() - Initialize DAPM bias level + * @dapm: The DAPM context to initialize + * @level: The DAPM level to initialize to + * + * This function only sets the driver internal state of the DAPM level and will + * not modify the state of the device. Hence it should not be used during normal + * operation, but only to synchronize the internal state to the device state. + * E.g. during driver probe to set the DAPM level to the one corresponding with + * the power-on reset state of the device. + * + * To change the DAPM state of the device use snd_soc_dapm_set_bias_level(). + */ +void snd_soc_dapm_init_bias_level(struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) +{ + dapm->bias_level = level; +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_init_bias_level); + /** * snd_soc_dapm_set_bias_level - set the bias level for the system * @dapm: DAPM context From 7b900b5878a910d60ecfa67448bbe81e4e2bb8b7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 6 Aug 2025 04:41:51 +0000 Subject: [PATCH 00037/11391] ASoC: soc-component: unpack snd_soc_component_force_bias_level() Because struct snd_soc_dapm_context is soc-dapm framework specific, user driver don't need to access its member directly, we would like to hide them. struct snd_soc_dapm_context will be removed from header in the future. This patch unpack component wrapper to cleanup it. The function will be kept by using macro for a while, but will be replaced/cleanuped in the future. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/871ppp83jk.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 17 ----------------- include/sound/soc-dapm.h | 3 +++ 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 2caa807c6249..c616f489c237 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -314,23 +314,6 @@ snd_soc_component_get_bias_level(struct snd_soc_component *component) snd_soc_component_get_dapm(component)); } -/** - * snd_soc_component_force_bias_level() - Set the COMPONENT DAPM bias level - * @component: The COMPONENT for which to set the level - * @level: The level to set to - * - * Forces the COMPONENT bias level to a specific state. See - * snd_soc_dapm_force_bias_level(). - */ -static inline int -snd_soc_component_force_bias_level(struct snd_soc_component *component, - enum snd_soc_bias_level level) -{ - return snd_soc_dapm_force_bias_level( - snd_soc_component_get_dapm(component), - level); -} - /** * snd_soc_dapm_kcontrol_component() - Returns the component associated to a * kcontrol diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 53bf6590bd4b..5bd9a27b12ba 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -725,6 +725,9 @@ int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm, enum snd_so enum snd_soc_bias_level snd_soc_dapm_get_bias_level(struct snd_soc_dapm_context *dapm); void snd_soc_dapm_init_bias_level(struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level); +// REMOVE ME !! +#define snd_soc_component_force_bias_level(c, l) snd_soc_dapm_force_bias_level(&(c)->dapm, l) + #define for_each_dapm_widgets(list, i, widget) \ for ((i) = 0; \ (i) < list->num_widgets && (widget = list->widgets[i]); \ From 7509e7e4288976e3028a6e8482d979ca77f584a7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 6 Aug 2025 04:41:55 +0000 Subject: [PATCH 00038/11391] ASoC: soc-component: unpack snd_soc_component_get_bias_level() Because struct snd_soc_dapm_context is soc-dapm framework specific, user driver don't need to access its member directly, we would like to hide them. struct snd_soc_dapm_context will be removed from header in the future. This patch unpack component wrapper to cleanup it. The function will be kept by using macro for a while, but will be replaced/cleanuped in the future. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87zfcd6oz0.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 13 ------------- include/sound/soc-dapm.h | 1 + 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index c616f489c237..86ad2802879f 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -301,19 +301,6 @@ snd_soc_component_init_bias_level(struct snd_soc_component *component, snd_soc_component_get_dapm(component), level); } -/** - * snd_soc_component_get_bias_level() - Get current COMPONENT DAPM bias level - * @component: The COMPONENT for which to get the DAPM bias level - * - * Returns: The current DAPM bias level of the COMPONENT. - */ -static inline enum snd_soc_bias_level -snd_soc_component_get_bias_level(struct snd_soc_component *component) -{ - return snd_soc_dapm_get_bias_level( - snd_soc_component_get_dapm(component)); -} - /** * snd_soc_dapm_kcontrol_component() - Returns the component associated to a * kcontrol diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 5bd9a27b12ba..6e2db79d6a97 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -727,6 +727,7 @@ void snd_soc_dapm_init_bias_level(struct snd_soc_dapm_context *dapm, enum snd_so // REMOVE ME !! #define snd_soc_component_force_bias_level(c, l) snd_soc_dapm_force_bias_level(&(c)->dapm, l) +#define snd_soc_component_get_bias_level(c) snd_soc_dapm_get_bias_level(&(c)->dapm) #define for_each_dapm_widgets(list, i, widget) \ for ((i) = 0; \ From cf25eb8eae91bcae9b2065d84b0c0ba0f6d9dd34 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 6 Aug 2025 04:42:05 +0000 Subject: [PATCH 00039/11391] ASoC: soc-component: unpack snd_soc_component_init_bias_level() Because struct snd_soc_dapm_context is soc-dapm framework specific, user driver don't need to access its member directly, we would like to hide them. struct snd_soc_dapm_context will be removed from header in the future. This patch unpack component wrapper to cleanup it. This patch keeps compatible by using define, but old name will be replaced on each drivers and removed from ASoC in the future. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87y0rx6oyx.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 15 --------------- include/sound/soc-dapm.h | 1 + 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 86ad2802879f..54bfa0cb1085 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -286,21 +286,6 @@ static inline struct snd_soc_dapm_context *snd_soc_component_get_dapm( return &component->dapm; } -/** - * snd_soc_component_init_bias_level() - Initialize COMPONENT DAPM bias level - * @component: The COMPONENT for which to initialize the DAPM bias level - * @level: The DAPM level to initialize to - * - * Initializes the COMPONENT DAPM bias level. See snd_soc_dapm_init_bias_level() - */ -static inline void -snd_soc_component_init_bias_level(struct snd_soc_component *component, - enum snd_soc_bias_level level) -{ - snd_soc_dapm_init_bias_level( - snd_soc_component_get_dapm(component), level); -} - /** * snd_soc_dapm_kcontrol_component() - Returns the component associated to a * kcontrol diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 6e2db79d6a97..2e9196b6ffba 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -728,6 +728,7 @@ void snd_soc_dapm_init_bias_level(struct snd_soc_dapm_context *dapm, enum snd_so // REMOVE ME !! #define snd_soc_component_force_bias_level(c, l) snd_soc_dapm_force_bias_level(&(c)->dapm, l) #define snd_soc_component_get_bias_level(c) snd_soc_dapm_get_bias_level(&(c)->dapm) +#define snd_soc_component_init_bias_level(c, l) snd_soc_dapm_init_bias_level(&(c)->dapm, l) #define for_each_dapm_widgets(list, i, widget) \ for ((i) = 0; \ From 5383d67e2430822fa7bd20dcbbebbd8ae808e386 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 8 Aug 2025 17:17:52 +0200 Subject: [PATCH 00040/11391] ASoC: add GPIOLIB_LEGACY dependency where needed In order to make the legacy gpiolib interfaces such as gpio_request() optional, mark the three ASoC driver that rely on it today with a dependency on the new Kconfig symbol. The tlv320dac33 and ak4641 drivers have no in-tree users, while the uda1380 driver is theoretically referened by two lpc3250 based boards, but neither of them work because of the legacy gpiolib dependency. Signed-off-by: Arnd Bergmann Link: https://patch.msgid.link/20250808151822.536879-9-arnd@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 6d7e4725d89c..759bcb8260cd 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -622,6 +622,7 @@ config SND_SOC_AK4619 config SND_SOC_AK4641 tristate depends on I2C + depends on GPIOLIB_LEGACY config SND_SOC_AK4642 tristate "AKM AK4642 CODEC" @@ -2175,6 +2176,7 @@ config SND_SOC_TLV320AIC3X_SPI config SND_SOC_TLV320DAC33 tristate depends on I2C + depends on GPIOLIB_LEGACY config SND_SOC_TLV320ADCX140 tristate "Texas Instruments TLV320ADCX140 CODEC family" @@ -2229,6 +2231,7 @@ config SND_SOC_UDA1342 config SND_SOC_UDA1380 tristate depends on I2C + depends on GPIOLIB_LEGACY config SND_SOC_WCD_CLASSH tristate From 2d86d2585ab929a143d1e6f8963da1499e33bf13 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 8 Aug 2025 17:18:05 +0200 Subject: [PATCH 00041/11391] ASoC: pxa: add GPIOLIB_LEGACY dependency The pxa27x platform uses the legacy gpiolib interfaces, including in its sound drivers: sound/arm/pxa2xx-ac97-lib.c: In function 'pxa2xx_ac97_hw_probe': sound/arm/pxa2xx-ac97-lib.c:374:23: error: implicit declaration of function 'gpio_request_one' [-Wimplicit-function-declaration] 374 | ret = gpio_request_one(reset_gpio, GPIOF_OUT_INIT_HIGH, Make sure we don't select those drivers for compile-testing unless we are building for a pxa27x system, or CONFIG_GPIOLIB_LEGACY is already enabled. The SND_PXA_SOC_SSP driver accidentally used a dependency on PLAT_PXA, which includes both ARCH_PXA and ARCH_MMP, but it is only used on the former. Signed-off-by: Arnd Bergmann Link: https://patch.msgid.link/20250808151822.536879-21-arnd@kernel.org Signed-off-by: Mark Brown --- sound/soc/pxa/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index e026f9912a6d..e54abcd39f79 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig @@ -3,7 +3,7 @@ menu "PXA" config SND_PXA2XX_SOC tristate "SoC Audio for the Intel PXA2xx chip" - depends on ARCH_PXA || COMPILE_TEST + depends on ARCH_PXA || (COMPILE_TEST && GPIOLIB_LEGACY) select SND_PXA2XX_LIB help Say Y or M if you want to add support for codecs attached to @@ -26,7 +26,7 @@ config SND_PXA2XX_SOC_I2S config SND_PXA_SOC_SSP tristate "Soc Audio via PXA2xx/PXA3xx SSP ports" - depends on PLAT_PXA + depends on ARCH_PXA select PXA_SSP select SND_PXA2XX_LIB From 605d902bb6b6f5b12a5baeaca0dc359ced7685cb Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Thu, 7 Aug 2025 16:43:57 -0500 Subject: [PATCH 00042/11391] ASoC: dt-bindings: Drop imx-audio-sgtl5000.txt The "fsl,imx-audio-sgtl5000" binding is already covered by fsl-asoc-card.yaml, so remove the old text binding. Signed-off-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250807214358.4172451-1-robh@kernel.org Acked-by: Conor Dooley Signed-off-by: Mark Brown --- .../bindings/sound/imx-audio-sgtl5000.txt | 56 ------------------- 1 file changed, 56 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt diff --git a/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt b/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt deleted file mode 100644 index 2f89db88fd57..000000000000 --- a/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt +++ /dev/null @@ -1,56 +0,0 @@ -Freescale i.MX audio complex with SGTL5000 codec - -Required properties: - - - compatible : "fsl,imx-audio-sgtl5000" - - - model : The user-visible name of this sound complex - - - ssi-controller : The phandle of the i.MX SSI controller - - - audio-codec : The phandle of the SGTL5000 audio codec - - - audio-routing : A list of the connections between audio components. - Each entry is a pair of strings, the first being the - connection's sink, the second being the connection's - source. Valid names could be power supplies, SGTL5000 - pins, and the jacks on the board: - - Power supplies: - * Mic Bias - - SGTL5000 pins: - * MIC_IN - * LINE_IN - * HP_OUT - * LINE_OUT - - Board connectors: - * Mic Jack - * Line In Jack - * Headphone Jack - * Line Out Jack - * Ext Spk - - - mux-int-port : The internal port of the i.MX audio muxer (AUDMUX) - - - mux-ext-port : The external port of the i.MX audio muxer - -Note: The AUDMUX port numbering should start at 1, which is consistent with -hardware manual. - -Example: - -sound { - compatible = "fsl,imx51-babbage-sgtl5000", - "fsl,imx-audio-sgtl5000"; - model = "imx51-babbage-sgtl5000"; - ssi-controller = <&ssi1>; - audio-codec = <&sgtl5000>; - audio-routing = - "MIC_IN", "Mic Jack", - "Mic Jack", "Mic Bias", - "Headphone Jack", "HP_OUT"; - mux-int-port = <1>; - mux-ext-port = <3>; -}; From 32dffd4c3e3129e3d9bb378af8d80bb57dc3038b Mon Sep 17 00:00:00 2001 From: Chancel Liu Date: Fri, 8 Aug 2025 15:17:41 +0900 Subject: [PATCH 00043/11391] ASoC: dmaengine_pcm: Add port_window_size to DAI dma data struct The port_window_size is a struct member of dma slave channel runtime config. It's the length of the register area in words the data need to be accessed on the device side. It is only used for devices which is using an area instead of a single register to send or receive the data. Typically the DMA loops in this area in order to transfer the data. It's useful for cases that reading/writing multiple registers in DMA transactions. Signed-off-by: Chancel Liu Link: https://patch.msgid.link/20250808061741.187414-1-chancel.liu@nxp.com Signed-off-by: Mark Brown --- include/sound/dmaengine_pcm.h | 5 +++++ sound/core/pcm_dmaengine.c | 2 ++ 2 files changed, 7 insertions(+) diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index 1ef13bcdc43f..9472f0a966a2 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -69,6 +69,10 @@ struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream) * @peripheral_config: peripheral configuration for programming peripheral * for dmaengine transfer * @peripheral_size: peripheral configuration buffer size + * @port_window_size: The length of the register area in words the data need + * to be accessed on the device side. It is only used for devices which is using + * an area instead of a single register to send/receive the data. Typically the + * DMA loops in this area in order to transfer the data. */ struct snd_dmaengine_dai_dma_data { dma_addr_t addr; @@ -80,6 +84,7 @@ struct snd_dmaengine_dai_dma_data { unsigned int flags; void *peripheral_config; size_t peripheral_size; + u32 port_window_size; }; void snd_dmaengine_pcm_set_config_from_dai_data( diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c index 72040964b6fd..f0c17503df42 100644 --- a/sound/core/pcm_dmaengine.c +++ b/sound/core/pcm_dmaengine.c @@ -111,6 +111,7 @@ void snd_dmaengine_pcm_set_config_from_dai_data( if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { slave_config->dst_addr = dma_data->addr; slave_config->dst_maxburst = dma_data->maxburst; + slave_config->dst_port_window_size = dma_data->port_window_size; if (dma_data->flags & SND_DMAENGINE_PCM_DAI_FLAG_PACK) slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED; @@ -119,6 +120,7 @@ void snd_dmaengine_pcm_set_config_from_dai_data( } else { slave_config->src_addr = dma_data->addr; slave_config->src_maxburst = dma_data->maxburst; + slave_config->src_port_window_size = dma_data->port_window_size; if (dma_data->flags & SND_DMAENGINE_PCM_DAI_FLAG_PACK) slave_config->src_addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED; From e83dcd139e776ebb86d5e88e13282580407278e4 Mon Sep 17 00:00:00 2001 From: Shenghao Ding Date: Sun, 3 Aug 2025 21:11:10 +0800 Subject: [PATCH 00044/11391] ASoC: tas2781: Add keyword "init" in profile section Since version 0x105, the keyword 'init' was introduced into the profile, which is used for chip initialization, particularly to store common settings for other non-initialization profiles. Signed-off-by: Shenghao Ding Link: https://patch.msgid.link/20250803131110.1443-1-shenghao-ding@ti.com Signed-off-by: Mark Brown --- include/sound/tas2781-dsp.h | 8 ++++++++ sound/soc/codecs/tas2781-fmwlib.c | 12 ++++++++++++ sound/soc/codecs/tas2781-i2c.c | 6 ++++++ 3 files changed, 26 insertions(+) diff --git a/include/sound/tas2781-dsp.h b/include/sound/tas2781-dsp.h index c3a9efa73d5d..a21f34c0266e 100644 --- a/include/sound/tas2781-dsp.h +++ b/include/sound/tas2781-dsp.h @@ -198,6 +198,14 @@ struct tasdevice_rca { int ncfgs; struct tasdevice_config_info **cfg_info; int profile_cfg_id; + /* + * Since version 0x105, the keyword 'init' was introduced into the + * profile, which is used for chip initialization, particularly to + * store common settings for other non-initialization profiles. + * if (init_profile_id < 0) + * No init profile inside the RCA firmware. + */ + int init_profile_id; }; void tasdevice_select_cfg_blk(void *context, int conf_no, diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c index c9c1e608ddb7..8baf56237624 100644 --- a/sound/soc/codecs/tas2781-fmwlib.c +++ b/sound/soc/codecs/tas2781-fmwlib.c @@ -180,6 +180,16 @@ static struct tasdevice_config_info *tasdevice_add_config( dev_err(tas_priv->dev, "add conf: Out of boundary\n"); goto out; } + /* If in the RCA bin file are several profiles with the + * keyword "init", init_profile_id only store the last + * init profile id. + */ + if (strnstr(&config_data[config_offset], "init", 64)) { + tas_priv->rcabin.init_profile_id = + tas_priv->rcabin.ncfgs - 1; + dev_dbg(tas_priv->dev, "%s: init profile id = %d\n", + __func__, tas_priv->rcabin.init_profile_id); + } config_offset += 64; } @@ -283,6 +293,8 @@ int tasdevice_rca_parser(void *context, const struct firmware *fmw) int i; rca = &(tas_priv->rcabin); + /* Initialize to none */ + rca->init_profile_id = -1; fw_hdr = &(rca->fw_hdr); if (!fmw || !fmw->data) { dev_err(tas_priv->dev, "Failed to read %s\n", diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c index 9f4d965a1335..f8faeffd983d 100644 --- a/sound/soc/codecs/tas2781-i2c.c +++ b/sound/soc/codecs/tas2781-i2c.c @@ -1641,6 +1641,12 @@ static void tasdevice_fw_ready(const struct firmware *fmw, tasdevice_prmg_load(tas_priv, 0); tas_priv->cur_prog = 0; + /* Init common setting for different audio profiles */ + if (tas_priv->rcabin.init_profile_id >= 0) + tasdevice_select_cfg_blk(tas_priv, + tas_priv->rcabin.init_profile_id, + TASDEVICE_BIN_BLK_PRE_POWER_UP); + #ifdef CONFIG_SND_SOC_TAS2781_ACOUST_I2C if (tas_priv->name_prefix) acoustic_debugfs_node = devm_kasprintf(tas_priv->dev, From 8ed2dca4df2297177e0edcb7e0c72ef87f3fd81a Mon Sep 17 00:00:00 2001 From: Terry Cheong Date: Wed, 23 Jul 2025 17:20:11 +0800 Subject: [PATCH 00045/11391] ASoC: mediatek: Use SND_JACK_AVOUT for HDMI/DP jacks The SND_JACK_AVOUT is a more specific jack type for HDMI and DisplayPort. Updatae the MediaTek drivers to use such jack type, allowing system to determine the device type based on jack event. Signed-off-by: Terry Cheong Reviewed-by: Chen-Yu Tsai Link: https://patch.msgid.link/20250723-mtk-hdmi-v1-1-4ff945eb6136@chromium.org Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8173/mt8173-rt5650.c | 2 +- sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c | 2 +- .../soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c | 2 +- sound/soc/mediatek/mt8186/mt8186-mt6366.c | 2 +- sound/soc/mediatek/mt8188/mt8188-mt6359.c | 8 ++++---- sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c | 2 +- sound/soc/mediatek/mt8195/mt8195-mt6359.c | 4 ++-- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c index 7d6a3586cdd5..3d6d7bc05b87 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c @@ -159,7 +159,7 @@ static int mt8173_rt5650_hdmi_init(struct snd_soc_pcm_runtime *rtd) { int ret; - ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT, + ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_AVOUT, &mt8173_rt5650_hdmi_jack); if (ret) return ret; diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c index 3388e076ccc9..983f3b91119a 100644 --- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c @@ -378,7 +378,7 @@ static int mt8183_da7219_max98357_hdmi_init(struct snd_soc_pcm_runtime *rtd) snd_soc_card_get_drvdata(rtd->card); int ret; - ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT, + ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_AVOUT, &priv->hdmi_jack); if (ret) return ret; diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c index 497a9043be7b..0bc1f11e17aa 100644 --- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c @@ -383,7 +383,7 @@ mt8183_mt6358_ts3a227_max98357_hdmi_init(struct snd_soc_pcm_runtime *rtd) snd_soc_card_get_drvdata(rtd->card); int ret; - ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT, + ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_AVOUT, &priv->hdmi_jack); if (ret) return ret; diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366.c b/sound/soc/mediatek/mt8186/mt8186-mt6366.c index 43546012cf61..45df69809cba 100644 --- a/sound/soc/mediatek/mt8186/mt8186-mt6366.c +++ b/sound/soc/mediatek/mt8186/mt8186-mt6366.c @@ -362,7 +362,7 @@ static int mt8186_mt6366_rt1019_rt5682s_hdmi_init(struct snd_soc_pcm_runtime *rt return ret; } - ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT, jack); + ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_AVOUT, jack); if (ret) { dev_err(rtd->dev, "HDMI Jack creation failed: %d\n", ret); return ret; diff --git a/sound/soc/mediatek/mt8188/mt8188-mt6359.c b/sound/soc/mediatek/mt8188/mt8188-mt6359.c index ea814a0f726d..c6e7461e8f76 100644 --- a/sound/soc/mediatek/mt8188/mt8188-mt6359.c +++ b/sound/soc/mediatek/mt8188/mt8188-mt6359.c @@ -250,14 +250,14 @@ enum mt8188_jacks { static struct snd_soc_jack_pin mt8188_hdmi_jack_pins[] = { { .pin = "HDMI", - .mask = SND_JACK_LINEOUT, + .mask = SND_JACK_AVOUT, }, }; static struct snd_soc_jack_pin mt8188_dp_jack_pins[] = { { .pin = "DP", - .mask = SND_JACK_LINEOUT, + .mask = SND_JACK_AVOUT, }, }; @@ -638,7 +638,7 @@ static int mt8188_hdmi_codec_init(struct snd_soc_pcm_runtime *rtd) int ret = 0; ret = snd_soc_card_jack_new_pins(rtd->card, "HDMI Jack", - SND_JACK_LINEOUT, jack, + SND_JACK_AVOUT, jack, mt8188_hdmi_jack_pins, ARRAY_SIZE(mt8188_hdmi_jack_pins)); if (ret) { @@ -663,7 +663,7 @@ static int mt8188_dptx_codec_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; int ret = 0; - ret = snd_soc_card_jack_new_pins(rtd->card, "DP Jack", SND_JACK_LINEOUT, + ret = snd_soc_card_jack_new_pins(rtd->card, "DP Jack", SND_JACK_AVOUT, jack, mt8188_dp_jack_pins, ARRAY_SIZE(mt8188_dp_jack_pins)); if (ret) { diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c index bf483a8fb34a..91c57765ab57 100644 --- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c +++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c @@ -368,7 +368,7 @@ static int mt8192_mt6359_hdmi_init(struct snd_soc_pcm_runtime *rtd) snd_soc_rtd_to_codec(rtd, 0)->component; int ret; - ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT, jack); + ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_AVOUT, jack); if (ret) { dev_err(rtd->dev, "HDMI Jack creation failed: %d\n", ret); return ret; diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359.c b/sound/soc/mediatek/mt8195/mt8195-mt6359.c index e57391c213e7..7b96c843a14a 100644 --- a/sound/soc/mediatek/mt8195/mt8195-mt6359.c +++ b/sound/soc/mediatek/mt8195/mt8195-mt6359.c @@ -360,7 +360,7 @@ static int mt8195_dptx_codec_init(struct snd_soc_pcm_runtime *rtd) snd_soc_rtd_to_codec(rtd, 0)->component; int ret; - ret = snd_soc_card_jack_new(rtd->card, "DP Jack", SND_JACK_LINEOUT, jack); + ret = snd_soc_card_jack_new(rtd->card, "DP Jack", SND_JACK_AVOUT, jack); if (ret) return ret; @@ -375,7 +375,7 @@ static int mt8195_hdmi_codec_init(struct snd_soc_pcm_runtime *rtd) snd_soc_rtd_to_codec(rtd, 0)->component; int ret; - ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT, jack); + ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_AVOUT, jack); if (ret) return ret; From 9d6a51651faa577e5d2be9d67915b7621c5c589a Mon Sep 17 00:00:00 2001 From: Waqar Hameed Date: Tue, 5 Aug 2025 11:33:32 +0200 Subject: [PATCH 00046/11391] ASoC: SOF: imx: 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: Daniel Baluta Link: https://patch.msgid.link/pndpldam7tf.a.out@axis.com Signed-off-by: Mark Brown --- sound/soc/sof/imx/imx-common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/imx/imx-common.c b/sound/soc/sof/imx/imx-common.c index f00b381cec3b..1757539a6a28 100644 --- a/sound/soc/sof/imx/imx-common.c +++ b/sound/soc/sof/imx/imx-common.c @@ -382,7 +382,7 @@ static int imx_probe(struct snd_sof_dev *sdev) imx_unregister_action, sdev); if (ret) - return dev_err_probe(sdev->dev, ret, "failed to add devm action\n"); + return ret; common->ipc_handle = dev_get_drvdata(&common->ipc_dev->dev); if (!common->ipc_handle) From 2399f3bd31595adfbc9bf38d6699b0a2ff36aee0 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Fri, 8 Aug 2025 13:57:19 +0800 Subject: [PATCH 00047/11391] ASoC: rt721: add some vendor registers This patch added some vendor registers to read for debugging. Signed-off-by: Shuming Fan Link: https://patch.msgid.link/20250808055719.1110808-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt721-sdca-sdw.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/rt721-sdca-sdw.c b/sound/soc/codecs/rt721-sdca-sdw.c index 582b47d69278..4d8a12b13015 100644 --- a/sound/soc/codecs/rt721-sdca-sdw.c +++ b/sound/soc/codecs/rt721-sdca-sdw.c @@ -63,15 +63,14 @@ static bool rt721_sdca_volatile_register(struct device *dev, unsigned int reg) static bool rt721_sdca_mbq_readable_register(struct device *dev, unsigned int reg) { switch (reg) { - case 0x0900007: + case 0x0900004 ... 0x0900009: case 0x0a00005: case 0x0c00005: case 0x0d00014: case 0x0310100: - case 0x2000001: - case 0x2000002: - case 0x2000003: + case 0x2000000 ... 0x2000003: case 0x2000013: + case 0x200002c: case 0x200003c: case 0x2000046: case 0x5810000: @@ -134,6 +133,8 @@ static bool rt721_sdca_mbq_volatile_register(struct device *dev, unsigned int re { switch (reg) { case 0x0310100: + case 0x0900005: + case 0x0900009: case 0x0a00005: case 0x0c00005: case 0x0d00014: @@ -141,6 +142,7 @@ static bool rt721_sdca_mbq_volatile_register(struct device *dev, unsigned int re case 0x200000d: case 0x2000019: case 0x2000020: + case 0x200002c: case 0x2000030: case 0x2000046: case 0x2000067: From 3059067fd3378a5454e7928c08d20bf3ef186760 Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Tue, 5 Aug 2025 17:04:31 +0800 Subject: [PATCH 00048/11391] ASoC: cs48l32: Use PTR_ERR_OR_ZERO() to simplify code Use the standard error pointer macro to shorten the code and simplify. Signed-off-by: Xichao Zhao Link: https://patch.msgid.link/20250805090431.117114-1-zhao.xichao@vivo.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs48l32-tables.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/codecs/cs48l32-tables.c b/sound/soc/codecs/cs48l32-tables.c index 59eaa9a5029f..8ff3652a010e 100644 --- a/sound/soc/codecs/cs48l32-tables.c +++ b/sound/soc/codecs/cs48l32-tables.c @@ -533,8 +533,6 @@ static const struct regmap_config cs48l32_regmap = { int cs48l32_create_regmap(struct spi_device *spi, struct cs48l32 *cs48l32) { cs48l32->regmap = devm_regmap_init_spi(spi, &cs48l32_regmap); - if (IS_ERR(cs48l32->regmap)) - return PTR_ERR(cs48l32->regmap); - return 0; + return PTR_ERR_OR_ZERO(cs48l32->regmap); } From 886f42ce96e7ce80545704e7168a9c6b60cd6c03 Mon Sep 17 00:00:00 2001 From: Luis Henriques Date: Mon, 28 Jul 2025 16:08:29 +0100 Subject: [PATCH 00049/11391] regmap: mmio: Add missing MODULE_DESCRIPTION() There were already several commits to add module descriptions to regmap modules. But this one was still missing: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/base/regmap/regmap-mmio.o Signed-off-by: Luis Henriques Link: https://patch.msgid.link/20250728150829.11890-1-luis@igalia.com Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-mmio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c index 99d7fd85ca7d..29e5f3175301 100644 --- a/drivers/base/regmap/regmap-mmio.c +++ b/drivers/base/regmap/regmap-mmio.c @@ -609,4 +609,5 @@ void regmap_mmio_detach_clk(struct regmap *map) } EXPORT_SYMBOL_GPL(regmap_mmio_detach_clk); +MODULE_DESCRIPTION("regmap MMIO Module"); MODULE_LICENSE("GPL v2"); From f7fbf3091f4cc4133574852f655593e1613d1af0 Mon Sep 17 00:00:00 2001 From: Daniel Almeida Date: Tue, 29 Jul 2025 14:31:40 -0300 Subject: [PATCH 00050/11391] rust: regulator: remove needless &mut from member functions Regulator functions like "regulator_enable()" and "regulator_disable()" already provide their own locking through "regulator_lock_dependent()", so we can safely call the Rust API with a shared reference. This was already the case with Regulator::set_voltage() on the Rust side, but it was forgotten for Regulator::enable() and Regulator::disable(). Signed-off-by: Daniel Almeida Link: https://patch.msgid.link/20250729-regulator-send-sync-v1-1-8bcbd546b940@collabora.com Reviewed-by: Alexandre Courbot Reviewed-by: Alice Ryhl Signed-off-by: Mark Brown --- rust/kernel/regulator.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/rust/kernel/regulator.rs b/rust/kernel/regulator.rs index 65f3a125348f..d56aa229e838 100644 --- a/rust/kernel/regulator.rs +++ b/rust/kernel/regulator.rs @@ -203,20 +203,20 @@ pub struct Error { /// // A fictictious probe function that obtains a regulator and sets it up. /// fn probe(dev: &Device) -> Result { /// // Obtain a reference to a (fictitious) regulator. -/// let mut regulator = Regulator::::get(dev, c_str!("vcc"))?; +/// let regulator = Regulator::::get(dev, c_str!("vcc"))?; /// /// Ok(PrivateData { regulator }) /// } /// /// // A fictictious function that indicates that the device is going to be used. -/// fn open(dev: &Device, data: &mut PrivateData) -> Result { +/// fn open(dev: &Device, data: &PrivateData) -> Result { /// // Increase the `enabled` reference count. /// data.regulator.enable()?; /// /// Ok(()) /// } /// -/// fn close(dev: &Device, data: &mut PrivateData) -> Result { +/// fn close(dev: &Device, data: &PrivateData) -> Result { /// // Decrease the `enabled` reference count. /// data.regulator.disable()?; /// @@ -289,12 +289,12 @@ fn get_internal(dev: &Device, name: &CStr) -> Result> { }) } - fn enable_internal(&mut self) -> Result { + fn enable_internal(&self) -> Result { // SAFETY: Safe as per the type invariants of `Regulator`. to_result(unsafe { bindings::regulator_enable(self.inner.as_ptr()) }) } - fn disable_internal(&mut self) -> Result { + fn disable_internal(&self) -> Result { // SAFETY: Safe as per the type invariants of `Regulator`. to_result(unsafe { bindings::regulator_disable(self.inner.as_ptr()) }) } @@ -310,7 +310,7 @@ pub fn get(dev: &Device, name: &CStr) -> Result { pub fn try_into_enabled(self) -> Result, Error> { // We will be transferring the ownership of our `regulator_get()` count to // `Regulator`. - let mut regulator = ManuallyDrop::new(self); + let regulator = ManuallyDrop::new(self); regulator .enable_internal() @@ -339,7 +339,7 @@ pub fn get(dev: &Device, name: &CStr) -> Result { pub fn try_into_disabled(self) -> Result, Error> { // We will be transferring the ownership of our `regulator_get()` count // to `Regulator`. - let mut regulator = ManuallyDrop::new(self); + let regulator = ManuallyDrop::new(self); regulator .disable_internal() @@ -366,12 +366,12 @@ pub fn get(dev: &Device, name: &CStr) -> Result { } /// Increases the `enabled` reference count. - pub fn enable(&mut self) -> Result { + pub fn enable(&self) -> Result { self.enable_internal() } /// Decreases the `enabled` reference count. - pub fn disable(&mut self) -> Result { + pub fn disable(&self) -> Result { self.disable_internal() } } From 9a200cbdb54349909a42b45379e792e4b39dd223 Mon Sep 17 00:00:00 2001 From: Daniel Almeida Date: Tue, 29 Jul 2025 14:31:41 -0300 Subject: [PATCH 00051/11391] rust: regulator: implement Send and Sync for Regulator Sending a &Regulator to another thread is safe, as the regulator core will properly handle the locking for us. Additionally, there are no restrictions that prevents sending a Regulator to another thread. Given these two facts, implement Send and Sync. Signed-off-by: Daniel Almeida Link: https://patch.msgid.link/20250729-regulator-send-sync-v1-2-8bcbd546b940@collabora.com Reviewed-by: Alexandre Courbot Reviewed-by: Alice Ryhl Signed-off-by: Mark Brown --- rust/kernel/regulator.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/rust/kernel/regulator.rs b/rust/kernel/regulator.rs index d56aa229e838..704147e18bfc 100644 --- a/rust/kernel/regulator.rs +++ b/rust/kernel/regulator.rs @@ -398,6 +398,14 @@ fn drop(&mut self) { } } +// SAFETY: It is safe to send a `Regulator` across threads. In particular, a +// Regulator can be dropped from any thread. +unsafe impl Send for Regulator {} + +// SAFETY: It is safe to send a &Regulator across threads because the C side +// handles its own locking. +unsafe impl Sync for Regulator {} + /// A voltage. /// /// This type represents a voltage value in microvolts. From 82f0907931f016c04bcb992f764bd65992c7008e Mon Sep 17 00:00:00 2001 From: Joy Zou Date: Thu, 31 Jul 2025 18:44:41 +0800 Subject: [PATCH 00052/11391] dt-bindings: regulator: add PF0900 regulator yaml Add device binding doc for PF0900 PMIC driver. Can not get the I2C_CRC_EN config by reading register. If the PMIC OTP_I2C_CRC_EN is enable, need to add the nxp,i2c-crc-enable property. Signed-off-by: Joy Zou Link: https://patch.msgid.link/20250731-b4-pf09-v2-v3-1-4c2659516582@nxp.com Reviewed-by: Rob Herring (Arm) Signed-off-by: Mark Brown --- .../bindings/regulator/nxp,pf0900.yaml | 163 ++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/nxp,pf0900.yaml diff --git a/Documentation/devicetree/bindings/regulator/nxp,pf0900.yaml b/Documentation/devicetree/bindings/regulator/nxp,pf0900.yaml new file mode 100644 index 000000000000..8c8fc2cd4ced --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/nxp,pf0900.yaml @@ -0,0 +1,163 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/nxp,pf0900.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP PF0900 Power Management Integrated Circuit regulators + +maintainers: + - Joy Zou + +description: + The PF0900 is a power management integrated circuit (PMIC) optimized + for high performance i.MX9x based applications. It features five high + efficiency buck converters, three linear and one vaon regulators. It + provides low quiescent current in Standby and low power off Modes. + +properties: + compatible: + enum: + - nxp,pf0900 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + regulators: + type: object + additionalProperties: false + + properties: + vaon: + type: object + $ref: regulator.yaml# + unevaluatedProperties: false + + patternProperties: + "^ldo[1-3]$": + type: object + $ref: regulator.yaml# + unevaluatedProperties: false + + "^sw[1-5]$": + type: object + $ref: regulator.yaml# + unevaluatedProperties: false + + nxp,i2c-crc-enable: + type: boolean + description: + The CRC enabled during register read/write. Controlled by customer + unviewable fuse bits OTP_I2C_CRC_EN. Check chip part number. + +required: + - compatible + - reg + - interrupts + - regulators + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + pmic@8 { + compatible = "nxp,pf0900"; + reg = <0x08>; + interrupt-parent = <&pcal6524>; + interrupts = <89 IRQ_TYPE_LEVEL_LOW>; + nxp,i2c-crc-enable; + + regulators { + vaon { + regulator-name = "VAON"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + sw1 { + regulator-name = "SW1"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <1950>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-max-microvolt = <650000>; + regulator-suspend-min-microvolt = <650000>; + }; + }; + + sw2 { + regulator-name = "SW2"; + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <1950>; + }; + + sw3 { + regulator-name = "SW3"; + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <1950>; + }; + + sw4 { + regulator-name = "SW4"; + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <1950>; + }; + + sw5 { + regulator-name = "SW5"; + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <1950>; + }; + + ldo1 { + regulator-name = "LDO1"; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo2 { + regulator-name = "LDO2"; + regulator-min-microvolt = <650000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo3 { + regulator-name = "LDO3"; + regulator-min-microvolt = <650000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; + }; From 162e23657e5379f07c6404dbfbf4367cb438ea7d Mon Sep 17 00:00:00 2001 From: Joy Zou Date: Thu, 31 Jul 2025 18:44:42 +0800 Subject: [PATCH 00053/11391] regulator: pf0900: Add PMIC PF0900 support The PF0900 is a power management integrated circuit (PMIC) optimized for high performance i.MX9x based applications. It features five high efficiency buck converters, three linear and one vaon regulators. It provides low quiescent current in Standby and low power off Modes. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202507221720.jxsGRfcE-lkp@intel.com/ Closes: https://lore.kernel.org/oe-kbuild-all/202506181134.0Hkvy7CK-lkp@intel.com/ Signed-off-by: Joy Zou Link: https://patch.msgid.link/20250731-b4-pf09-v2-v3-2-4c2659516582@nxp.com Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 8 + drivers/regulator/Makefile | 1 + drivers/regulator/pf0900-regulator.c | 975 +++++++++++++++++++++++++++ 3 files changed, 984 insertions(+) create mode 100644 drivers/regulator/pf0900-regulator.c diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index eaa6df1c9f80..b474b4bf63b3 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -1006,6 +1006,14 @@ config REGULATOR_PCAP This driver provides support for the voltage regulators of the PCAP2 PMIC. +config REGULATOR_PF0900 + tristate "NXP PF0900/PF0901/PF09XX regulator driver" + depends on I2C + select REGMAP_I2C + help + Say y here to support the NXP PF0900/PF0901/PF09XX PMIC + regulator driver. + config REGULATOR_PF8X00 tristate "NXP PF8100/PF8121A/PF8200 regulator driver" depends on I2C && OF diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index be98b29d6675..74b029d29a8b 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -124,6 +124,7 @@ obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o obj-$(CONFIG_REGULATOR_QCOM_USB_VBUS) += qcom_usb_vbus-regulator.o obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o obj-$(CONFIG_REGULATOR_PCA9450) += pca9450-regulator.o +obj-$(CONFIG_REGULATOR_PF0900) += pf0900-regulator.o obj-$(CONFIG_REGULATOR_PF9453) += pf9453-regulator.o obj-$(CONFIG_REGULATOR_PF8X00) += pf8x00-regulator.o obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o diff --git a/drivers/regulator/pf0900-regulator.c b/drivers/regulator/pf0900-regulator.c new file mode 100644 index 000000000000..b5effee32917 --- /dev/null +++ b/drivers/regulator/pf0900-regulator.c @@ -0,0 +1,975 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright 2025 NXP. +// NXP PF0900 pmic driver + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum pf0900_regulators { + PF0900_SW1 = 0, + PF0900_SW2, + PF0900_SW3, + PF0900_SW4, + PF0900_SW5, + PF0900_LDO1, + PF0900_LDO2, + PF0900_LDO3, + PF0900_VAON, + PF0900_REGULATOR_CNT, +}; + +enum { + PF0900_DVS_LEVEL_RUN = 0, + PF0900_DVS_LEVEL_STANDBY, + PF0900_DVS_LEVEL_MAX, +}; + + +#define PF0900_VAON_VOLTAGE_NUM 0x03 +#define PF0900_SW_VOLTAGE_NUM 0x100 +#define PF0900_LDO_VOLTAGE_NUM 0x20 + +#define REGU_SW_CNT 0x5 +#define REGU_LDO_VAON_CNT 0x4 + +enum { + PF0900_REG_DEV_ID = 0x00, + PF0900_REG_DEV_FAM = 0x01, + PF0900_REG_REV_ID = 0x02, + PF0900_REG_PROG_ID1 = 0x03, + PF0900_REG_PROG_ID2 = 0x04, + PF0900_REG_SYSTEM_INT = 0x05, + PF0900_REG_STATUS1_INT = 0x06, + PF0900_REG_STATUS1_MSK = 0x07, + PF0900_REG_STATUS1_SNS = 0x08, + PF0900_REG_STATUS2_INT = 0x09, + PF0900_REG_STATUS2_MSK = 0x0A, + PF0900_REG_STATUS2_SNS = 0x0B, + PF0900_REG_STATUS3_INT = 0x0C, + PF0900_REG_STATUS3_MSK = 0x0D, + PF0900_REG_SW_MODE_INT = 0x0E, + PF0900_REG_SW_MODE_MSK = 0x0F, + PF0900_REG_SW_ILIM_INT = 0x10, + PF0900_REG_SW_ILIM_MSK = 0x11, + PF0900_REG_SW_ILIM_SNS = 0x12, + PF0900_REG_LDO_ILIM_INT = 0x13, + PF0900_REG_LDO_ILIM_MSK = 0x14, + PF0900_REG_LDO_ILIM_SNS = 0x15, + PF0900_REG_SW_UV_INT = 0x16, + PF0900_REG_SW_UV_MSK = 0x17, + PF0900_REG_SW_UV_SNS = 0x18, + PF0900_REG_SW_OV_INT = 0x19, + PF0900_REG_SW_OV_MSK = 0x1A, + PF0900_REG_SW_OV_SNS = 0x1B, + PF0900_REG_LDO_UV_INT = 0x1C, + PF0900_REG_LDO_UV_MSK = 0x1D, + PF0900_REG_LDO_UV_SNS = 0x1E, + PF0900_REG_LDO_OV_INT = 0x1F, + PF0900_REG_LDO_OV_MSK = 0x20, + PF0900_REG_LDO_OV_SNS = 0x21, + PF0900_REG_PWRON_INT = 0x22, + PF0900_REG_IO_INT = 0x24, + PF0900_REG_IO_MSK = 0x25, + PF0900_REG_IO_SNS = 0x26, + PF0900_REG_IOSHORT_SNS = 0x27, + PF0900_REG_ABIST_OV1 = 0x28, + PF0900_REG_ABIST_OV2 = 0x29, + PF0900_REG_ABIST_UV1 = 0x2A, + PF0900_REG_ABIST_UV2 = 0x2B, + PF0900_REG_ABIST_IO = 0x2C, + PF0900_REG_TEST_FLAGS = 0x2D, + PF0900_REG_HFAULT_FLAGS = 0x2E, + PF0900_REG_FAULT_FLAGS = 0x2F, + PF0900_REG_FS0B_CFG = 0x30, + PF0900_REG_FCCU_CFG = 0x31, + PF0900_REG_RSTB_CFG1 = 0x32, + PF0900_REG_SYSTEM_CMD = 0x33, + PF0900_REG_FS0B_CMD = 0x34, + PF0900_REG_SECURE_WR1 = 0x35, + PF0900_REG_SECURE_WR2 = 0x36, + PF0900_REG_VMON_CFG1 = 0x37, + PF0900_REG_SYS_CFG1 = 0x38, + PF0900_REG_GPO_CFG = 0x39, + PF0900_REG_GPO_CTRL = 0x3A, + PF0900_REG_PWRUP_CFG = 0x3B, + PF0900_REG_RSTB_PWRUP = 0x3C, + PF0900_REG_GPIO1_PWRUP = 0x3D, + PF0900_REG_GPIO2_PWRUP = 0x3E, + PF0900_REG_GPIO3_PWRUP = 0x3F, + PF0900_REG_GPIO4_PWRUP = 0x40, + PF0900_REG_VMON1_PWRUP = 0x41, + PF0900_REG_VMON2_PWRUP = 0x42, + PF0900_REG_SW1_PWRUP = 0x43, + PF0900_REG_SW2_PWRUP = 0x44, + PF0900_REG_SW3_PWRUP = 0x45, + PF0900_REG_SW4_PWRUP = 0x46, + PF0900_REG_SW5_PWRUP = 0x47, + PF0900_REG_LDO1_PWRUP = 0x48, + PF0900_REG_LDO2_PWRUP = 0x49, + PF0900_REG_LDO3_PWRUP = 0x4A, + PF0900_REG_VAON_PWRUP = 0x4B, + PF0900_REG_FREQ_CTRL = 0x4C, + PF0900_REG_PWRON_CFG = 0x4D, + PF0900_REG_WD_CTRL1 = 0x4E, + PF0900_REG_WD_CTRL2 = 0x4F, + PF0900_REG_WD_CFG1 = 0x50, + PF0900_REG_WD_CFG2 = 0x51, + PF0900_REG_WD_CNT1 = 0x52, + PF0900_REG_WD_CNT2 = 0x53, + PF0900_REG_FAULT_CFG = 0x54, + PF0900_REG_FAULT_CNT = 0x55, + PF0900_REG_DFS_CNT = 0x56, + PF0900_REG_AMUX_CFG = 0x57, + PF0900_REG_VMON1_RUN_CFG = 0x58, + PF0900_REG_VMON1_STBY_CFG = 0x59, + PF0900_REG_VMON1_CTRL = 0x5A, + PF0900_REG_VMON2_RUN_CFG = 0x5B, + PF0900_REG_VMON2_STBY_CFG = 0x5C, + PF0900_REG_VMON2_CTRL = 0x5D, + PF0900_REG_SW1_VRUN = 0x5E, + PF0900_REG_SW1_VSTBY = 0x5F, + PF0900_REG_SW1_MODE = 0x60, + PF0900_REG_SW1_CFG1 = 0x61, + PF0900_REG_SW1_CFG2 = 0x62, + PF0900_REG_SW2_VRUN = 0x63, + PF0900_REG_SW2_VSTBY = 0x64, + PF0900_REG_SW2_MODE = 0x65, + PF0900_REG_SW2_CFG1 = 0x66, + PF0900_REG_SW2_CFG2 = 0x67, + PF0900_REG_SW3_VRUN = 0x68, + PF0900_REG_SW3_VSTBY = 0x69, + PF0900_REG_SW3_MODE = 0x6A, + PF0900_REG_SW3_CFG1 = 0x6B, + PF0900_REG_SW3_CFG2 = 0x6C, + PF0900_REG_SW4_VRUN = 0x6D, + PF0900_REG_SW4_VSTBY = 0x6E, + PF0900_REG_SW4_MODE = 0x6F, + PF0900_REG_SW4_CFG1 = 0x70, + PF0900_REG_SW4_CFG2 = 0x71, + PF0900_REG_SW5_VRUN = 0x72, + PF0900_REG_SW5_VSTBY = 0x73, + PF0900_REG_SW5_MODE = 0x74, + PF0900_REG_SW5_CFG1 = 0x75, + PF0900_REG_SW5_CFG2 = 0x76, + PF0900_REG_LDO1_RUN = 0x77, + PF0900_REG_LDO1_STBY = 0x78, + PF0900_REG_LDO1_CFG2 = 0x79, + PF0900_REG_LDO2_RUN = 0x7A, + PF0900_REG_LDO2_STBY = 0x7B, + PF0900_REG_LDO2_CFG2 = 0x7C, + PF0900_REG_LDO3_RUN = 0x7D, + PF0900_REG_LDO3_STBY = 0x7E, + PF0900_REG_LDO3_CFG2 = 0x7F, + PF0900_REG_VAON_CFG1 = 0x80, + PF0900_REG_VAON_CFG2 = 0x81, + PF0900_REG_SYS_DIAG = 0x82, + PF0900_MAX_REGISTER, +}; + +/* PF0900 SW MODE */ +#define SW_RUN_MODE_OFF 0x00 +#define SW_RUN_MODE_PWM 0x01 +#define SW_RUN_MODE_PFM 0x02 +#define SW_STBY_MODE_OFF 0x00 +#define SW_STBY_MODE_PWM 0x04 +#define SW_STBY_MODE_PFM 0x08 + +/* PF0900 SW MODE MASK */ +#define SW_RUN_MODE_MASK GENMASK(1, 0) +#define SW_STBY_MODE_MASK GENMASK(3, 2) + +/* PF0900 SW VRUN/VSTBY MASK */ +#define PF0900_SW_VOL_MASK GENMASK(7, 0) + +/* PF0900_REG_VAON_CFG1 bits */ +#define PF0900_VAON_1P8V 0x01 + +#define PF0900_VAON_MASK GENMASK(1, 0) + +/* PF0900_REG_SWX_CFG1 MASK */ +#define PF0900_SW_DVS_MASK GENMASK(4, 3) + +/* PF0900_REG_LDO_RUN MASK */ +#define VLDO_RUN_MASK GENMASK(4, 0) +#define LDO_RUN_EN_MASK BIT(5) + +/* PF0900_REG_STATUS1_INT bits */ +#define PF0900_IRQ_PWRUP BIT(3) + +/* PF0900_REG_ILIM_INT bits */ +#define PF0900_IRQ_SW1_IL BIT(0) +#define PF0900_IRQ_SW2_IL BIT(1) +#define PF0900_IRQ_SW3_IL BIT(2) +#define PF0900_IRQ_SW4_IL BIT(3) +#define PF0900_IRQ_SW5_IL BIT(4) + +#define PF0900_IRQ_LDO1_IL BIT(0) +#define PF0900_IRQ_LDO2_IL BIT(1) +#define PF0900_IRQ_LDO3_IL BIT(2) + +/* PF0900_REG_UV_INT bits */ +#define PF0900_IRQ_SW1_UV BIT(0) +#define PF0900_IRQ_SW2_UV BIT(1) +#define PF0900_IRQ_SW3_UV BIT(2) +#define PF0900_IRQ_SW4_UV BIT(3) +#define PF0900_IRQ_SW5_UV BIT(4) + +#define PF0900_IRQ_LDO1_UV BIT(0) +#define PF0900_IRQ_LDO2_UV BIT(1) +#define PF0900_IRQ_LDO3_UV BIT(2) +#define PF0900_IRQ_VAON_UV BIT(3) + +/* PF0900_REG_OV_INT bits */ +#define PF0900_IRQ_SW1_OV BIT(0) +#define PF0900_IRQ_SW2_OV BIT(1) +#define PF0900_IRQ_SW3_OV BIT(2) +#define PF0900_IRQ_SW4_OV BIT(3) +#define PF0900_IRQ_SW5_OV BIT(4) + +#define PF0900_IRQ_LDO1_OV BIT(0) +#define PF0900_IRQ_LDO2_OV BIT(1) +#define PF0900_IRQ_LDO3_OV BIT(2) +#define PF0900_IRQ_VAON_OV BIT(3) + +struct pf0900_regulator_desc { + struct regulator_desc desc; + unsigned int suspend_enable_mask; + unsigned int suspend_voltage_reg; + unsigned int suspend_voltage_cache; +}; + +struct pf0900_drvdata { + const struct pf0900_regulator_desc *desc; + unsigned int rcnt; +}; + +struct pf0900 { + struct device *dev; + struct regmap *regmap; + const struct pf0900_drvdata *drvdata; + struct regulator_dev *rdevs[PF0900_REGULATOR_CNT]; + int irq; + unsigned short addr; + bool crc_en; +}; + +enum pf0900_regulator_type { + PF0900_SW = 0, + PF0900_LDO, +}; + +#define PF0900_REGU_IRQ(_reg, _type, _event) \ + { \ + .reg = _reg, \ + .type = _type, \ + .event = _event, \ + } + +struct pf0900_regulator_irq { + unsigned int reg; + unsigned int type; + unsigned int event; +}; + +static const struct regmap_range pf0900_range = { + .range_min = PF0900_REG_DEV_ID, + .range_max = PF0900_REG_SYS_DIAG, +}; + +static const struct regmap_access_table pf0900_volatile_regs = { + .yes_ranges = &pf0900_range, + .n_yes_ranges = 1, +}; + +static const struct regmap_config pf0900_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_table = &pf0900_volatile_regs, + .max_register = PF0900_MAX_REGISTER - 1, + .cache_type = REGCACHE_MAPLE, +}; + +static uint8_t crc8_j1850(unsigned short addr, unsigned int reg, + unsigned int val) +{ + uint8_t crcBuf[3]; + uint8_t t_crc; + uint8_t i, j; + + crcBuf[0] = addr; + crcBuf[1] = reg; + crcBuf[2] = val; + t_crc = 0xFF; + + /* + * The CRC calculation is based on the standard CRC-8-SAE as + * defined in the SAE-J1850 specification with the following + * characteristics. + * Polynomial = 0x1D + * Initial Value = 0xFF + * The CRC byte is calculated by shifting 24-bit data through + * the CRC polynomial.The 24-bits package is built as follows: + * DEVICE_ADDR[b8] + REGISTER_ADDR [b8] +DATA[b8] + * The DEVICE_ADDR is calculated as the 7-bit slave address + * shifted left one space plus the corresponding read/write bit. + * (7Bit Address [b7] << 1 ) + R/W = DEVICE_ADDR[b8] + */ + for (i = 0; i < sizeof(crcBuf); i++) { + t_crc ^= crcBuf[i]; + for (j = 0; j < 8; j++) { + if ((t_crc & 0x80) != 0) { + t_crc <<= 1; + t_crc ^= 0x1D; + } else { + t_crc <<= 1; + } + } + } + + return t_crc; +} + +static int pf0900_regmap_read(void *context, unsigned int reg, + unsigned int *val) +{ + struct device *dev = context; + struct i2c_client *i2c = to_i2c_client(dev); + struct pf0900 *pf0900 = dev_get_drvdata(dev); + int ret; + u8 crc; + + if (!pf0900 || !pf0900->dev) + return -EINVAL; + + if (reg >= PF0900_MAX_REGISTER) { + dev_err(pf0900->dev, "Invalid register address: 0x%x\n", reg); + return -EINVAL; + } + + if (pf0900->crc_en) { + ret = i2c_smbus_read_word_data(i2c, reg); + if (ret < 0) { + dev_err(pf0900->dev, "Read error at reg=0x%x: %d\n", reg, ret); + return ret; + } + + *val = (u16)ret; + crc = crc8_j1850(pf0900->addr << 1 | 0x1, reg, FIELD_GET(GENMASK(7, 0), *val)); + if (crc != FIELD_GET(GENMASK(15, 8), *val)) { + dev_err(pf0900->dev, "Crc check error!\n"); + return -EINVAL; + } + *val = FIELD_GET(GENMASK(7, 0), *val); + } else { + ret = i2c_smbus_read_byte_data(i2c, reg); + if (ret < 0) { + dev_err(pf0900->dev, "Read error at reg=0x%x: %d\n", reg, ret); + return ret; + } + *val = ret; + } + + return 0; +} + +static int pf0900_regmap_write(void *context, unsigned int reg, + unsigned int val) +{ + struct device *dev = context; + struct i2c_client *i2c = to_i2c_client(dev); + struct pf0900 *pf0900 = dev_get_drvdata(dev); + uint8_t data[2]; + int ret; + + if (!pf0900 || !pf0900->dev) + return -EINVAL; + + if (reg >= PF0900_MAX_REGISTER) { + dev_err(pf0900->dev, "Invalid register address: 0x%x\n", reg); + return -EINVAL; + } + + data[0] = val; + if (pf0900->crc_en) { + /* Get CRC */ + data[1] = crc8_j1850(pf0900->addr << 1, reg, data[0]); + val = FIELD_PREP(GENMASK(15, 8), data[1]) | data[0]; + ret = i2c_smbus_write_word_data(i2c, reg, val); + } else { + ret = i2c_smbus_write_byte_data(i2c, reg, data[0]); + } + + if (ret) { + dev_err(pf0900->dev, "Write reg=0x%x error!\n", reg); + return ret; + } + + return 0; +} + +static int pf0900_suspend_enable(struct regulator_dev *rdev) +{ + struct pf0900_regulator_desc *rdata = rdev_get_drvdata(rdev); + struct regmap *rmap = rdev_get_regmap(rdev); + + return regmap_update_bits(rmap, rdata->desc.enable_reg, + rdata->suspend_enable_mask, SW_STBY_MODE_PFM); +} + +static int pf0900_suspend_disable(struct regulator_dev *rdev) +{ + struct pf0900_regulator_desc *rdata = rdev_get_drvdata(rdev); + struct regmap *rmap = rdev_get_regmap(rdev); + + return regmap_update_bits(rmap, rdata->desc.enable_reg, + rdata->suspend_enable_mask, SW_STBY_MODE_OFF); +} + +static int pf0900_set_suspend_voltage(struct regulator_dev *rdev, int uV) +{ + struct pf0900_regulator_desc *rdata = rdev_get_drvdata(rdev); + struct regmap *rmap = rdev_get_regmap(rdev); + int ret; + + if (rdata->suspend_voltage_cache == uV) + return 0; + + ret = regulator_map_voltage_iterate(rdev, uV, uV); + if (ret < 0) { + dev_err(rdev_get_dev(rdev), "failed to map %i uV\n", uV); + return ret; + } + + dev_dbg(rdev_get_dev(rdev), "uV: %i, reg: 0x%x, msk: 0x%x, val: 0x%x\n", + uV, rdata->suspend_voltage_reg, rdata->desc.vsel_mask, ret); + ret = regmap_update_bits(rmap, rdata->suspend_voltage_reg, + rdata->desc.vsel_mask, ret); + if (ret < 0) { + dev_err(rdev_get_dev(rdev), "failed to set %i uV\n", uV); + return ret; + } + + rdata->suspend_voltage_cache = uV; + + return 0; +} + +static const struct regmap_bus pf0900_regmap_bus = { + .reg_read = pf0900_regmap_read, + .reg_write = pf0900_regmap_write, +}; + +static const struct regulator_ops pf0900_avon_regulator_ops = { + .list_voltage = regulator_list_voltage_table, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, +}; + +static const struct regulator_ops pf0900_dvs_sw_regulator_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_ramp_delay = regulator_set_ramp_delay_regmap, + .set_suspend_enable = pf0900_suspend_enable, + .set_suspend_disable = pf0900_suspend_disable, + .set_suspend_voltage = pf0900_set_suspend_voltage, +}; + +static const struct regulator_ops pf0900_ldo_regulator_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, +}; + +/* + * SW1/2/3/4/5 + * SW1_DVS[1:0] SW1 DVS ramp rate setting + * 00: 15.6mV/8usec + * 01: 15.6mV/4usec + * 10: 15.6mV/2usec + * 11: 15.6mV/1usec + */ +static const unsigned int pf0900_dvs_sw_ramp_table[] = { + 1950, 3900, 7800, 15600 +}; + +/* VAON 1.8V, 3.0V, or 3.3V */ +static const int pf0900_vaon_voltages[] = { + 0, 1800000, 3000000, 3300000, +}; + +/* + * SW1 0.5V to 3.3V + * 0.5V to 1.35V (6.25mV step) + * 1.8V to 2.5V (125mV step) + * 2.8V to 3.3V (250mV step) + */ +static const struct linear_range pf0900_dvs_sw1_volts[] = { + REGULATOR_LINEAR_RANGE(0, 0x00, 0x08, 0), + REGULATOR_LINEAR_RANGE(500000, 0x09, 0x91, 6250), + REGULATOR_LINEAR_RANGE(0, 0x92, 0x9E, 0), + REGULATOR_LINEAR_RANGE(1500000, 0x9F, 0x9F, 0), + REGULATOR_LINEAR_RANGE(1800000, 0xA0, 0xD8, 12500), + REGULATOR_LINEAR_RANGE(0, 0xD9, 0xDF, 0), + REGULATOR_LINEAR_RANGE(2800000, 0xE0, 0xF4, 25000), + REGULATOR_LINEAR_RANGE(0, 0xF5, 0xFF, 0), +}; + +/* + * SW2/3/4/5 0.3V to 3.3V + * 0.45V to 1.35V (6.25mV step) + * 1.8V to 2.5V (125mV step) + * 2.8V to 3.3V (250mV step) + */ +static const struct linear_range pf0900_dvs_sw2345_volts[] = { + REGULATOR_LINEAR_RANGE(300000, 0x00, 0x00, 0), + REGULATOR_LINEAR_RANGE(450000, 0x01, 0x91, 6250), + REGULATOR_LINEAR_RANGE(0, 0x92, 0x9E, 0), + REGULATOR_LINEAR_RANGE(1500000, 0x9F, 0x9F, 0), + REGULATOR_LINEAR_RANGE(1800000, 0xA0, 0xD8, 12500), + REGULATOR_LINEAR_RANGE(0, 0xD9, 0xDF, 0), + REGULATOR_LINEAR_RANGE(2800000, 0xE0, 0xF4, 25000), + REGULATOR_LINEAR_RANGE(0, 0xF5, 0xFF, 0), +}; + +/* + * LDO1 + * 0.75V to 3.3V + */ +static const struct linear_range pf0900_ldo1_volts[] = { + REGULATOR_LINEAR_RANGE(750000, 0x00, 0x0F, 50000), + REGULATOR_LINEAR_RANGE(1800000, 0x10, 0x1F, 100000), +}; + +/* + * LDO2/3 + * 0.65V to 3.3V (50mV step) + */ +static const struct linear_range pf0900_ldo23_volts[] = { + REGULATOR_LINEAR_RANGE(650000, 0x00, 0x0D, 50000), + REGULATOR_LINEAR_RANGE(1400000, 0x0E, 0x0F, 100000), + REGULATOR_LINEAR_RANGE(1800000, 0x10, 0x1F, 100000), +}; + +static const struct pf0900_regulator_desc pf0900_regulators[] = { + { + .desc = { + .name = "sw1", + .of_match = of_match_ptr("sw1"), + .regulators_node = of_match_ptr("regulators"), + .id = PF0900_SW1, + .ops = &pf0900_dvs_sw_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = PF0900_SW_VOLTAGE_NUM, + .linear_ranges = pf0900_dvs_sw1_volts, + .n_linear_ranges = ARRAY_SIZE(pf0900_dvs_sw1_volts), + .vsel_reg = PF0900_REG_SW1_VRUN, + .vsel_mask = PF0900_SW_VOL_MASK, + .enable_reg = PF0900_REG_SW1_MODE, + .enable_mask = SW_RUN_MODE_MASK, + .enable_val = SW_RUN_MODE_PWM, + .ramp_reg = PF0900_REG_SW1_CFG1, + .ramp_mask = PF0900_SW_DVS_MASK, + .ramp_delay_table = pf0900_dvs_sw_ramp_table, + .n_ramp_values = ARRAY_SIZE(pf0900_dvs_sw_ramp_table), + .owner = THIS_MODULE, + }, + .suspend_enable_mask = SW_STBY_MODE_MASK, + .suspend_voltage_reg = PF0900_REG_SW1_VSTBY, + }, + { + .desc = { + .name = "sw2", + .of_match = of_match_ptr("sw2"), + .regulators_node = of_match_ptr("regulators"), + .id = PF0900_SW2, + .ops = &pf0900_dvs_sw_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = PF0900_SW_VOLTAGE_NUM, + .linear_ranges = pf0900_dvs_sw2345_volts, + .n_linear_ranges = ARRAY_SIZE(pf0900_dvs_sw2345_volts), + .vsel_reg = PF0900_REG_SW2_VRUN, + .vsel_mask = PF0900_SW_VOL_MASK, + .enable_reg = PF0900_REG_SW2_MODE, + .enable_mask = SW_RUN_MODE_MASK, + .enable_val = SW_RUN_MODE_PWM, + .ramp_reg = PF0900_REG_SW2_CFG1, + .ramp_mask = PF0900_SW_DVS_MASK, + .ramp_delay_table = pf0900_dvs_sw_ramp_table, + .n_ramp_values = ARRAY_SIZE(pf0900_dvs_sw_ramp_table), + .owner = THIS_MODULE, + }, + .suspend_enable_mask = SW_STBY_MODE_MASK, + .suspend_voltage_reg = PF0900_REG_SW2_VSTBY, + }, + { + .desc = { + .name = "sw3", + .of_match = of_match_ptr("sw3"), + .regulators_node = of_match_ptr("regulators"), + .id = PF0900_SW3, + .ops = &pf0900_dvs_sw_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = PF0900_SW_VOLTAGE_NUM, + .linear_ranges = pf0900_dvs_sw2345_volts, + .n_linear_ranges = ARRAY_SIZE(pf0900_dvs_sw2345_volts), + .vsel_reg = PF0900_REG_SW3_VRUN, + .vsel_mask = PF0900_SW_VOL_MASK, + .enable_reg = PF0900_REG_SW3_MODE, + .enable_mask = SW_RUN_MODE_MASK, + .enable_val = SW_RUN_MODE_PWM, + .ramp_reg = PF0900_REG_SW3_CFG1, + .ramp_mask = PF0900_SW_DVS_MASK, + .ramp_delay_table = pf0900_dvs_sw_ramp_table, + .n_ramp_values = ARRAY_SIZE(pf0900_dvs_sw_ramp_table), + .owner = THIS_MODULE, + }, + .suspend_enable_mask = SW_STBY_MODE_MASK, + .suspend_voltage_reg = PF0900_REG_SW3_VSTBY, + }, + { + .desc = { + .name = "sw4", + .of_match = of_match_ptr("sw4"), + .regulators_node = of_match_ptr("regulators"), + .id = PF0900_SW4, + .ops = &pf0900_dvs_sw_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = PF0900_SW_VOLTAGE_NUM, + .linear_ranges = pf0900_dvs_sw2345_volts, + .n_linear_ranges = ARRAY_SIZE(pf0900_dvs_sw2345_volts), + .vsel_reg = PF0900_REG_SW4_VRUN, + .vsel_mask = PF0900_SW_VOL_MASK, + .enable_reg = PF0900_REG_SW4_MODE, + .enable_mask = SW_RUN_MODE_MASK, + .enable_val = SW_RUN_MODE_PWM, + .ramp_reg = PF0900_REG_SW4_CFG1, + .ramp_mask = PF0900_SW_DVS_MASK, + .ramp_delay_table = pf0900_dvs_sw_ramp_table, + .n_ramp_values = ARRAY_SIZE(pf0900_dvs_sw_ramp_table), + .owner = THIS_MODULE, + }, + .suspend_enable_mask = SW_STBY_MODE_MASK, + .suspend_voltage_reg = PF0900_REG_SW4_VSTBY, + }, + { + .desc = { + .name = "sw5", + .of_match = of_match_ptr("sw5"), + .regulators_node = of_match_ptr("regulators"), + .id = PF0900_SW5, + .ops = &pf0900_dvs_sw_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = PF0900_SW_VOLTAGE_NUM, + .linear_ranges = pf0900_dvs_sw2345_volts, + .n_linear_ranges = ARRAY_SIZE(pf0900_dvs_sw2345_volts), + .vsel_reg = PF0900_REG_SW5_VRUN, + .vsel_mask = PF0900_SW_VOL_MASK, + .enable_reg = PF0900_REG_SW5_MODE, + .enable_mask = SW_RUN_MODE_MASK, + .enable_val = SW_RUN_MODE_PWM, + .ramp_reg = PF0900_REG_SW5_CFG1, + .ramp_mask = PF0900_SW_DVS_MASK, + .ramp_delay_table = pf0900_dvs_sw_ramp_table, + .n_ramp_values = ARRAY_SIZE(pf0900_dvs_sw_ramp_table), + .owner = THIS_MODULE, + }, + .suspend_enable_mask = SW_STBY_MODE_MASK, + .suspend_voltage_reg = PF0900_REG_SW5_VSTBY, + }, + { + .desc = { + .name = "ldo1", + .of_match = of_match_ptr("ldo1"), + .regulators_node = of_match_ptr("regulators"), + .id = PF0900_LDO1, + .ops = &pf0900_ldo_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = PF0900_LDO_VOLTAGE_NUM, + .linear_ranges = pf0900_ldo1_volts, + .n_linear_ranges = ARRAY_SIZE(pf0900_ldo1_volts), + .vsel_reg = PF0900_REG_LDO1_RUN, + .vsel_mask = VLDO_RUN_MASK, + .enable_reg = PF0900_REG_LDO1_RUN, + .enable_mask = LDO_RUN_EN_MASK, + .owner = THIS_MODULE, + }, + }, + { + .desc = { + .name = "ldo2", + .of_match = of_match_ptr("ldo2"), + .regulators_node = of_match_ptr("regulators"), + .id = PF0900_LDO2, + .ops = &pf0900_ldo_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = PF0900_LDO_VOLTAGE_NUM, + .linear_ranges = pf0900_ldo23_volts, + .n_linear_ranges = ARRAY_SIZE(pf0900_ldo23_volts), + .vsel_reg = PF0900_REG_LDO2_RUN, + .vsel_mask = VLDO_RUN_MASK, + .enable_reg = PF0900_REG_LDO2_RUN, + .enable_mask = LDO_RUN_EN_MASK, + .owner = THIS_MODULE, + }, + }, + { + .desc = { + .name = "ldo3", + .of_match = of_match_ptr("ldo3"), + .regulators_node = of_match_ptr("regulators"), + .id = PF0900_LDO3, + .ops = &pf0900_ldo_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = PF0900_LDO_VOLTAGE_NUM, + .linear_ranges = pf0900_ldo23_volts, + .n_linear_ranges = ARRAY_SIZE(pf0900_ldo23_volts), + .vsel_reg = PF0900_REG_LDO3_RUN, + .vsel_mask = VLDO_RUN_MASK, + .enable_reg = PF0900_REG_LDO3_RUN, + .enable_mask = LDO_RUN_EN_MASK, + .owner = THIS_MODULE, + }, + }, + { + .desc = { + .name = "vaon", + .of_match = of_match_ptr("vaon"), + .regulators_node = of_match_ptr("regulators"), + .id = PF0900_VAON, + .ops = &pf0900_avon_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = PF0900_VAON_VOLTAGE_NUM, + .volt_table = pf0900_vaon_voltages, + .enable_reg = PF0900_REG_VAON_CFG1, + .enable_mask = PF0900_VAON_MASK, + .enable_val = PF0900_VAON_1P8V, + .vsel_reg = PF0900_REG_VAON_CFG1, + .vsel_mask = PF0900_VAON_MASK, + .owner = THIS_MODULE, + }, + }, +}; + +struct pf0900_regulator_irq regu_irqs[] = { + PF0900_REGU_IRQ(PF0900_REG_SW_ILIM_INT, PF0900_SW, REGULATOR_ERROR_OVER_CURRENT_WARN), + PF0900_REGU_IRQ(PF0900_REG_LDO_ILIM_INT, PF0900_LDO, REGULATOR_ERROR_OVER_CURRENT_WARN), + PF0900_REGU_IRQ(PF0900_REG_SW_UV_INT, PF0900_SW, REGULATOR_ERROR_UNDER_VOLTAGE_WARN), + PF0900_REGU_IRQ(PF0900_REG_LDO_UV_INT, PF0900_LDO, REGULATOR_ERROR_UNDER_VOLTAGE_WARN), + PF0900_REGU_IRQ(PF0900_REG_SW_OV_INT, PF0900_SW, REGULATOR_ERROR_OVER_VOLTAGE_WARN), + PF0900_REGU_IRQ(PF0900_REG_LDO_OV_INT, PF0900_LDO, REGULATOR_ERROR_OVER_VOLTAGE_WARN), +}; + +static irqreturn_t pf0900_irq_handler(int irq, void *data) +{ + unsigned int val, regu, i, index; + struct pf0900 *pf0900 = data; + int ret; + + for (i = 0; i < ARRAY_SIZE(regu_irqs); i++) { + ret = regmap_read(pf0900->regmap, regu_irqs[i].reg, &val); + if (ret < 0) { + dev_err(pf0900->dev, "Failed to read %d\n", ret); + return IRQ_NONE; + } + if (val) { + ret = regmap_write_bits(pf0900->regmap, regu_irqs[i].reg, val, val); + if (ret < 0) { + dev_err(pf0900->dev, "Failed to update %d\n", ret); + return IRQ_NONE; + } + + if (regu_irqs[i].type == PF0900_SW) { + for (index = 0; index < REGU_SW_CNT; index++) { + if (val & BIT(index)) { + regu = (enum pf0900_regulators)index; + regulator_notifier_call_chain(pf0900->rdevs[regu], + regu_irqs[i].event, + NULL); + } + } + } else if (regu_irqs[i].type == PF0900_LDO) { + for (index = 0; index < REGU_LDO_VAON_CNT; index++) { + if (val & BIT(index)) { + regu = (enum pf0900_regulators)index + PF0900_LDO1; + regulator_notifier_call_chain(pf0900->rdevs[regu], + regu_irqs[i].event, + NULL); + } + } + } + } + } + + return IRQ_HANDLED; +} + +static int pf0900_i2c_probe(struct i2c_client *i2c) +{ + const struct pf0900_regulator_desc *regulator_desc; + const struct pf0900_drvdata *drvdata = NULL; + struct device_node *np = i2c->dev.of_node; + unsigned int device_id, device_fam, i; + struct regulator_config config = { }; + struct pf0900 *pf0900; + int ret; + + if (!i2c->irq) + return dev_err_probe(&i2c->dev, -EINVAL, "No IRQ configured?\n"); + + pf0900 = devm_kzalloc(&i2c->dev, sizeof(struct pf0900), GFP_KERNEL); + if (!pf0900) + return -ENOMEM; + + drvdata = device_get_match_data(&i2c->dev); + if (!drvdata) + return dev_err_probe(&i2c->dev, -EINVAL, "unable to find driver data\n"); + + regulator_desc = drvdata->desc; + pf0900->drvdata = drvdata; + pf0900->crc_en = of_property_read_bool(np, "nxp,i2c-crc-enable"); + pf0900->irq = i2c->irq; + pf0900->dev = &i2c->dev; + pf0900->addr = i2c->addr; + + dev_set_drvdata(&i2c->dev, pf0900); + + pf0900->regmap = devm_regmap_init(&i2c->dev, &pf0900_regmap_bus, &i2c->dev, + &pf0900_regmap_config); + if (IS_ERR(pf0900->regmap)) + return dev_err_probe(&i2c->dev, PTR_ERR(pf0900->regmap), + "regmap initialization failed\n"); + ret = regmap_read(pf0900->regmap, PF0900_REG_DEV_ID, &device_id); + if (ret) + return dev_err_probe(&i2c->dev, ret, "Read device id error\n"); + + ret = regmap_read(pf0900->regmap, PF0900_REG_DEV_FAM, &device_fam); + if (ret) + return dev_err_probe(&i2c->dev, ret, "Read device fam error\n"); + + /* Check your board and dts for match the right pmic */ + if (device_fam == 0x09 && (device_id & 0x1F) != 0x0) + return dev_err_probe(&i2c->dev, -EINVAL, "Device id(%x) mismatched\n", + device_id >> 4); + + for (i = 0; i < drvdata->rcnt; i++) { + const struct regulator_desc *desc; + const struct pf0900_regulator_desc *r; + + r = ®ulator_desc[i]; + desc = &r->desc; + config.regmap = pf0900->regmap; + config.driver_data = (void *)r; + config.dev = pf0900->dev; + + pf0900->rdevs[i] = devm_regulator_register(pf0900->dev, desc, &config); + if (IS_ERR(pf0900->rdevs[i])) + return dev_err_probe(pf0900->dev, PTR_ERR(pf0900->rdevs[i]), + "Failed to register regulator(%s)\n", desc->name); + } + + ret = devm_request_threaded_irq(pf0900->dev, pf0900->irq, NULL, + pf0900_irq_handler, + (IRQF_TRIGGER_FALLING | IRQF_ONESHOT), + "pf0900-irq", pf0900); + + if (ret != 0) + return dev_err_probe(pf0900->dev, ret, "Failed to request IRQ: %d\n", + pf0900->irq); + /* + * The PWRUP_M is unmasked by default. When the device enter in RUN state, + * it will assert the PWRUP_I interrupt and assert the INTB pin to inform + * the MCU that it has finished the power up sequence properly. + */ + ret = regmap_write_bits(pf0900->regmap, PF0900_REG_STATUS1_INT, PF0900_IRQ_PWRUP, + PF0900_IRQ_PWRUP); + if (ret) + return dev_err_probe(&i2c->dev, ret, "Clean PWRUP_I error\n"); + + /* mask interrupt PWRUP */ + ret = regmap_update_bits(pf0900->regmap, PF0900_REG_STATUS1_MSK, PF0900_IRQ_PWRUP, + PF0900_IRQ_PWRUP); + if (ret) + return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n"); + + ret = regmap_update_bits(pf0900->regmap, PF0900_REG_SW_ILIM_MSK, PF0900_IRQ_SW1_IL | + PF0900_IRQ_SW2_IL | PF0900_IRQ_SW3_IL | PF0900_IRQ_SW4_IL | + PF0900_IRQ_SW5_IL, 0); + if (ret) + return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n"); + + ret = regmap_update_bits(pf0900->regmap, PF0900_REG_SW_UV_MSK, PF0900_IRQ_SW1_UV | + PF0900_IRQ_SW2_UV | PF0900_IRQ_SW3_UV | PF0900_IRQ_SW4_UV | + PF0900_IRQ_SW5_UV, 0); + if (ret) + return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n"); + + ret = regmap_update_bits(pf0900->regmap, PF0900_REG_SW_OV_MSK, PF0900_IRQ_SW1_OV | + PF0900_IRQ_SW2_OV | PF0900_IRQ_SW3_OV | PF0900_IRQ_SW4_OV | + PF0900_IRQ_SW5_OV, 0); + if (ret) + return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n"); + + ret = regmap_update_bits(pf0900->regmap, PF0900_REG_LDO_ILIM_MSK, PF0900_IRQ_LDO1_IL | + PF0900_IRQ_LDO2_IL | PF0900_IRQ_LDO3_IL, 0); + if (ret) + return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n"); + + ret = regmap_update_bits(pf0900->regmap, PF0900_REG_LDO_UV_MSK, PF0900_IRQ_LDO1_UV | + PF0900_IRQ_LDO2_UV | PF0900_IRQ_LDO3_UV | PF0900_IRQ_VAON_UV, 0); + if (ret) + return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n"); + + ret = regmap_update_bits(pf0900->regmap, PF0900_REG_LDO_OV_MSK, PF0900_IRQ_LDO1_OV | + PF0900_IRQ_LDO2_OV | PF0900_IRQ_LDO3_OV | PF0900_IRQ_VAON_OV, 0); + if (ret) + return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n"); + + return 0; +} + +static struct pf0900_drvdata pf0900_drvdata = { + .desc = pf0900_regulators, + .rcnt = ARRAY_SIZE(pf0900_regulators), +}; + +static const struct of_device_id pf0900_of_match[] = { + { .compatible = "nxp,pf0900", .data = &pf0900_drvdata}, + { } +}; + +MODULE_DEVICE_TABLE(of, pf0900_of_match); + +static struct i2c_driver pf0900_i2c_driver = { + .driver = { + .name = "nxp-pf0900", + .of_match_table = pf0900_of_match, + }, + .probe = pf0900_i2c_probe, +}; + +module_i2c_driver(pf0900_i2c_driver); + +MODULE_AUTHOR("Joy Zou "); +MODULE_DESCRIPTION("NXP PF0900 Power Management IC driver"); +MODULE_LICENSE("GPL"); From 692abf80ce8443a4ded8cade25a1acf772436293 Mon Sep 17 00:00:00 2001 From: Waqar Hameed Date: Tue, 5 Aug 2025 11:33:37 +0200 Subject: [PATCH 00054/11391] spi: nxp-fspi: 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 Link: https://patch.msgid.link/pndqzxqkt8u.a.out@axis.com Signed-off-by: Mark Brown --- drivers/spi/spi-nxp-fspi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c index b92bfef47371..848fa9319e36 100644 --- a/drivers/spi/spi-nxp-fspi.c +++ b/drivers/spi/spi-nxp-fspi.c @@ -1284,7 +1284,7 @@ static int nxp_fspi_probe(struct platform_device *pdev) ret = devm_add_action_or_reset(dev, nxp_fspi_cleanup, f); if (ret) - return dev_err_probe(dev, ret, "Failed to register nxp_fspi_cleanup\n"); + return ret; return devm_spi_register_controller(&pdev->dev, ctlr); } From f1ac30a862cc5d53392d59f42b513e79948acb18 Mon Sep 17 00:00:00 2001 From: Darshan R Date: Mon, 28 Jul 2025 12:41:04 +0000 Subject: [PATCH 00055/11391] spi: sunplus: sp7021: Clean up coding style This patch tidies up minor coding style deviations within the Sunplus SP7021 SPI driver, ensuring closer adherence to established kernel coding guidelines. Specifically, it addresses: - Correction of a whitespace inconsistency before a comma in `writel()` calls. - Alignment of function parameter indentation for `struct spi_transfer *xfer` in `sp7021_spi_host_transfer_one()` and `sp7021_spi_target_transfer_one()`. While purely cosmetic, these adjustments contribute to improved code readability and maintainability, making future development and review easier. Signed-off-by: Darshan R. Link: https://patch.msgid.link/20250728124104.6370-1-rathod.darshan.0896@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-sunplus-sp7021.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-sunplus-sp7021.c b/drivers/spi/spi-sunplus-sp7021.c index 7fd4cc6f74c2..256ae07db6be 100644 --- a/drivers/spi/spi-sunplus-sp7021.c +++ b/drivers/spi/spi-sunplus-sp7021.c @@ -103,7 +103,7 @@ static irqreturn_t sp7021_spi_target_irq(int irq, void *dev) data_status = readl(pspim->s_base + SP7021_DATA_RDY_REG); data_status |= SP7021_SLAVE_CLR_INT; - writel(data_status , pspim->s_base + SP7021_DATA_RDY_REG); + writel(data_status, pspim->s_base + SP7021_DATA_RDY_REG); complete(&pspim->target_isr); return IRQ_HANDLED; } @@ -296,7 +296,7 @@ static void sp7021_spi_setup_clk(struct spi_controller *ctlr, struct spi_transfe } static int sp7021_spi_host_transfer_one(struct spi_controller *ctlr, struct spi_device *spi, - struct spi_transfer *xfer) + struct spi_transfer *xfer) { struct sp7021_spi_ctlr *pspim = spi_controller_get_devdata(ctlr); unsigned long timeout = msecs_to_jiffies(1000); @@ -360,7 +360,7 @@ static int sp7021_spi_host_transfer_one(struct spi_controller *ctlr, struct spi_ } static int sp7021_spi_target_transfer_one(struct spi_controller *ctlr, struct spi_device *spi, - struct spi_transfer *xfer) + struct spi_transfer *xfer) { struct sp7021_spi_ctlr *pspim = spi_controller_get_devdata(ctlr); struct device *dev = pspim->dev; From 379f819733f28b5aa1802f3ede442f08b7275f4e Mon Sep 17 00:00:00 2001 From: Manikandan Muralidharan Date: Wed, 30 Jul 2025 15:40:13 +0530 Subject: [PATCH 00056/11391] spi: atmel: simplify MR register update in cs_activate() simplified the MR register configuration by updating only the PCS field using SPI_BFINS() instead of rewriting the entire register. Avoids code duplication. Signed-off-by: Manikandan Muralidharan Link: https://patch.msgid.link/20250730101015.323964-1-manikandan.m@microchip.com Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 89a6b46cd319..409f544d8983 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -397,20 +397,10 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi) * on CS1,2,3 needs SPI_CSR0.BITS config as SPI_CSR1,2,3.BITS */ spi_writel(as, CSR0, asd->csr); - if (as->caps.has_wdrbt) { - spi_writel(as, MR, - SPI_BF(PCS, ~(0x01 << chip_select)) - | SPI_BIT(WDRBT) - | SPI_BIT(MODFDIS) - | SPI_BIT(MSTR)); - } else { - spi_writel(as, MR, - SPI_BF(PCS, ~(0x01 << chip_select)) - | SPI_BIT(MODFDIS) - | SPI_BIT(MSTR)); - } mr = spi_readl(as, MR); + mr = SPI_BFINS(PCS, ~(0x01 << chip_select), mr); + spi_writel(as, MR, mr); /* * Ensures the clock polarity is valid before we actually From a673ebd0a2a587f3d6b923d59d363fc9e8a9f920 Mon Sep 17 00:00:00 2001 From: Manikandan Muralidharan Date: Wed, 30 Jul 2025 15:40:14 +0530 Subject: [PATCH 00057/11391] spi: dt-bindings: atmel,at91rm9200-spi: Add support for optional 'spi_gclk' clock Update the Atmel SPI DT binding to support an optional programmable SPI generic clock 'spi_gclk', in addition to the required 'spi_clk'. Signed-off-by: Manikandan Muralidharan Link: https://patch.msgid.link/20250730101015.323964-2-manikandan.m@microchip.com Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/atmel,at91rm9200-spi.yaml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/atmel,at91rm9200-spi.yaml b/Documentation/devicetree/bindings/spi/atmel,at91rm9200-spi.yaml index d29772994cf5..11885d0cc209 100644 --- a/Documentation/devicetree/bindings/spi/atmel,at91rm9200-spi.yaml +++ b/Documentation/devicetree/bindings/spi/atmel,at91rm9200-spi.yaml @@ -31,11 +31,16 @@ properties: maxItems: 1 clock-names: - contains: - const: spi_clk + items: + - const: spi_clk + - const: spi_gclk + minItems: 1 clocks: - maxItems: 1 + items: + - description: Peripheral Bus clock + - description: Programmable Generic clock + minItems: 1 dmas: items: From 91e5722baaea06c1f1b105e9e3fd6645dbdd938b Mon Sep 17 00:00:00 2001 From: Manikandan Muralidharan Date: Wed, 30 Jul 2025 15:40:15 +0530 Subject: [PATCH 00058/11391] spi: atmel: Add support for handling GCLK as a clock source MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SPI peripheral clock is typically used to derive the serial clock (SPCK) via the FLEX_SPI_CSRx.SCBR field. However, on platforms like the SAM9X7 SoC, where the peripheral clock can reach up to 266 MHz, this may exceed the SCBR limit, causing SPI transfers to fail. This patch adds support for using the SPI Generic Clock (GCLK) as an alternative and more flexible clock source for SPCK generation. The FLEX_SPI_MR.BRSRCCLK bit is updated accordingly to select between the peripheral clock and GCLK. Signed-off-by: Manikandan Muralidharan Link: https://patch.msgid.link/20250730101015.323964-3-manikandan.m@microchip.com Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 64 +++++++++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 409f544d8983..89977bff76d2 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -256,6 +256,7 @@ struct atmel_spi { void __iomem *regs; int irq; struct clk *clk; + struct clk *gclk; struct platform_device *pdev; unsigned long spi_clk; @@ -1480,6 +1481,8 @@ static void atmel_get_caps(struct atmel_spi *as) static void atmel_spi_init(struct atmel_spi *as) { + u32 mr = 0; + spi_writel(as, CR, SPI_BIT(SWRST)); spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */ @@ -1487,12 +1490,17 @@ static void atmel_spi_init(struct atmel_spi *as) if (as->fifo_size) spi_writel(as, CR, SPI_BIT(FIFOEN)); - if (as->caps.has_wdrbt) { - spi_writel(as, MR, SPI_BIT(WDRBT) | SPI_BIT(MODFDIS) - | SPI_BIT(MSTR)); - } else { - spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS)); - } + /* + * If GCLK is selected as the source clock for the bit rate generation + * Enable the BRSRCCLK/FDIV/DIV32 bit + */ + if (as->gclk) + mr |= SPI_BIT(FDIV); + + if (as->caps.has_wdrbt) + mr |= SPI_BIT(WDRBT); + + spi_writel(as, MR, mr | SPI_BIT(MODFDIS) | SPI_BIT(MSTR)); if (as->use_pdc) spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS)); @@ -1555,6 +1563,11 @@ static int atmel_spi_probe(struct platform_device *pdev) as->phybase = regs->start; as->irq = irq; as->clk = clk; + as->gclk = devm_clk_get_optional(&pdev->dev, "spi_gclk"); + if (IS_ERR(as->gclk)) { + ret = PTR_ERR(as->gclk); + goto out_unmap_regs; + } init_completion(&as->xfer_completion); @@ -1615,7 +1628,19 @@ static int atmel_spi_probe(struct platform_device *pdev) if (ret) goto out_free_irq; - as->spi_clk = clk_get_rate(clk); + /* + * In cases where the peripheral clock is higher,the FLEX_SPI_CSRx.SCBR + * exceeds the threshold (SCBR ≤ 255), the GCLK is used as the source clock + * for the SPCK (SPI Serial Clock) bit rate generation + */ + if (as->gclk) { + ret = clk_prepare_enable(as->gclk); + if (ret) + goto out_disable_clk; + as->spi_clk = clk_get_rate(as->gclk); + } else { + as->spi_clk = clk_get_rate(clk); + } as->fifo_size = 0; if (!of_property_read_u32(pdev->dev.of_node, "atmel,fifo-size", @@ -1650,6 +1675,8 @@ static int atmel_spi_probe(struct platform_device *pdev) spi_writel(as, CR, SPI_BIT(SWRST)); spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */ + clk_disable_unprepare(as->gclk); +out_disable_clk: clk_disable_unprepare(clk); out_free_irq: out_unmap_regs: @@ -1685,6 +1712,8 @@ static void atmel_spi_remove(struct platform_device *pdev) spin_unlock_irq(&as->lock); clk_disable_unprepare(as->clk); + if (as->gclk) + clk_disable_unprepare(as->gclk); pm_runtime_put_noidle(&pdev->dev); pm_runtime_disable(&pdev->dev); @@ -1696,6 +1725,8 @@ static int atmel_spi_runtime_suspend(struct device *dev) struct atmel_spi *as = spi_controller_get_devdata(host); clk_disable_unprepare(as->clk); + if (as->gclk) + clk_disable_unprepare(as->gclk); pinctrl_pm_select_sleep_state(dev); return 0; @@ -1705,10 +1736,20 @@ static int atmel_spi_runtime_resume(struct device *dev) { struct spi_controller *host = dev_get_drvdata(dev); struct atmel_spi *as = spi_controller_get_devdata(host); + int ret; pinctrl_pm_select_default_state(dev); - return clk_prepare_enable(as->clk); + ret = clk_prepare_enable(as->clk); + if (ret) + return ret; + if (as->gclk) { + ret = clk_prepare_enable(as->gclk); + if (ret) + return ret; + } + + return 0; } static int atmel_spi_suspend(struct device *dev) @@ -1736,10 +1777,17 @@ static int atmel_spi_resume(struct device *dev) ret = clk_prepare_enable(as->clk); if (ret) return ret; + if (as->gclk) { + ret = clk_prepare_enable(as->gclk); + if (ret) + return ret; + } atmel_spi_init(as); clk_disable_unprepare(as->clk); + if (as->gclk) + clk_disable_unprepare(as->gclk); if (!pm_runtime_suspended(dev)) { ret = atmel_spi_runtime_resume(dev); From a1d0b0ae65ae3f32597edfbb547f16c75601cd87 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 8 Aug 2025 15:15:32 +0200 Subject: [PATCH 00059/11391] spi: spi-qpic-snand: avoid double assignment in qcom_spi_probe() The snandc->dev pointer is being assigned twice in the qcom_spi_probe() function. Remove the second assignment as that uses the same pointer value than the first one. No functional changes. Signed-off-by: Gabor Juhos Link: https://patch.msgid.link/20250808-qpic-snand-double-assign-fix-v2-1-1a3d0ed0d404@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-qpic-snand.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c index 0ceaad7dba3c..5c72d8ed74bb 100644 --- a/drivers/spi/spi-qpic-snand.c +++ b/drivers/spi/spi-qpic-snand.c @@ -1549,7 +1549,6 @@ static int qcom_spi_probe(struct platform_device *pdev) } snandc->props = dev_data; - snandc->dev = &pdev->dev; snandc->core_clk = devm_clk_get(dev, "core"); if (IS_ERR(snandc->core_clk)) From b20d199da7be0602013e88123e9fe1b17f22a4cb Mon Sep 17 00:00:00 2001 From: Willie Thai Date: Thu, 17 Jul 2025 09:52:10 +0000 Subject: [PATCH 00060/11391] ARM: dts: aspeed: nvidia: gb200nvl: Add VCC Supply Add Vcc supply to avoid probing the devices before they have power. Signed-off-by: Deepak Kodihalli Signed-off-by: Ed Tanous Signed-off-by: Willie Thai Link: https://patch.msgid.link/20250717-update-gb200nvl-dts-for-new-hardware-v3-1-f28145c55c98@nvidia.com Signed-off-by: Andrew Jeffery --- .../aspeed/aspeed-bmc-nvidia-gb200nvl-bmc.dts | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-nvidia-gb200nvl-bmc.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-nvidia-gb200nvl-bmc.dts index 41e3e9dd85f5..bd9395a19413 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-nvidia-gb200nvl-bmc.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-nvidia-gb200nvl-bmc.dts @@ -126,6 +126,17 @@ button-uid { gpio = <&sgpiom0 154 GPIO_ACTIVE_LOW>; }; }; + + standby_power_regulator: standby-power-regulator { + status = "okay"; + compatible = "regulator-fixed"; + regulator-name = "standby_power"; + gpio = <&gpio0 ASPEED_GPIO(M, 3) GPIO_ACTIVE_HIGH>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + enable-active-high; + regulator-always-on; + }; }; // Enable Primary flash on FMC for bring up activity @@ -431,6 +442,7 @@ exp4: gpio@21 { #interrupt-cells = <2>; interrupt-parent = <&gpio1>; interrupts = ; + vcc-supply = <&standby_power_regulator>; gpio-line-names = "RTC_MUX_SEL-O", "PCI_MUX_SEL-O", @@ -464,6 +476,7 @@ i2c-mux@71 { #size-cells = <0>; reg = <0x71>; i2c-mux-idle-disconnect; + vdd-supply = <&standby_power_regulator>; imux16: i2c@0 { #address-cells = <1>; @@ -528,6 +541,7 @@ i2c-mux@72 { #size-cells = <0>; reg = <0x72>; i2c-mux-idle-disconnect; + vdd-supply = <&standby_power_regulator>; imux20: i2c@0 { #address-cells = <1>; @@ -545,6 +559,7 @@ gpio@21 { reg = <0x21>; gpio-controller; #gpio-cells = <2>; + vcc-supply = <&standby_power_regulator>; gpio-line-names = "RST_CX_0_L-O", "RST_CX_1_L-O", @@ -584,6 +599,7 @@ i2c-mux@73 { #size-cells = <0>; reg = <0x73>; i2c-mux-idle-disconnect; + vdd-supply = <&standby_power_regulator>; imux24: i2c@0 { #address-cells = <1>; @@ -602,6 +618,7 @@ i2c-mux@70 { #size-cells = <0>; reg = <0x70>; i2c-mux-idle-disconnect; + vdd-supply = <&standby_power_regulator>; i2c25mux0: i2c@0 { #address-cells = <1>; @@ -648,6 +665,7 @@ i2c-mux@75 { #size-cells = <0>; reg = <0x75>; i2c-mux-idle-disconnect; + vdd-supply = <&standby_power_regulator>; imux28: i2c@0 { #address-cells = <1>; @@ -712,6 +730,7 @@ i2c-mux@76 { #size-cells = <0>; reg = <0x76>; i2c-mux-idle-disconnect; + vdd-supply = <&standby_power_regulator>; imux32: i2c@0 { #address-cells = <1>; @@ -729,6 +748,7 @@ gpio@21 { reg = <0x21>; gpio-controller; #gpio-cells = <2>; + vcc-supply = <&standby_power_regulator>; gpio-line-names = "SEC_RST_CX_0_L-O", "SEC_RST_CX_1_L-O", @@ -768,6 +788,7 @@ i2c-mux@77 { #size-cells = <0>; reg = <0x77>; i2c-mux-idle-disconnect; + vdd-supply = <&standby_power_regulator>; imux36: i2c@0 { #address-cells = <1>; @@ -862,6 +883,7 @@ exp0: gpio@20 { #interrupt-cells = <2>; interrupt-parent = <&gpio1>; interrupts = ; + vcc-supply = <&standby_power_regulator>; gpio-line-names = "FPGA_THERM_OVERT_L-I", "FPGA_READY_BMC-I", @@ -891,6 +913,7 @@ exp1: gpio@21 { #interrupt-cells = <2>; interrupt-parent = <&gpio1>; interrupts = ; + vcc-supply = <&standby_power_regulator>; gpio-line-names = "SEC_FPGA_THERM_OVERT_L-I", "SEC_FPGA_READY_BMC-I", @@ -949,6 +972,7 @@ exp3: gpio@74 { #interrupt-cells = <2>; interrupt-parent = <&gpio1>; interrupts = ; + vcc-supply = <&standby_power_regulator>; gpio-line-names = "IOB_PRSNT_L", "IOB_DP_HPD", @@ -1014,6 +1038,7 @@ i2c-mux@77 { #size-cells = <0>; reg = <0x77>; i2c-mux-idle-disconnect; + vdd-supply = <&standby_power_regulator>; e1si2c0: i2c@0 { #address-cells = <1>; @@ -1054,6 +1079,7 @@ i2c-mux@77 { #size-cells = <0>; reg = <0x77>; i2c-mux-idle-disconnect; + vdd-supply = <&standby_power_regulator>; e1si2c4: i2c@0 { #address-cells = <1>; From 63d2e5dd62ab4002be544bbe109d7516a1377d37 Mon Sep 17 00:00:00 2001 From: Willie Thai Date: Thu, 17 Jul 2025 09:52:11 +0000 Subject: [PATCH 00061/11391] ARM: dts: aspeed: nvidia: gb200nvl: Enable i2c3 bus Enable i2c3 bus for telemetry fetching purpose. Signed-off-by: Deepak Kodihalli Signed-off-by: Ed Tanous Signed-off-by: Willie Thai Link: https://patch.msgid.link/20250717-update-gb200nvl-dts-for-new-hardware-v3-2-f28145c55c98@nvidia.com Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-nvidia-gb200nvl-bmc.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-nvidia-gb200nvl-bmc.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-nvidia-gb200nvl-bmc.dts index bd9395a19413..f0a18adc3287 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-nvidia-gb200nvl-bmc.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-nvidia-gb200nvl-bmc.dts @@ -422,7 +422,7 @@ &i2c2 { // I2C4 &i2c3 { - status = "disabled"; + status = "okay"; }; // I2C5 From 2193aed6024c5766375a25f84f267053819090d0 Mon Sep 17 00:00:00 2001 From: Willie Thai Date: Thu, 17 Jul 2025 09:52:12 +0000 Subject: [PATCH 00062/11391] ARM: dts: aspeed: nvidia: gb200nvl: Repurpose the HMC gpio pin Repurpose the HMC reset pin to FPGA reset pin. This change is according to hardware change. Signed-off-by: Deepak Kodihalli Signed-off-by: Ed Tanous Signed-off-by: Willie Thai Link: https://patch.msgid.link/20250717-update-gb200nvl-dts-for-new-hardware-v3-3-f28145c55c98@nvidia.com Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-nvidia-gb200nvl-bmc.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-nvidia-gb200nvl-bmc.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-nvidia-gb200nvl-bmc.dts index f0a18adc3287..dd2a02a6d1d4 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-nvidia-gb200nvl-bmc.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-nvidia-gb200nvl-bmc.dts @@ -1126,7 +1126,7 @@ &gpio0 { /*J0-J7*/ "", "", "", "", "", "", "", "", /*K0-K7*/ "", "", "", "", "", "", "", "", /*L0-L7*/ "", "", "", "", "", "", "", "", - /*M0-M7*/ "PCIE_EP_RST_EN-O", "BMC_FRU_WP-O", "HMC_RESET_L-O", "STBY_POWER_EN-O", + /*M0-M7*/ "PCIE_EP_RST_EN-O", "BMC_FRU_WP-O", "FPGA_RST_L-O", "STBY_POWER_EN-O", "STBY_POWER_PG-I", "PCIE_EP_RST_L-O", "", "", /*N0-N7*/ "", "", "", "", "", "", "", "", /*O0-O7*/ "", "", "", "", "", "", "", "", From 2b4e0d787dcd7fb936b0b2f2d095a5ef3754351d Mon Sep 17 00:00:00 2001 From: Willie Thai Date: Thu, 17 Jul 2025 09:52:13 +0000 Subject: [PATCH 00063/11391] ARM: dts: aspeed: nvidia: gb200nvl: Enable MAC0 for BMC network Upstream-Status: Inappropriate Bad devices Signed-off-by: Deepak Kodihalli Signed-off-by: Ed Tanous Signed-off-by: Willie Thai Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20250717-update-gb200nvl-dts-for-new-hardware-v3-4-f28145c55c98@nvidia.com Signed-off-by: Andrew Jeffery --- .../aspeed/aspeed-bmc-nvidia-gb200nvl-bmc.dts | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-nvidia-gb200nvl-bmc.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-nvidia-gb200nvl-bmc.dts index dd2a02a6d1d4..72dafebc080d 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-nvidia-gb200nvl-bmc.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-nvidia-gb200nvl-bmc.dts @@ -227,6 +227,30 @@ &uart_routing { status = "okay"; }; +&mdio0 { + status = "okay"; + ethphy0: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0>; + }; +}; + +&mdio3 { + status = "okay"; + ethphy3: ethernet-phy@2 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <2>; + }; +}; + +&mac0 { + status = "okay"; + pinctrl-names = "default"; + phy-mode = "rgmii-id"; + phy-handle = <ðphy3>; + pinctrl-0 = <&pinctrl_rgmii1_default>; +}; + &mac2 { status = "okay"; phy-mode = "rmii"; From fc6c8ccfaa142bbfd981ed3afb9ed894d7980dba Mon Sep 17 00:00:00 2001 From: Tao Ren Date: Sun, 27 Jul 2025 22:56:03 -0700 Subject: [PATCH 00064/11391] ARM: dts: aspeed: wedge400: Fix DTB warnings Fix the deprecated spi-gpio properties in wedge400 dts. Signed-off-by: Tao Ren Link: https://patch.msgid.link/20250728055618.61616-2-rentao.bupt@gmail.com Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-wedge400.dts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-wedge400.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-wedge400.dts index 5a8169bbda87..3e4d30f0884d 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-wedge400.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-wedge400.dts @@ -75,9 +75,9 @@ spi_gpio: spi { #size-cells = <0>; cs-gpios = <&gpio ASPEED_GPIO(R, 2) GPIO_ACTIVE_LOW>; - gpio-sck = <&gpio ASPEED_GPIO(R, 3) GPIO_ACTIVE_HIGH>; - gpio-mosi = <&gpio ASPEED_GPIO(R, 4) GPIO_ACTIVE_HIGH>; - gpio-miso = <&gpio ASPEED_GPIO(R, 5) GPIO_ACTIVE_HIGH>; + sck-gpios = <&gpio ASPEED_GPIO(R, 3) GPIO_ACTIVE_HIGH>; + mosi-gpios = <&gpio ASPEED_GPIO(R, 4) GPIO_ACTIVE_HIGH>; + miso-gpios = <&gpio ASPEED_GPIO(R, 5) GPIO_ACTIVE_HIGH>; num-chipselects = <1>; tpm@0 { From 78831e53bb2162809f4ed6d2463bbea947c70b24 Mon Sep 17 00:00:00 2001 From: Tao Ren Date: Sun, 27 Jul 2025 22:56:04 -0700 Subject: [PATCH 00065/11391] ARM: dts: aspeed: fuji: Fix DTB warnings Remove redundant adm1278 properties from fuji dts. Signed-off-by: Tao Ren Link: https://patch.msgid.link/20250728055618.61616-3-rentao.bupt@gmail.com Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-fuji.dts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-fuji.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-fuji.dts index f23c26a3441d..840d19d6b1d4 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-fuji.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-fuji.dts @@ -248,8 +248,6 @@ imux16: i2c@0 { adm1278@10 { compatible = "adi,adm1278"; reg = <0x10>; - #address-cells = <1>; - #size-cells = <0>; shunt-resistor-micro-ohms = <1500>; }; }; @@ -577,8 +575,6 @@ imux67: i2c@3 { adm1278@10 { compatible = "adi,adm1278"; reg = <0x10>; - #address-cells = <1>; - #size-cells = <0>; shunt-resistor-micro-ohms = <250>; }; }; @@ -648,8 +644,6 @@ imux75: i2c@3 { adm1278@10 { compatible = "adi,adm1278"; reg = <0x10>; - #address-cells = <1>; - #size-cells = <0>; shunt-resistor-micro-ohms = <250>; }; }; From dc4717e34f6942628f26dc19c831a8dfecc76c31 Mon Sep 17 00:00:00 2001 From: Tao Ren Date: Sun, 27 Jul 2025 22:56:05 -0700 Subject: [PATCH 00066/11391] ARM: dts: aspeed: Fix DTB warnings in ast2600-facebook-netbmc-common.dtsi Fix deprecated spi-gpio properties in ast2600-facebook-netbmc-common.dtsi. Signed-off-by: Tao Ren Link: https://patch.msgid.link/20250728055618.61616-4-rentao.bupt@gmail.com Signed-off-by: Andrew Jeffery --- .../dts/aspeed/ast2600-facebook-netbmc-common.dtsi | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/aspeed/ast2600-facebook-netbmc-common.dtsi b/arch/arm/boot/dts/aspeed/ast2600-facebook-netbmc-common.dtsi index 00e5887c926f..208cf6567ed4 100644 --- a/arch/arm/boot/dts/aspeed/ast2600-facebook-netbmc-common.dtsi +++ b/arch/arm/boot/dts/aspeed/ast2600-facebook-netbmc-common.dtsi @@ -31,9 +31,13 @@ spi_gpio: spi { #address-cells = <1>; #size-cells = <0>; - gpio-sck = <&gpio0 ASPEED_GPIO(X, 3) GPIO_ACTIVE_HIGH>; - gpio-mosi = <&gpio0 ASPEED_GPIO(X, 4) GPIO_ACTIVE_HIGH>; - gpio-miso = <&gpio0 ASPEED_GPIO(X, 5) GPIO_ACTIVE_HIGH>; + /* + * chipselect pins are defined in platform .dts files + * separately. + */ + sck-gpios = <&gpio0 ASPEED_GPIO(X, 3) GPIO_ACTIVE_HIGH>; + mosi-gpios = <&gpio0 ASPEED_GPIO(X, 4) GPIO_ACTIVE_HIGH>; + miso-gpios = <&gpio0 ASPEED_GPIO(X, 5) GPIO_ACTIVE_HIGH>; tpm@0 { compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; From c11f9190f9d6a08953d5346c016a29c42ddb17dd Mon Sep 17 00:00:00 2001 From: Tao Ren Date: Sun, 27 Jul 2025 22:56:06 -0700 Subject: [PATCH 00067/11391] ARM: dts: aspeed: Move eMMC out of ast2600-facebook-netbmc-common.dtsi Move eMMC entries from ast2600-facebook-netbmc-common.dtsi to each platform because eMMC is removed from future Meta/Facebook AST2600 Network BMC platforms. Signed-off-by: Tao Ren Link: https://patch.msgid.link/20250728055618.61616-5-rentao.bupt@gmail.com Signed-off-by: Andrew Jeffery --- .../boot/dts/aspeed/aspeed-bmc-facebook-elbert.dts | 12 ++++++++++++ .../arm/boot/dts/aspeed/aspeed-bmc-facebook-fuji.dts | 12 ++++++++++++ .../dts/aspeed/ast2600-facebook-netbmc-common.dtsi | 12 ------------ 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-elbert.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-elbert.dts index 74f3c67e0eff..ff1009ea1c49 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-elbert.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-elbert.dts @@ -201,3 +201,15 @@ fixed-link { full-duplex; }; }; + +&emmc_controller { + status = "okay"; +}; + +&emmc { + status = "okay"; + + non-removable; + max-frequency = <25000000>; + bus-width = <4>; +}; diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-fuji.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-fuji.dts index 840d19d6b1d4..d0331980d082 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-fuji.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-fuji.dts @@ -1243,3 +1243,15 @@ &mac3 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_rgmii4_default>; }; + +&emmc_controller { + status = "okay"; +}; + +&emmc { + status = "okay"; + + non-removable; + max-frequency = <25000000>; + bus-width = <4>; +}; diff --git a/arch/arm/boot/dts/aspeed/ast2600-facebook-netbmc-common.dtsi b/arch/arm/boot/dts/aspeed/ast2600-facebook-netbmc-common.dtsi index 208cf6567ed4..0ef225acddfc 100644 --- a/arch/arm/boot/dts/aspeed/ast2600-facebook-netbmc-common.dtsi +++ b/arch/arm/boot/dts/aspeed/ast2600-facebook-netbmc-common.dtsi @@ -156,18 +156,6 @@ &vhub { status = "okay"; }; -&emmc_controller { - status = "okay"; -}; - -&emmc { - status = "okay"; - - non-removable; - max-frequency = <25000000>; - bus-width = <4>; -}; - &rtc { status = "okay"; }; From e1b5c5f54797a61073e564278e7dbefb469c1c50 Mon Sep 17 00:00:00 2001 From: Tao Ren Date: Sun, 27 Jul 2025 22:56:07 -0700 Subject: [PATCH 00068/11391] ARM: dts: aspeed: Add facebook-bmc-flash-layout-128-data64.dtsi Add facebook-bmc-flash-layout-128-data64.dts (with 64MB datastore) to be used by Meta Network BMC platforms. Signed-off-by: Tao Ren Link: https://patch.msgid.link/20250728055618.61616-6-rentao.bupt@gmail.com Signed-off-by: Andrew Jeffery --- .../facebook-bmc-flash-layout-128-data64.dtsi | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 arch/arm/boot/dts/aspeed/facebook-bmc-flash-layout-128-data64.dtsi diff --git a/arch/arm/boot/dts/aspeed/facebook-bmc-flash-layout-128-data64.dtsi b/arch/arm/boot/dts/aspeed/facebook-bmc-flash-layout-128-data64.dtsi new file mode 100644 index 000000000000..efd92232cda2 --- /dev/null +++ b/arch/arm/boot/dts/aspeed/facebook-bmc-flash-layout-128-data64.dtsi @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2020 Facebook Inc. + +partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* + * u-boot partition: 896KB. + */ + u-boot@0 { + reg = <0x0 0xe0000>; + label = "u-boot"; + }; + + /* + * u-boot environment variables: 64KB. + */ + u-boot-env@e0000 { + reg = <0xe0000 0x10000>; + label = "env"; + }; + + /* + * image metadata partition (64KB), used by Facebook internal + * tools. + */ + image-meta@f0000 { + reg = <0xf0000 0x10000>; + label = "meta"; + }; + + /* + * FIT image: 63 MB. + */ + fit@100000 { + reg = <0x100000 0x3f00000>; + label = "fit"; + }; + + /* + * "data0" partition (64MB) is used by Facebook BMC platforms as + * persistent data store. + */ + data0@4000000 { + reg = <0x4000000 0x4000000>; + label = "data0"; + }; + + /* + * Although the master partition can be created by enabling + * MTD_PARTITIONED_MASTER option, below "flash0" partition is + * explicitly created to avoid breaking legacy applications. + */ + flash0@0 { + reg = <0x0 0x8000000>; + label = "flash0"; + }; +}; From 83656699ba3ab61a86b83daf4579cb5598d68c55 Mon Sep 17 00:00:00 2001 From: Tao Ren Date: Sun, 27 Jul 2025 22:56:08 -0700 Subject: [PATCH 00069/11391] dt-bindings: arm: aspeed: add Facebook Wedge400-data64 board Document the new compatibles used on Meta/Facebook Wedge400-data64 board. Signed-off-by: Tao Ren Acked-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250728055618.61616-7-rentao.bupt@gmail.com Signed-off-by: Andrew Jeffery --- Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml index 456dbf7b5ec8..5a01e2f4ce20 100644 --- a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml +++ b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml @@ -46,6 +46,7 @@ properties: - facebook,yamp-bmc - facebook,yosemitev2-bmc - facebook,wedge400-bmc + - facebook,wedge400-data64-bmc - hxt,stardragon4800-rep2-bmc - ibm,mihawk-bmc - ibm,mowgli-bmc From 2baf3b61f05cedd470b460a3b6fd1bcabd02be51 Mon Sep 17 00:00:00 2001 From: Tao Ren Date: Sun, 27 Jul 2025 22:56:09 -0700 Subject: [PATCH 00070/11391] ARM: dts: aspeed: Add Facebook Wedge400-data64 (AST2500) BMC Add wedge400-data64.dts to extend wedge400's data0 partition from 8MB to 64MB smoothly. wedge400-data64.dts is copied from wedge400.dts with below changes: - updating model/compatible strings. - updating flash0 partition. Signed-off-by: Tao Ren Link: https://patch.msgid.link/20250728055618.61616-8-rentao.bupt@gmail.com Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/Makefile | 1 + .../aspeed-bmc-facebook-wedge400-data64.dts | 375 ++++++++++++++++++ 2 files changed, 376 insertions(+) create mode 100644 arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-wedge400-data64.dts diff --git a/arch/arm/boot/dts/aspeed/Makefile b/arch/arm/boot/dts/aspeed/Makefile index aba7451ab749..0c63297bf13b 100644 --- a/arch/arm/boot/dts/aspeed/Makefile +++ b/arch/arm/boot/dts/aspeed/Makefile @@ -31,6 +31,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \ aspeed-bmc-facebook-tiogapass.dtb \ aspeed-bmc-facebook-wedge40.dtb \ aspeed-bmc-facebook-wedge100.dtb \ + aspeed-bmc-facebook-wedge400-data64.dtb \ aspeed-bmc-facebook-wedge400.dtb \ aspeed-bmc-facebook-yamp.dtb \ aspeed-bmc-facebook-yosemitev2.dtb \ diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-wedge400-data64.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-wedge400-data64.dts new file mode 100644 index 000000000000..1d46eaee8656 --- /dev/null +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-wedge400-data64.dts @@ -0,0 +1,375 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2019 Facebook Inc. +/dts-v1/; + +#include +#include "ast2500-facebook-netbmc-common.dtsi" + +/ { + model = "Facebook Wedge 400 BMC (64MB Datastore)"; + compatible = "facebook,wedge400-data64-bmc", "aspeed,ast2500"; + + aliases { + /* + * PCA9548 (2-0070) provides 8 channels connecting to + * SCM (System Controller Module). + */ + i2c16 = &imux16; + i2c17 = &imux17; + i2c18 = &imux18; + i2c19 = &imux19; + i2c20 = &imux20; + i2c21 = &imux21; + i2c22 = &imux22; + i2c23 = &imux23; + + /* + * PCA9548 (8-0070) provides 8 channels connecting to + * SMB (Switch Main Board). + */ + i2c24 = &imux24; + i2c25 = &imux25; + i2c26 = &imux26; + i2c27 = &imux27; + i2c28 = &imux28; + i2c29 = &imux29; + i2c30 = &imux30; + i2c31 = &imux31; + + /* + * PCA9548 (11-0076) provides 8 channels connecting to + * FCM (Fan Controller Module). + */ + i2c32 = &imux32; + i2c33 = &imux33; + i2c34 = &imux34; + i2c35 = &imux35; + i2c36 = &imux36; + i2c37 = &imux37; + i2c38 = &imux38; + i2c39 = &imux39; + + spi2 = &spi_gpio; + }; + + chosen { + stdout-path = &uart1; + }; + + ast-adc-hwmon { + compatible = "iio-hwmon"; + io-channels = <&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>, <&adc 4>, + <&adc 5>, <&adc 6>, <&adc 7>, <&adc 8>; + }; + + /* + * GPIO-based SPI Master is required to access SPI TPM, because + * full-duplex SPI transactions are not supported by ASPEED SPI + * Controllers. + */ + spi_gpio: spi { + status = "okay"; + compatible = "spi-gpio"; + #address-cells = <1>; + #size-cells = <0>; + + cs-gpios = <&gpio ASPEED_GPIO(R, 2) GPIO_ACTIVE_LOW>; + sck-gpios = <&gpio ASPEED_GPIO(R, 3) GPIO_ACTIVE_HIGH>; + mosi-gpios = <&gpio ASPEED_GPIO(R, 4) GPIO_ACTIVE_HIGH>; + miso-gpios = <&gpio ASPEED_GPIO(R, 5) GPIO_ACTIVE_HIGH>; + num-chipselects = <1>; + + tpm@0 { + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; + spi-max-frequency = <33000000>; + reg = <0>; + }; + }; +}; + +/* + * Both firmware flashes are 128MB on Wedge400 BMC. + */ +&fmc_flash0 { +#include "facebook-bmc-flash-layout-128-data64.dtsi" +}; + +&fmc_flash1 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + flash1@0 { + reg = <0x0 0x8000000>; + label = "flash1"; + }; + }; +}; + +&uart2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd2_default + &pinctrl_rxd2_default>; +}; + +&uart4 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd4_default + &pinctrl_rxd4_default>; +}; + +/* + * I2C bus #0 is multi-master environment dedicated for BMC and Bridge IC + * communication. + */ +&i2c0 { + status = "okay"; + multi-master; + bus-frequency = <1000000>; +}; + +&i2c1 { + status = "okay"; +}; + +&i2c2 { + status = "okay"; + + i2c-mux@70 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x70>; + i2c-mux-idle-disconnect; + + imux16: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + imux17: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + imux18: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + imux19: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + + imux20: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + }; + + imux21: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + }; + + imux22: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + }; + + imux23: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + }; + }; +}; + +&i2c3 { + status = "okay"; +}; + +&i2c4 { + status = "okay"; +}; + +&i2c5 { + status = "okay"; +}; + +&i2c6 { + status = "okay"; +}; + +&i2c7 { + status = "okay"; +}; + +&i2c8 { + status = "okay"; + + i2c-mux@70 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x70>; + i2c-mux-idle-disconnect; + + imux24: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + imux25: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + imux26: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + imux27: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + + imux28: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + }; + + imux29: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + }; + + imux30: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + }; + + imux31: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + }; + + }; +}; + +&i2c9 { + status = "okay"; +}; + +&i2c10 { + status = "okay"; +}; + +&i2c11 { + status = "okay"; + + i2c-mux@76 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x76>; + i2c-mux-idle-disconnect; + + imux32: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + imux33: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + imux34: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + imux35: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + + imux36: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + }; + + imux37: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + }; + + imux38: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + }; + + imux39: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + }; + + }; +}; + +&i2c12 { + status = "okay"; +}; + +&i2c13 { + status = "okay"; +}; + +&adc { + status = "okay"; +}; + +&ehci1 { + status = "okay"; +}; + +&uhci { + status = "okay"; +}; + +&sdhci1 { + max-frequency = <25000000>; + /* + * DMA mode needs to be disabled to avoid conflicts with UHCI + * Controller in AST2500 SoC. + */ + sdhci-caps-mask = <0x0 0x580000>; +}; From fe0e2fbb6a7801883df3567b1e89b834c0969998 Mon Sep 17 00:00:00 2001 From: Tao Ren Date: Sun, 27 Jul 2025 22:56:10 -0700 Subject: [PATCH 00071/11391] ARM: dts: aspeed: wedge400: Include wedge400-data64.dts Include "wedge400-data64.dts" in wedge400 dts to avoid duplicated code. Wedge400-data64 and Wedge400 are identical except the BMC flash layout. Signed-off-by: Tao Ren Link: https://patch.msgid.link/20250728055618.61616-9-rentao.bupt@gmail.com Signed-off-by: Andrew Jeffery --- .../aspeed/aspeed-bmc-facebook-wedge400.dts | 366 +----------------- 1 file changed, 2 insertions(+), 364 deletions(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-wedge400.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-wedge400.dts index 3e4d30f0884d..ef0cfc51cda4 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-wedge400.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-wedge400.dts @@ -1,376 +1,14 @@ // SPDX-License-Identifier: GPL-2.0+ // Copyright (c) 2019 Facebook Inc. -/dts-v1/; -#include -#include "ast2500-facebook-netbmc-common.dtsi" +#include "aspeed-bmc-facebook-wedge400-data64.dts" / { model = "Facebook Wedge 400 BMC"; compatible = "facebook,wedge400-bmc", "aspeed,ast2500"; - - aliases { - /* - * PCA9548 (2-0070) provides 8 channels connecting to - * SCM (System Controller Module). - */ - i2c16 = &imux16; - i2c17 = &imux17; - i2c18 = &imux18; - i2c19 = &imux19; - i2c20 = &imux20; - i2c21 = &imux21; - i2c22 = &imux22; - i2c23 = &imux23; - - /* - * PCA9548 (8-0070) provides 8 channels connecting to - * SMB (Switch Main Board). - */ - i2c24 = &imux24; - i2c25 = &imux25; - i2c26 = &imux26; - i2c27 = &imux27; - i2c28 = &imux28; - i2c29 = &imux29; - i2c30 = &imux30; - i2c31 = &imux31; - - /* - * PCA9548 (11-0076) provides 8 channels connecting to - * FCM (Fan Controller Module). - */ - i2c32 = &imux32; - i2c33 = &imux33; - i2c34 = &imux34; - i2c35 = &imux35; - i2c36 = &imux36; - i2c37 = &imux37; - i2c38 = &imux38; - i2c39 = &imux39; - - spi2 = &spi_gpio; - }; - - chosen { - stdout-path = &uart1; - bootargs = "console=ttyS0,9600n8 root=/dev/ram rw"; - }; - - ast-adc-hwmon { - compatible = "iio-hwmon"; - io-channels = <&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>, <&adc 4>, - <&adc 5>, <&adc 6>, <&adc 7>, <&adc 8>; - }; - - /* - * GPIO-based SPI Master is required to access SPI TPM, because - * full-duplex SPI transactions are not supported by ASPEED SPI - * Controllers. - */ - spi_gpio: spi { - status = "okay"; - compatible = "spi-gpio"; - #address-cells = <1>; - #size-cells = <0>; - - cs-gpios = <&gpio ASPEED_GPIO(R, 2) GPIO_ACTIVE_LOW>; - sck-gpios = <&gpio ASPEED_GPIO(R, 3) GPIO_ACTIVE_HIGH>; - mosi-gpios = <&gpio ASPEED_GPIO(R, 4) GPIO_ACTIVE_HIGH>; - miso-gpios = <&gpio ASPEED_GPIO(R, 5) GPIO_ACTIVE_HIGH>; - num-chipselects = <1>; - - tpm@0 { - compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; - spi-max-frequency = <33000000>; - reg = <0>; - }; - }; }; -/* - * Both firmware flashes are 128MB on Wedge400 BMC. - */ &fmc_flash0 { + /delete-node/partitions; #include "facebook-bmc-flash-layout-128.dtsi" }; - -&fmc_flash1 { - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - flash1@0 { - reg = <0x0 0x8000000>; - label = "flash1"; - }; - }; -}; - -&uart2 { - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_txd2_default - &pinctrl_rxd2_default>; -}; - -&uart4 { - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_txd4_default - &pinctrl_rxd4_default>; -}; - -/* - * I2C bus #0 is multi-master environment dedicated for BMC and Bridge IC - * communication. - */ -&i2c0 { - status = "okay"; - multi-master; - bus-frequency = <1000000>; -}; - -&i2c1 { - status = "okay"; -}; - -&i2c2 { - status = "okay"; - - i2c-mux@70 { - compatible = "nxp,pca9548"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x70>; - i2c-mux-idle-disconnect; - - imux16: i2c@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - }; - - imux17: i2c@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - }; - - imux18: i2c@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - }; - - imux19: i2c@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - }; - - imux20: i2c@4 { - #address-cells = <1>; - #size-cells = <0>; - reg = <4>; - }; - - imux21: i2c@5 { - #address-cells = <1>; - #size-cells = <0>; - reg = <5>; - }; - - imux22: i2c@6 { - #address-cells = <1>; - #size-cells = <0>; - reg = <6>; - }; - - imux23: i2c@7 { - #address-cells = <1>; - #size-cells = <0>; - reg = <7>; - }; - }; -}; - -&i2c3 { - status = "okay"; -}; - -&i2c4 { - status = "okay"; -}; - -&i2c5 { - status = "okay"; -}; - -&i2c6 { - status = "okay"; -}; - -&i2c7 { - status = "okay"; -}; - -&i2c8 { - status = "okay"; - - i2c-mux@70 { - compatible = "nxp,pca9548"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x70>; - i2c-mux-idle-disconnect; - - imux24: i2c@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - }; - - imux25: i2c@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - }; - - imux26: i2c@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - }; - - imux27: i2c@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - }; - - imux28: i2c@4 { - #address-cells = <1>; - #size-cells = <0>; - reg = <4>; - }; - - imux29: i2c@5 { - #address-cells = <1>; - #size-cells = <0>; - reg = <5>; - }; - - imux30: i2c@6 { - #address-cells = <1>; - #size-cells = <0>; - reg = <6>; - }; - - imux31: i2c@7 { - #address-cells = <1>; - #size-cells = <0>; - reg = <7>; - }; - - }; -}; - -&i2c9 { - status = "okay"; -}; - -&i2c10 { - status = "okay"; -}; - -&i2c11 { - status = "okay"; - - i2c-mux@76 { - compatible = "nxp,pca9548"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x76>; - i2c-mux-idle-disconnect; - - imux32: i2c@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - }; - - imux33: i2c@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - }; - - imux34: i2c@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - }; - - imux35: i2c@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - }; - - imux36: i2c@4 { - #address-cells = <1>; - #size-cells = <0>; - reg = <4>; - }; - - imux37: i2c@5 { - #address-cells = <1>; - #size-cells = <0>; - reg = <5>; - }; - - imux38: i2c@6 { - #address-cells = <1>; - #size-cells = <0>; - reg = <6>; - }; - - imux39: i2c@7 { - #address-cells = <1>; - #size-cells = <0>; - reg = <7>; - }; - - }; -}; - -&i2c12 { - status = "okay"; -}; - -&i2c13 { - status = "okay"; -}; - -&adc { - status = "okay"; -}; - -&ehci1 { - status = "okay"; -}; - -&uhci { - status = "okay"; -}; - -&sdhci1 { - max-frequency = <25000000>; - /* - * DMA mode needs to be disabled to avoid conflicts with UHCI - * Controller in AST2500 SoC. - */ - sdhci-caps-mask = <0x0 0x580000>; -}; From 36296b06cd50e790d1769bb1299670b5c83ba3a7 Mon Sep 17 00:00:00 2001 From: Tao Ren Date: Sun, 27 Jul 2025 22:56:11 -0700 Subject: [PATCH 00072/11391] dt-bindings: arm: aspeed: add Facebook Fuji-data64 board Document the new compatibles used on Meta/Facebook Fuji-data64 board. Signed-off-by: Tao Ren Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250728055618.61616-10-rentao.bupt@gmail.com Signed-off-by: Andrew Jeffery --- Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml index 5a01e2f4ce20..e06a2e75e00d 100644 --- a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml +++ b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml @@ -85,6 +85,7 @@ properties: - facebook,cloudripper-bmc - facebook,elbert-bmc - facebook,fuji-bmc + - facebook,fuji-data64-bmc - facebook,greatlakes-bmc - facebook,harma-bmc - facebook,minerva-cmc From 1bc26258369e020d27ef11d1efd7ff82b0a9192f Mon Sep 17 00:00:00 2001 From: Tao Ren Date: Sun, 27 Jul 2025 22:56:12 -0700 Subject: [PATCH 00073/11391] ARM: dts: aspeed: Add Facebook Fuji-data64 (AST2600) Board Introduce fuji-data64.dts to extend Meta/Facebook Fuji BMC's data0 partition without breaking the existing users. Fuji-data64.dts is copied from fuji.dts with below changes: - updating model/compatible strings. - updating FMC flash0' data0 partition to 64MB. - removing mac3. Signed-off-by: Tao Ren Link: https://patch.msgid.link/20250728055618.61616-11-rentao.bupt@gmail.com Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/Makefile | 1 + .../aspeed-bmc-facebook-fuji-data64.dts | 1256 +++++++++++++++++ 2 files changed, 1257 insertions(+) create mode 100644 arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-fuji-data64.dts diff --git a/arch/arm/boot/dts/aspeed/Makefile b/arch/arm/boot/dts/aspeed/Makefile index 0c63297bf13b..5c447533f474 100644 --- a/arch/arm/boot/dts/aspeed/Makefile +++ b/arch/arm/boot/dts/aspeed/Makefile @@ -21,6 +21,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \ aspeed-bmc-facebook-catalina.dtb \ aspeed-bmc-facebook-cmm.dtb \ aspeed-bmc-facebook-elbert.dtb \ + aspeed-bmc-facebook-fuji-data64.dtb \ aspeed-bmc-facebook-fuji.dtb \ aspeed-bmc-facebook-galaxy100.dtb \ aspeed-bmc-facebook-greatlakes.dtb \ diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-fuji-data64.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-fuji-data64.dts new file mode 100644 index 000000000000..aa9576d8ab56 --- /dev/null +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-fuji-data64.dts @@ -0,0 +1,1256 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2020 Facebook Inc. + +/dts-v1/; + +#include +#include "ast2600-facebook-netbmc-common.dtsi" + +/ { + model = "Facebook Fuji BMC (64MB Datastore)"; + compatible = "facebook,fuji-data64-bmc", "aspeed,ast2600"; + + aliases { + /* + * PCA9548 (2-0070) provides 8 channels connecting to + * SCM (System Controller Module). + */ + i2c16 = &imux16; + i2c17 = &imux17; + i2c18 = &imux18; + i2c19 = &imux19; + i2c20 = &imux20; + i2c21 = &imux21; + i2c22 = &imux22; + i2c23 = &imux23; + + /* + * PCA9548 (8-0070) provides 8 channels connecting to + * SMB (Switch Main Board). + */ + i2c24 = &imux24; + i2c25 = &imux25; + i2c26 = &imux26; + i2c27 = &imux27; + i2c28 = &imux28; + i2c29 = &imux29; + i2c30 = &imux30; + i2c31 = &imux31; + + /* + * PCA9548 (11-0077) provides 8 channels connecting to + * SMB (Switch Main Board). + */ + i2c40 = &imux40; + i2c41 = &imux41; + i2c42 = &imux42; + i2c43 = &imux43; + i2c44 = &imux44; + i2c45 = &imux45; + i2c46 = &imux46; + i2c47 = &imux47; + + /* + * PCA9548 (24-0071) provides 8 channels connecting to + * PDB-Left. + */ + i2c48 = &imux48; + i2c49 = &imux49; + i2c50 = &imux50; + i2c51 = &imux51; + i2c52 = &imux52; + i2c53 = &imux53; + i2c54 = &imux54; + i2c55 = &imux55; + + /* + * PCA9548 (25-0072) provides 8 channels connecting to + * PDB-Right. + */ + i2c56 = &imux56; + i2c57 = &imux57; + i2c58 = &imux58; + i2c59 = &imux59; + i2c60 = &imux60; + i2c61 = &imux61; + i2c62 = &imux62; + i2c63 = &imux63; + + /* + * PCA9548 (26-0076) provides 8 channels connecting to + * FCM1. + */ + i2c64 = &imux64; + i2c65 = &imux65; + i2c66 = &imux66; + i2c67 = &imux67; + i2c68 = &imux68; + i2c69 = &imux69; + i2c70 = &imux70; + i2c71 = &imux71; + + /* + * PCA9548 (27-0076) provides 8 channels connecting to + * FCM2. + */ + i2c72 = &imux72; + i2c73 = &imux73; + i2c74 = &imux74; + i2c75 = &imux75; + i2c76 = &imux76; + i2c77 = &imux77; + i2c78 = &imux78; + i2c79 = &imux79; + + /* + * PCA9548 (40-0076) provides 8 channels connecting to + * PIM1. + */ + i2c80 = &imux80; + i2c81 = &imux81; + i2c82 = &imux82; + i2c83 = &imux83; + i2c84 = &imux84; + i2c85 = &imux85; + i2c86 = &imux86; + i2c87 = &imux87; + + /* + * PCA9548 (41-0076) provides 8 channels connecting to + * PIM2. + */ + i2c88 = &imux88; + i2c89 = &imux89; + i2c90 = &imux90; + i2c91 = &imux91; + i2c92 = &imux92; + i2c93 = &imux93; + i2c94 = &imux94; + i2c95 = &imux95; + + /* + * PCA9548 (42-0076) provides 8 channels connecting to + * PIM3. + */ + i2c96 = &imux96; + i2c97 = &imux97; + i2c98 = &imux98; + i2c99 = &imux99; + i2c100 = &imux100; + i2c101 = &imux101; + i2c102 = &imux102; + i2c103 = &imux103; + + /* + * PCA9548 (43-0076) provides 8 channels connecting to + * PIM4. + */ + i2c104 = &imux104; + i2c105 = &imux105; + i2c106 = &imux106; + i2c107 = &imux107; + i2c108 = &imux108; + i2c109 = &imux109; + i2c110 = &imux110; + i2c111 = &imux111; + + /* + * PCA9548 (44-0076) provides 8 channels connecting to + * PIM5. + */ + i2c112 = &imux112; + i2c113 = &imux113; + i2c114 = &imux114; + i2c115 = &imux115; + i2c116 = &imux116; + i2c117 = &imux117; + i2c118 = &imux118; + i2c119 = &imux119; + + /* + * PCA9548 (45-0076) provides 8 channels connecting to + * PIM6. + */ + i2c120 = &imux120; + i2c121 = &imux121; + i2c122 = &imux122; + i2c123 = &imux123; + i2c124 = &imux124; + i2c125 = &imux125; + i2c126 = &imux126; + i2c127 = &imux127; + + /* + * PCA9548 (46-0076) provides 8 channels connecting to + * PIM7. + */ + i2c128 = &imux128; + i2c129 = &imux129; + i2c130 = &imux130; + i2c131 = &imux131; + i2c132 = &imux132; + i2c133 = &imux133; + i2c134 = &imux134; + i2c135 = &imux135; + + /* + * PCA9548 (47-0076) provides 8 channels connecting to + * PIM8. + */ + i2c136 = &imux136; + i2c137 = &imux137; + i2c138 = &imux138; + i2c139 = &imux139; + i2c140 = &imux140; + i2c141 = &imux141; + i2c142 = &imux142; + i2c143 = &imux143; + }; + + spi_gpio: spi { + num-chipselects = <3>; + cs-gpios = <&gpio0 ASPEED_GPIO(X, 0) GPIO_ACTIVE_LOW>, + <0>, /* device reg=<1> does not exist */ + <&gpio0 ASPEED_GPIO(X, 2) GPIO_ACTIVE_HIGH>; + + eeprom@2 { + compatible = "atmel,at93c46d"; + spi-max-frequency = <250000>; + data-size = <16>; + spi-cs-high; + reg = <2>; + }; + }; +}; + +&fmc { + flash@0 { + /delete-node/partitions; +#include "facebook-bmc-flash-layout-128-data64.dtsi" + }; +}; + +&i2c0 { + multi-master; + bus-frequency = <1000000>; +}; + +&i2c2 { + /* + * PCA9548 (2-0070) provides 8 channels connecting to SCM (System + * Controller Module). + */ + i2c-mux@70 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x70>; + i2c-mux-idle-disconnect; + + imux16: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + adm1278@10 { + compatible = "adi,adm1278"; + reg = <0x10>; + shunt-resistor-micro-ohms = <1500>; + }; + }; + + imux17: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + imux18: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + imux19: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + + imux20: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + }; + + imux21: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + }; + + imux22: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + }; + + imux23: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + }; + }; +}; + +&i2c8 { + /* + * PCA9548 (8-0070) provides 8 channels connecting to SMB (Switch + * Main Board). + */ + i2c-mux@70 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x70>; + i2c-mux-idle-disconnect; + + imux24: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + i2c-mux@71 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x71>; + i2c-mux-idle-disconnect; + + imux48: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + imux49: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + imux50: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + + lp5012@14 { + compatible = "ti,lp5012"; + reg = <0x14>; + #address-cells = <1>; + #size-cells = <0>; + + multi-led@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + color = ; + function = LED_FUNCTION_ACTIVITY; + label = "sys"; + + led@0 { + reg = <0>; + color = ; + }; + + led@1 { + reg = <1>; + color = ; + }; + + led@2 { + reg = <2>; + color = ; + }; + }; + + multi-led@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + color = ; + function = LED_FUNCTION_ACTIVITY; + label = "fan"; + + led@0 { + reg = <0>; + color = ; + }; + + led@1 { + reg = <1>; + color = ; + }; + + led@2 { + reg = <2>; + color = ; + }; + }; + + multi-led@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + color = ; + function = LED_FUNCTION_ACTIVITY; + label = "psu"; + + led@0 { + reg = <0>; + color = ; + }; + + led@1 { + reg = <1>; + color = ; + }; + + led@2 { + reg = <2>; + color = ; + }; + }; + + multi-led@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + color = ; + function = LED_FUNCTION_ACTIVITY; + label = "smb"; + + led@0 { + reg = <0>; + color = ; + }; + + led@1 { + reg = <1>; + color = ; + }; + + led@2 { + reg = <2>; + color = ; + }; + }; + }; + }; + + imux51: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + + imux52: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + }; + + imux53: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + }; + + imux54: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + }; + + imux55: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + }; + }; + + }; + + imux25: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + i2c-mux@72 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x72>; + i2c-mux-idle-disconnect; + + imux56: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + imux57: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + imux58: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + imux59: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + + imux60: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + }; + + imux61: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + }; + + imux62: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + }; + + imux63: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + }; + }; + + }; + + imux26: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + + i2c-mux@76 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x76>; + i2c-mux-idle-disconnect; + + imux64: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + imux65: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + imux66: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + imux67: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + + adm1278@10 { + compatible = "adi,adm1278"; + reg = <0x10>; + shunt-resistor-micro-ohms = <250>; + }; + }; + + imux68: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + }; + + imux69: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + }; + + imux70: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + }; + + imux71: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + }; + }; + + }; + + imux27: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + + i2c-mux@76 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x76>; + i2c-mux-idle-disconnect; + + imux72: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + imux73: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + imux74: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + imux75: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + + adm1278@10 { + compatible = "adi,adm1278"; + reg = <0x10>; + shunt-resistor-micro-ohms = <250>; + }; + }; + + imux76: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + }; + + imux77: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + }; + + imux78: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + }; + + imux79: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + }; + }; + + }; + + imux28: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + }; + + imux29: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + }; + + imux30: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + }; + + imux31: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + }; + + }; +}; + +&i2c11 { + status = "okay"; + + /* + * PCA9548 (11-0077) provides 8 channels connecting to SMB (Switch + * Main Board). + */ + i2c-mux@77 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x77>; + i2c-mux-idle-disconnect; + + imux40: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + i2c-mux@76 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x76>; + i2c-mux-idle-disconnect; + + imux80: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + imux81: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + imux82: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + imux83: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + + imux84: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + }; + + imux85: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + }; + + imux86: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + }; + + imux87: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + }; + }; + + }; + + imux41: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + i2c-mux@76 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x76>; + i2c-mux-idle-disconnect; + + imux88: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + imux89: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + imux90: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + imux91: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + + imux92: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + }; + + imux93: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + }; + + imux94: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + }; + + imux95: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + }; + }; + + }; + + imux42: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + + i2c-mux@76 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x76>; + i2c-mux-idle-disconnect; + + imux96: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + imux97: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + imux98: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + imux99: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + + imux100: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + }; + + imux101: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + }; + + imux102: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + }; + + imux103: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + }; + }; + + }; + + imux43: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + + i2c-mux@76 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x76>; + i2c-mux-idle-disconnect; + + imux104: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + imux105: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + imux106: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + imux107: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + + imux108: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + }; + + imux109: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + }; + + imux110: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + }; + + imux111: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + }; + }; + + }; + + imux44: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + + i2c-mux@76 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x76>; + i2c-mux-idle-disconnect; + + imux112: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + imux113: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + imux114: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + imux115: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + + imux116: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + }; + + imux117: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + }; + + imux118: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + }; + + imux119: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + }; + }; + + }; + + imux45: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + + i2c-mux@76 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x76>; + i2c-mux-idle-disconnect; + + imux120: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + imux121: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + imux122: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + imux123: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + + imux124: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + }; + + imux125: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + }; + + imux126: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + }; + + imux127: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + }; + }; + + }; + + imux46: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + + i2c-mux@76 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x76>; + i2c-mux-idle-disconnect; + + imux128: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + imux129: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + imux130: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + imux131: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + + imux132: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + }; + + imux133: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + }; + + imux134: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + }; + + imux135: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + }; + }; + + }; + + imux47: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + + i2c-mux@76 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x76>; + i2c-mux-idle-disconnect; + + imux136: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + imux137: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + imux138: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + imux139: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + + imux140: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + }; + + imux141: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + }; + + imux142: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + }; + + imux143: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + }; + }; + + }; + + }; +}; + +&ehci1 { + status = "okay"; +}; + +&mdio1 { + status = "okay"; + + ethphy3: ethernet-phy@13 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0x0d>; + }; +}; + +&emmc_controller { + status = "okay"; +}; + +&emmc { + status = "okay"; + + non-removable; + max-frequency = <25000000>; + bus-width = <4>; +}; From b0f294fdfc3e472839a9bc0dc91f2322e27e38ef Mon Sep 17 00:00:00 2001 From: Tao Ren Date: Sun, 27 Jul 2025 22:56:13 -0700 Subject: [PATCH 00074/11391] ARM: dts: aspeed: facebook-fuji: Include facebook-fuji-data64.dts Include "facebook-fuji-data64.dts" in facebook-fuji dts to avoid duplicated code. Fuji-data64 and Fuji are identical except the BMC flash layout. Signed-off-by: Tao Ren Link: https://patch.msgid.link/20250728055618.61616-12-rentao.bupt@gmail.com Signed-off-by: Andrew Jeffery --- .../dts/aspeed/aspeed-bmc-facebook-fuji.dts | 1253 +---------------- 1 file changed, 6 insertions(+), 1247 deletions(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-fuji.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-fuji.dts index d0331980d082..5dc2a165e441 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-fuji.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-fuji.dts @@ -1,1257 +1,16 @@ // SPDX-License-Identifier: GPL-2.0+ // Copyright (c) 2020 Facebook Inc. -/dts-v1/; - -#include -#include "ast2600-facebook-netbmc-common.dtsi" +#include "aspeed-bmc-facebook-fuji-data64.dts" / { model = "Facebook Fuji BMC"; compatible = "facebook,fuji-bmc", "aspeed,ast2600"; +}; - aliases { - /* - * PCA9548 (2-0070) provides 8 channels connecting to - * SCM (System Controller Module). - */ - i2c16 = &imux16; - i2c17 = &imux17; - i2c18 = &imux18; - i2c19 = &imux19; - i2c20 = &imux20; - i2c21 = &imux21; - i2c22 = &imux22; - i2c23 = &imux23; - - /* - * PCA9548 (8-0070) provides 8 channels connecting to - * SMB (Switch Main Board). - */ - i2c24 = &imux24; - i2c25 = &imux25; - i2c26 = &imux26; - i2c27 = &imux27; - i2c28 = &imux28; - i2c29 = &imux29; - i2c30 = &imux30; - i2c31 = &imux31; - - /* - * PCA9548 (11-0077) provides 8 channels connecting to - * SMB (Switch Main Board). - */ - i2c40 = &imux40; - i2c41 = &imux41; - i2c42 = &imux42; - i2c43 = &imux43; - i2c44 = &imux44; - i2c45 = &imux45; - i2c46 = &imux46; - i2c47 = &imux47; - - /* - * PCA9548 (24-0071) provides 8 channels connecting to - * PDB-Left. - */ - i2c48 = &imux48; - i2c49 = &imux49; - i2c50 = &imux50; - i2c51 = &imux51; - i2c52 = &imux52; - i2c53 = &imux53; - i2c54 = &imux54; - i2c55 = &imux55; - - /* - * PCA9548 (25-0072) provides 8 channels connecting to - * PDB-Right. - */ - i2c56 = &imux56; - i2c57 = &imux57; - i2c58 = &imux58; - i2c59 = &imux59; - i2c60 = &imux60; - i2c61 = &imux61; - i2c62 = &imux62; - i2c63 = &imux63; - - /* - * PCA9548 (26-0076) provides 8 channels connecting to - * FCM1. - */ - i2c64 = &imux64; - i2c65 = &imux65; - i2c66 = &imux66; - i2c67 = &imux67; - i2c68 = &imux68; - i2c69 = &imux69; - i2c70 = &imux70; - i2c71 = &imux71; - - /* - * PCA9548 (27-0076) provides 8 channels connecting to - * FCM2. - */ - i2c72 = &imux72; - i2c73 = &imux73; - i2c74 = &imux74; - i2c75 = &imux75; - i2c76 = &imux76; - i2c77 = &imux77; - i2c78 = &imux78; - i2c79 = &imux79; - - /* - * PCA9548 (40-0076) provides 8 channels connecting to - * PIM1. - */ - i2c80 = &imux80; - i2c81 = &imux81; - i2c82 = &imux82; - i2c83 = &imux83; - i2c84 = &imux84; - i2c85 = &imux85; - i2c86 = &imux86; - i2c87 = &imux87; - - /* - * PCA9548 (41-0076) provides 8 channels connecting to - * PIM2. - */ - i2c88 = &imux88; - i2c89 = &imux89; - i2c90 = &imux90; - i2c91 = &imux91; - i2c92 = &imux92; - i2c93 = &imux93; - i2c94 = &imux94; - i2c95 = &imux95; - - /* - * PCA9548 (42-0076) provides 8 channels connecting to - * PIM3. - */ - i2c96 = &imux96; - i2c97 = &imux97; - i2c98 = &imux98; - i2c99 = &imux99; - i2c100 = &imux100; - i2c101 = &imux101; - i2c102 = &imux102; - i2c103 = &imux103; - - /* - * PCA9548 (43-0076) provides 8 channels connecting to - * PIM4. - */ - i2c104 = &imux104; - i2c105 = &imux105; - i2c106 = &imux106; - i2c107 = &imux107; - i2c108 = &imux108; - i2c109 = &imux109; - i2c110 = &imux110; - i2c111 = &imux111; - - /* - * PCA9548 (44-0076) provides 8 channels connecting to - * PIM5. - */ - i2c112 = &imux112; - i2c113 = &imux113; - i2c114 = &imux114; - i2c115 = &imux115; - i2c116 = &imux116; - i2c117 = &imux117; - i2c118 = &imux118; - i2c119 = &imux119; - - /* - * PCA9548 (45-0076) provides 8 channels connecting to - * PIM6. - */ - i2c120 = &imux120; - i2c121 = &imux121; - i2c122 = &imux122; - i2c123 = &imux123; - i2c124 = &imux124; - i2c125 = &imux125; - i2c126 = &imux126; - i2c127 = &imux127; - - /* - * PCA9548 (46-0076) provides 8 channels connecting to - * PIM7. - */ - i2c128 = &imux128; - i2c129 = &imux129; - i2c130 = &imux130; - i2c131 = &imux131; - i2c132 = &imux132; - i2c133 = &imux133; - i2c134 = &imux134; - i2c135 = &imux135; - - /* - * PCA9548 (47-0076) provides 8 channels connecting to - * PIM8. - */ - i2c136 = &imux136; - i2c137 = &imux137; - i2c138 = &imux138; - i2c139 = &imux139; - i2c140 = &imux140; - i2c141 = &imux141; - i2c142 = &imux142; - i2c143 = &imux143; - }; - - spi_gpio: spi { - num-chipselects = <3>; - cs-gpios = <&gpio0 ASPEED_GPIO(X, 0) GPIO_ACTIVE_LOW>, - <0>, /* device reg=<1> does not exist */ - <&gpio0 ASPEED_GPIO(X, 2) GPIO_ACTIVE_HIGH>; - - eeprom@2 { - compatible = "atmel,at93c46d"; - spi-max-frequency = <250000>; - data-size = <16>; - spi-cs-high; - reg = <2>; - }; +&fmc { + flash@0 { + /delete-node/partitions; +#include "facebook-bmc-flash-layout-128.dtsi" }; }; - -&i2c0 { - multi-master; - bus-frequency = <1000000>; -}; - -&i2c2 { - /* - * PCA9548 (2-0070) provides 8 channels connecting to SCM (System - * Controller Module). - */ - i2c-mux@70 { - compatible = "nxp,pca9548"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x70>; - i2c-mux-idle-disconnect; - - imux16: i2c@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - - adm1278@10 { - compatible = "adi,adm1278"; - reg = <0x10>; - shunt-resistor-micro-ohms = <1500>; - }; - }; - - imux17: i2c@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - }; - - imux18: i2c@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - }; - - imux19: i2c@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - }; - - imux20: i2c@4 { - #address-cells = <1>; - #size-cells = <0>; - reg = <4>; - }; - - imux21: i2c@5 { - #address-cells = <1>; - #size-cells = <0>; - reg = <5>; - }; - - imux22: i2c@6 { - #address-cells = <1>; - #size-cells = <0>; - reg = <6>; - }; - - imux23: i2c@7 { - #address-cells = <1>; - #size-cells = <0>; - reg = <7>; - }; - }; -}; - -&i2c8 { - /* - * PCA9548 (8-0070) provides 8 channels connecting to SMB (Switch - * Main Board). - */ - i2c-mux@70 { - compatible = "nxp,pca9548"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x70>; - i2c-mux-idle-disconnect; - - imux24: i2c@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - - i2c-mux@71 { - compatible = "nxp,pca9548"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x71>; - i2c-mux-idle-disconnect; - - imux48: i2c@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - }; - - imux49: i2c@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - }; - - imux50: i2c@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - - lp5012@14 { - compatible = "ti,lp5012"; - reg = <0x14>; - #address-cells = <1>; - #size-cells = <0>; - - multi-led@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - color = ; - function = LED_FUNCTION_ACTIVITY; - label = "sys"; - - led@0 { - reg = <0>; - color = ; - }; - - led@1 { - reg = <1>; - color = ; - }; - - led@2 { - reg = <2>; - color = ; - }; - }; - - multi-led@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - color = ; - function = LED_FUNCTION_ACTIVITY; - label = "fan"; - - led@0 { - reg = <0>; - color = ; - }; - - led@1 { - reg = <1>; - color = ; - }; - - led@2 { - reg = <2>; - color = ; - }; - }; - - multi-led@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - color = ; - function = LED_FUNCTION_ACTIVITY; - label = "psu"; - - led@0 { - reg = <0>; - color = ; - }; - - led@1 { - reg = <1>; - color = ; - }; - - led@2 { - reg = <2>; - color = ; - }; - }; - - multi-led@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - color = ; - function = LED_FUNCTION_ACTIVITY; - label = "smb"; - - led@0 { - reg = <0>; - color = ; - }; - - led@1 { - reg = <1>; - color = ; - }; - - led@2 { - reg = <2>; - color = ; - }; - }; - }; - }; - - imux51: i2c@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - }; - - imux52: i2c@4 { - #address-cells = <1>; - #size-cells = <0>; - reg = <4>; - }; - - imux53: i2c@5 { - #address-cells = <1>; - #size-cells = <0>; - reg = <5>; - }; - - imux54: i2c@6 { - #address-cells = <1>; - #size-cells = <0>; - reg = <6>; - }; - - imux55: i2c@7 { - #address-cells = <1>; - #size-cells = <0>; - reg = <7>; - }; - }; - - }; - - imux25: i2c@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - - i2c-mux@72 { - compatible = "nxp,pca9548"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x72>; - i2c-mux-idle-disconnect; - - imux56: i2c@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - }; - - imux57: i2c@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - }; - - imux58: i2c@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - }; - - imux59: i2c@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - }; - - imux60: i2c@4 { - #address-cells = <1>; - #size-cells = <0>; - reg = <4>; - }; - - imux61: i2c@5 { - #address-cells = <1>; - #size-cells = <0>; - reg = <5>; - }; - - imux62: i2c@6 { - #address-cells = <1>; - #size-cells = <0>; - reg = <6>; - }; - - imux63: i2c@7 { - #address-cells = <1>; - #size-cells = <0>; - reg = <7>; - }; - }; - - }; - - imux26: i2c@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - - i2c-mux@76 { - compatible = "nxp,pca9548"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x76>; - i2c-mux-idle-disconnect; - - imux64: i2c@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - }; - - imux65: i2c@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - }; - - imux66: i2c@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - }; - - imux67: i2c@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - - adm1278@10 { - compatible = "adi,adm1278"; - reg = <0x10>; - shunt-resistor-micro-ohms = <250>; - }; - }; - - imux68: i2c@4 { - #address-cells = <1>; - #size-cells = <0>; - reg = <4>; - }; - - imux69: i2c@5 { - #address-cells = <1>; - #size-cells = <0>; - reg = <5>; - }; - - imux70: i2c@6 { - #address-cells = <1>; - #size-cells = <0>; - reg = <6>; - }; - - imux71: i2c@7 { - #address-cells = <1>; - #size-cells = <0>; - reg = <7>; - }; - }; - - }; - - imux27: i2c@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - - i2c-mux@76 { - compatible = "nxp,pca9548"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x76>; - i2c-mux-idle-disconnect; - - imux72: i2c@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - }; - - imux73: i2c@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - }; - - imux74: i2c@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - }; - - imux75: i2c@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - - adm1278@10 { - compatible = "adi,adm1278"; - reg = <0x10>; - shunt-resistor-micro-ohms = <250>; - }; - }; - - imux76: i2c@4 { - #address-cells = <1>; - #size-cells = <0>; - reg = <4>; - }; - - imux77: i2c@5 { - #address-cells = <1>; - #size-cells = <0>; - reg = <5>; - }; - - imux78: i2c@6 { - #address-cells = <1>; - #size-cells = <0>; - reg = <6>; - }; - - imux79: i2c@7 { - #address-cells = <1>; - #size-cells = <0>; - reg = <7>; - }; - }; - - }; - - imux28: i2c@4 { - #address-cells = <1>; - #size-cells = <0>; - reg = <4>; - }; - - imux29: i2c@5 { - #address-cells = <1>; - #size-cells = <0>; - reg = <5>; - }; - - imux30: i2c@6 { - #address-cells = <1>; - #size-cells = <0>; - reg = <6>; - }; - - imux31: i2c@7 { - #address-cells = <1>; - #size-cells = <0>; - reg = <7>; - }; - - }; -}; - -&i2c11 { - status = "okay"; - - /* - * PCA9548 (11-0077) provides 8 channels connecting to SMB (Switch - * Main Board). - */ - i2c-mux@77 { - compatible = "nxp,pca9548"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x77>; - i2c-mux-idle-disconnect; - - imux40: i2c@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - - i2c-mux@76 { - compatible = "nxp,pca9548"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x76>; - i2c-mux-idle-disconnect; - - imux80: i2c@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - }; - - imux81: i2c@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - }; - - imux82: i2c@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - }; - - imux83: i2c@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - }; - - imux84: i2c@4 { - #address-cells = <1>; - #size-cells = <0>; - reg = <4>; - }; - - imux85: i2c@5 { - #address-cells = <1>; - #size-cells = <0>; - reg = <5>; - }; - - imux86: i2c@6 { - #address-cells = <1>; - #size-cells = <0>; - reg = <6>; - }; - - imux87: i2c@7 { - #address-cells = <1>; - #size-cells = <0>; - reg = <7>; - }; - }; - - }; - - imux41: i2c@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - - i2c-mux@76 { - compatible = "nxp,pca9548"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x76>; - i2c-mux-idle-disconnect; - - imux88: i2c@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - }; - - imux89: i2c@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - }; - - imux90: i2c@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - }; - - imux91: i2c@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - }; - - imux92: i2c@4 { - #address-cells = <1>; - #size-cells = <0>; - reg = <4>; - }; - - imux93: i2c@5 { - #address-cells = <1>; - #size-cells = <0>; - reg = <5>; - }; - - imux94: i2c@6 { - #address-cells = <1>; - #size-cells = <0>; - reg = <6>; - }; - - imux95: i2c@7 { - #address-cells = <1>; - #size-cells = <0>; - reg = <7>; - }; - }; - - }; - - imux42: i2c@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - - i2c-mux@76 { - compatible = "nxp,pca9548"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x76>; - i2c-mux-idle-disconnect; - - imux96: i2c@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - }; - - imux97: i2c@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - }; - - imux98: i2c@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - }; - - imux99: i2c@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - }; - - imux100: i2c@4 { - #address-cells = <1>; - #size-cells = <0>; - reg = <4>; - }; - - imux101: i2c@5 { - #address-cells = <1>; - #size-cells = <0>; - reg = <5>; - }; - - imux102: i2c@6 { - #address-cells = <1>; - #size-cells = <0>; - reg = <6>; - }; - - imux103: i2c@7 { - #address-cells = <1>; - #size-cells = <0>; - reg = <7>; - }; - }; - - }; - - imux43: i2c@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - - i2c-mux@76 { - compatible = "nxp,pca9548"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x76>; - i2c-mux-idle-disconnect; - - imux104: i2c@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - }; - - imux105: i2c@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - }; - - imux106: i2c@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - }; - - imux107: i2c@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - }; - - imux108: i2c@4 { - #address-cells = <1>; - #size-cells = <0>; - reg = <4>; - }; - - imux109: i2c@5 { - #address-cells = <1>; - #size-cells = <0>; - reg = <5>; - }; - - imux110: i2c@6 { - #address-cells = <1>; - #size-cells = <0>; - reg = <6>; - }; - - imux111: i2c@7 { - #address-cells = <1>; - #size-cells = <0>; - reg = <7>; - }; - }; - - }; - - imux44: i2c@4 { - #address-cells = <1>; - #size-cells = <0>; - reg = <4>; - - i2c-mux@76 { - compatible = "nxp,pca9548"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x76>; - i2c-mux-idle-disconnect; - - imux112: i2c@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - }; - - imux113: i2c@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - }; - - imux114: i2c@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - }; - - imux115: i2c@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - }; - - imux116: i2c@4 { - #address-cells = <1>; - #size-cells = <0>; - reg = <4>; - }; - - imux117: i2c@5 { - #address-cells = <1>; - #size-cells = <0>; - reg = <5>; - }; - - imux118: i2c@6 { - #address-cells = <1>; - #size-cells = <0>; - reg = <6>; - }; - - imux119: i2c@7 { - #address-cells = <1>; - #size-cells = <0>; - reg = <7>; - }; - }; - - }; - - imux45: i2c@5 { - #address-cells = <1>; - #size-cells = <0>; - reg = <5>; - - i2c-mux@76 { - compatible = "nxp,pca9548"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x76>; - i2c-mux-idle-disconnect; - - imux120: i2c@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - }; - - imux121: i2c@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - }; - - imux122: i2c@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - }; - - imux123: i2c@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - }; - - imux124: i2c@4 { - #address-cells = <1>; - #size-cells = <0>; - reg = <4>; - }; - - imux125: i2c@5 { - #address-cells = <1>; - #size-cells = <0>; - reg = <5>; - }; - - imux126: i2c@6 { - #address-cells = <1>; - #size-cells = <0>; - reg = <6>; - }; - - imux127: i2c@7 { - #address-cells = <1>; - #size-cells = <0>; - reg = <7>; - }; - }; - - }; - - imux46: i2c@6 { - #address-cells = <1>; - #size-cells = <0>; - reg = <6>; - - i2c-mux@76 { - compatible = "nxp,pca9548"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x76>; - i2c-mux-idle-disconnect; - - imux128: i2c@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - }; - - imux129: i2c@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - }; - - imux130: i2c@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - }; - - imux131: i2c@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - }; - - imux132: i2c@4 { - #address-cells = <1>; - #size-cells = <0>; - reg = <4>; - }; - - imux133: i2c@5 { - #address-cells = <1>; - #size-cells = <0>; - reg = <5>; - }; - - imux134: i2c@6 { - #address-cells = <1>; - #size-cells = <0>; - reg = <6>; - }; - - imux135: i2c@7 { - #address-cells = <1>; - #size-cells = <0>; - reg = <7>; - }; - }; - - }; - - imux47: i2c@7 { - #address-cells = <1>; - #size-cells = <0>; - reg = <7>; - - i2c-mux@76 { - compatible = "nxp,pca9548"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x76>; - i2c-mux-idle-disconnect; - - imux136: i2c@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - }; - - imux137: i2c@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - }; - - imux138: i2c@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - }; - - imux139: i2c@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - }; - - imux140: i2c@4 { - #address-cells = <1>; - #size-cells = <0>; - reg = <4>; - }; - - imux141: i2c@5 { - #address-cells = <1>; - #size-cells = <0>; - reg = <5>; - }; - - imux142: i2c@6 { - #address-cells = <1>; - #size-cells = <0>; - reg = <6>; - }; - - imux143: i2c@7 { - #address-cells = <1>; - #size-cells = <0>; - reg = <7>; - }; - }; - - }; - - }; -}; - -&ehci1 { - status = "okay"; -}; - -&mdio1 { - status = "okay"; - - ethphy3: ethernet-phy@13 { - compatible = "ethernet-phy-ieee802.3-c22"; - reg = <0x0d>; - }; -}; - -&mac3 { - status = "okay"; - phy-mode = "rgmii"; - phy-handle = <ðphy3>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_rgmii4_default>; -}; - -&emmc_controller { - status = "okay"; -}; - -&emmc { - status = "okay"; - - non-removable; - max-frequency = <25000000>; - bus-width = <4>; -}; From 0ae11080995f30cfb8362d5680e361da04fa6f79 Mon Sep 17 00:00:00 2001 From: Tao Ren Date: Sun, 27 Jul 2025 22:56:14 -0700 Subject: [PATCH 00075/11391] dt-bindings: arm: aspeed: add Facebook Darwin board Document the new compatibles used on Meta/Facebook Darwin board. Signed-off-by: Tao Ren Acked-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250728055618.61616-13-rentao.bupt@gmail.com Signed-off-by: Andrew Jeffery --- Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml index e06a2e75e00d..b3c9d3310d57 100644 --- a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml +++ b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml @@ -83,6 +83,7 @@ properties: - facebook,bletchley-bmc - facebook,catalina-bmc - facebook,cloudripper-bmc + - facebook,darwin-bmc - facebook,elbert-bmc - facebook,fuji-bmc - facebook,fuji-data64-bmc From 88950abacd5b9b8215125609dcf9449d8031417a Mon Sep 17 00:00:00 2001 From: Tao Ren Date: Sun, 27 Jul 2025 22:56:15 -0700 Subject: [PATCH 00076/11391] ARM: dts: aspeed: Add Facebook Darwin (AST2600) BMC Add initial device tree for the Meta (Facebook) Darwin AST2600 BMC. Darwin is Meta's rack switch platform with an AST2600 BMC integrated for health monitoring purpose. Signed-off-by: Tao Ren Link: https://patch.msgid.link/20250728055618.61616-14-rentao.bupt@gmail.com Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/Makefile | 1 + .../dts/aspeed/aspeed-bmc-facebook-darwin.dts | 72 +++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-darwin.dts diff --git a/arch/arm/boot/dts/aspeed/Makefile b/arch/arm/boot/dts/aspeed/Makefile index 5c447533f474..8062c685f7e8 100644 --- a/arch/arm/boot/dts/aspeed/Makefile +++ b/arch/arm/boot/dts/aspeed/Makefile @@ -20,6 +20,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \ aspeed-bmc-facebook-bletchley.dtb \ aspeed-bmc-facebook-catalina.dtb \ aspeed-bmc-facebook-cmm.dtb \ + aspeed-bmc-facebook-darwin.dtb \ aspeed-bmc-facebook-elbert.dtb \ aspeed-bmc-facebook-fuji-data64.dtb \ aspeed-bmc-facebook-fuji.dtb \ diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-darwin.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-darwin.dts new file mode 100644 index 000000000000..58c107a1b6cf --- /dev/null +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-darwin.dts @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2021 Facebook Inc. + +/dts-v1/; + +#include "ast2600-facebook-netbmc-common.dtsi" + +/ { + model = "Facebook Darwin BMC"; + compatible = "facebook,darwin-bmc", "aspeed,ast2600"; + + aliases { + serial0 = &uart5; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; + }; + + chosen { + stdout-path = &uart5; + }; + + iio-hwmon { + compatible = "iio-hwmon"; + io-channels = <&adc0 0>, <&adc0 1>, <&adc0 2>, <&adc0 3>, + <&adc0 4>, <&adc0 5>, <&adc0 6>, <&adc0 7>, + <&adc1 0>, <&adc1 1>, <&adc1 2>, <&adc1 3>, + <&adc1 4>, <&adc1 5>, <&adc1 6>, <&adc1 7>; + }; + + spi_gpio: spi { + num-chipselects = <1>; + cs-gpios = <&gpio0 ASPEED_GPIO(X, 0) GPIO_ACTIVE_LOW>; + }; +}; + +&i2c0 { + eeprom@50 { + compatible = "atmel,24c512"; + reg = <0x50>; + }; +}; + +&adc0 { + status = "okay"; + + pinctrl-0 = <&pinctrl_adc0_default &pinctrl_adc1_default + &pinctrl_adc2_default &pinctrl_adc3_default + &pinctrl_adc4_default &pinctrl_adc5_default + &pinctrl_adc6_default &pinctrl_adc7_default>; +}; + +&adc1 { + status = "okay"; + + pinctrl-0 = <&pinctrl_adc8_default &pinctrl_adc9_default + &pinctrl_adc10_default &pinctrl_adc11_default + &pinctrl_adc12_default &pinctrl_adc13_default + &pinctrl_adc14_default &pinctrl_adc15_default>; +}; + +&emmc_controller { + status = "okay"; +}; + +&emmc { + status = "okay"; + + non-removable; + max-frequency = <25000000>; + bus-width = <4>; +}; From 3ca621af06072aeffbaf845a407e5ff6e22c79b4 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Thu, 31 Jul 2025 17:12:18 -0500 Subject: [PATCH 00077/11391] ARM: dts: aspeed: Drop "no-gpio-delays" The "no-gpios-delays" property only applies to the "fsi-master-gpio" binding and not the "aspeed,ast2[45]00-cf-fsi-master" binding. It doesn't really make sense either as the timing is controlled by the offloaded firmware. Signed-off-by: Rob Herring (Arm) Acked-by: Eddie James Link: https://patch.msgid.link/20250731-dt-fsi-cleanups-v1-1-e7b695a29fc3@kernel.org Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-inspur-fp5280g2.dts | 1 - arch/arm/boot/dts/aspeed/aspeed-bmc-opp-nicole.dts | 1 - arch/arm/boot/dts/aspeed/aspeed-bmc-opp-romulus.dts | 1 - 3 files changed, 3 deletions(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-inspur-fp5280g2.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-inspur-fp5280g2.dts index 78a5656ef75d..f42254ba6aeb 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-inspur-fp5280g2.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-inspur-fp5280g2.dts @@ -57,7 +57,6 @@ fsi: gpio-fsi { compatible = "aspeed,ast2500-cf-fsi-master", "fsi-master"; #address-cells = <2>; #size-cells = <0>; - no-gpio-delays; memory-region = <&coldfire_memory>; aspeed,sram = <&sram>; diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-nicole.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-nicole.dts index 1a7c61750d0d..0a67790f5ad0 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-nicole.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-nicole.dts @@ -80,7 +80,6 @@ fsi: gpio-fsi { compatible = "aspeed,ast2500-cf-fsi-master", "fsi-master"; #address-cells = <2>; #size-cells = <0>; - no-gpio-delays; memory-region = <&coldfire_memory>; aspeed,sram = <&sram>; diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-romulus.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-romulus.dts index e6b383f6e977..96b2930017c5 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-romulus.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-romulus.dts @@ -71,7 +71,6 @@ fsi: gpio-fsi { compatible = "aspeed,ast2500-cf-fsi-master", "fsi-master"; #address-cells = <2>; #size-cells = <0>; - no-gpio-delays; memory-region = <&coldfire_memory>; aspeed,sram = <&sram>; From b1ccd095b8ac4c843cf6bf15d9f6aadd8ae1195d Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Thu, 31 Jul 2025 17:12:19 -0500 Subject: [PATCH 00078/11391] ARM: dts: aspeed: Drop "fsi-master" compatibles The "fsi-master" compatible has been used inconsistently on FSI masters. It doesn't have any real use or meaning, so it's easier to drop it everywhere than add it where missing. It is also not documented by any schemas (only .txt bindings). Signed-off-by: Rob Herring (Arm) Acked-by: Eddie James Link: https://patch.msgid.link/20250731-dt-fsi-cleanups-v1-2-e7b695a29fc3@kernel.org [arj: Drop hunk affecting removed swift platform] Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-inspur-fp5280g2.dts | 2 +- arch/arm/boot/dts/aspeed/aspeed-bmc-opp-lanyang.dts | 2 +- arch/arm/boot/dts/aspeed/aspeed-bmc-opp-mowgli.dts | 2 +- arch/arm/boot/dts/aspeed/aspeed-bmc-opp-nicole.dts | 2 +- arch/arm/boot/dts/aspeed/aspeed-bmc-opp-palmetto.dts | 2 +- arch/arm/boot/dts/aspeed/aspeed-bmc-opp-romulus.dts | 2 +- arch/arm/boot/dts/aspeed/aspeed-bmc-opp-witherspoon.dts | 2 +- arch/arm/boot/dts/aspeed/aspeed-bmc-opp-zaius.dts | 2 +- arch/arm/boot/dts/aspeed/aspeed-g6.dtsi | 4 ++-- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-inspur-fp5280g2.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-inspur-fp5280g2.dts index f42254ba6aeb..79c6919b3570 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-inspur-fp5280g2.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-inspur-fp5280g2.dts @@ -54,7 +54,7 @@ video_engine_memory: jpegbuffer { }; fsi: gpio-fsi { - compatible = "aspeed,ast2500-cf-fsi-master", "fsi-master"; + compatible = "aspeed,ast2500-cf-fsi-master"; #address-cells = <2>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-lanyang.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-lanyang.dts index 65b2208f5a90..9f2ad551255d 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-lanyang.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-lanyang.dts @@ -63,7 +63,7 @@ sys_err { }; fsi: gpio-fsi { - compatible = "fsi-master-gpio", "fsi-master"; + compatible = "fsi-master-gpio"; #address-cells = <2>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-mowgli.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-mowgli.dts index 31ff19ef87a0..6c8b966ffccc 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-mowgli.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-mowgli.dts @@ -165,7 +165,7 @@ fan4 { }; fsi: gpio-fsi { - compatible = "fsi-master-gpio", "fsi-master"; + compatible = "fsi-master-gpio"; #address-cells = <2>; #size-cells = <0>; no-gpio-delays; diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-nicole.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-nicole.dts index 0a67790f5ad0..ce6d30ddf07c 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-nicole.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-nicole.dts @@ -77,7 +77,7 @@ attention { }; fsi: gpio-fsi { - compatible = "aspeed,ast2500-cf-fsi-master", "fsi-master"; + compatible = "aspeed,ast2500-cf-fsi-master"; #address-cells = <2>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-palmetto.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-palmetto.dts index 123da82c04d5..a1d3e046d4a2 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-palmetto.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-palmetto.dts @@ -55,7 +55,7 @@ identify { }; fsi: gpio-fsi { - compatible = "aspeed,ast2400-cf-fsi-master", "fsi-master"; + compatible = "aspeed,ast2400-cf-fsi-master"; #address-cells = <2>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-romulus.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-romulus.dts index 96b2930017c5..a0263d969e51 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-romulus.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-romulus.dts @@ -68,7 +68,7 @@ power { }; fsi: gpio-fsi { - compatible = "aspeed,ast2500-cf-fsi-master", "fsi-master"; + compatible = "aspeed,ast2500-cf-fsi-master"; #address-cells = <2>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-witherspoon.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-witherspoon.dts index 8b1e82c8cdfe..89907b628b65 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-witherspoon.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-witherspoon.dts @@ -173,7 +173,7 @@ power-button { }; fsi: gpio-fsi { - compatible = "fsi-master-gpio", "fsi-master"; + compatible = "fsi-master-gpio"; #address-cells = <2>; #size-cells = <0>; no-gpio-delays; diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-zaius.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-zaius.dts index 6ac7b0aa6e54..627c91f178e6 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-zaius.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-zaius.dts @@ -96,7 +96,7 @@ hdd_fault { }; fsi: gpio-fsi { - compatible = "fsi-master-gpio", "fsi-master"; + compatible = "fsi-master-gpio"; #address-cells = <2>; #size-cells = <0>; no-gpio-delays; diff --git a/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi index 8ed715bd53aa..acdb6ae74b27 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi +++ b/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi @@ -847,7 +847,7 @@ i2c: bus@1e78a000 { fsim0: fsi@1e79b000 { #interrupt-cells = <1>; - compatible = "aspeed,ast2600-fsi-master", "fsi-master"; + compatible = "aspeed,ast2600-fsi-master"; reg = <0x1e79b000 0x94>; interrupts = ; pinctrl-names = "default"; @@ -859,7 +859,7 @@ fsim0: fsi@1e79b000 { fsim1: fsi@1e79b100 { #interrupt-cells = <1>; - compatible = "aspeed,ast2600-fsi-master", "fsi-master"; + compatible = "aspeed,ast2600-fsi-master"; reg = <0x1e79b100 0x94>; interrupts = ; pinctrl-names = "default"; From 608e2990e67c0e367cc87a86301f2e57b9fffc7e Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Thu, 31 Jul 2025 17:12:20 -0500 Subject: [PATCH 00079/11391] ARM: dts: aspeed: Add missing "ibm,spi-fsi" compatibles The "ibm,spi-fsi" compatible is missing or incorrect in various nodes. The incorrect cases used the "ibm,fsi2spi" compatible by mistake which is the parent node of the actual SPI controller nodes. Signed-off-by: Rob Herring (Arm) Acked-by: Eddie James Link: https://patch.msgid.link/20250731-dt-fsi-cleanups-v1-3-e7b695a29fc3@kernel.org Signed-off-by: Andrew Jeffery --- .../dts/aspeed/aspeed-bmc-ibm-everest.dts | 24 ++++++++++++------- .../arm/boot/dts/aspeed/ibm-power10-dual.dtsi | 12 ++++++---- .../arm/boot/dts/aspeed/ibm-power10-quad.dtsi | 12 ++++++---- 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-ibm-everest.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-ibm-everest.dts index 4d9e2cd11f44..9f144f527f03 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-ibm-everest.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-ibm-everest.dts @@ -2808,6 +2808,7 @@ fsi2spi@1c00 { #size-cells = <0>; cfam4_spi0: spi@0 { + compatible = "ibm,spi-fsi"; reg = <0x0>; #address-cells = <1>; #size-cells = <0>; @@ -2824,6 +2825,7 @@ eeprom@0 { }; cfam4_spi1: spi@20 { + compatible = "ibm,spi-fsi"; reg = <0x20>; #address-cells = <1>; #size-cells = <0>; @@ -2840,8 +2842,8 @@ eeprom@0 { }; cfam4_spi2: spi@40 { + compatible = "ibm,spi-fsi"; reg = <0x40>; - compatible = "ibm,fsi2spi"; #address-cells = <1>; #size-cells = <0>; @@ -2857,8 +2859,8 @@ eeprom@0 { }; cfam4_spi3: spi@60 { + compatible = "ibm,spi-fsi"; reg = <0x60>; - compatible = "ibm,fsi2spi"; #address-cells = <1>; #size-cells = <0>; @@ -3181,6 +3183,7 @@ fsi2spi@1c00 { #size-cells = <0>; cfam5_spi0: spi@0 { + compatible = "ibm,spi-fsi"; reg = <0x0>; #address-cells = <1>; #size-cells = <0>; @@ -3197,6 +3200,7 @@ eeprom@0 { }; cfam5_spi1: spi@20 { + compatible = "ibm,spi-fsi"; reg = <0x20>; #address-cells = <1>; #size-cells = <0>; @@ -3213,8 +3217,8 @@ eeprom@0 { }; cfam5_spi2: spi@40 { + compatible = "ibm,spi-fsi"; reg = <0x40>; - compatible = "ibm,fsi2spi"; #address-cells = <1>; #size-cells = <0>; @@ -3230,8 +3234,8 @@ eeprom@0 { }; cfam5_spi3: spi@60 { + compatible = "ibm,spi-fsi"; reg = <0x60>; - compatible = "ibm,fsi2spi"; #address-cells = <1>; #size-cells = <0>; @@ -3554,6 +3558,7 @@ fsi2spi@1c00 { #size-cells = <0>; cfam6_spi0: spi@0 { + compatible = "ibm,spi-fsi"; reg = <0x0>; #address-cells = <1>; #size-cells = <0>; @@ -3570,6 +3575,7 @@ eeprom@0 { }; cfam6_spi1: spi@20 { + compatible = "ibm,spi-fsi"; reg = <0x20>; #address-cells = <1>; #size-cells = <0>; @@ -3586,8 +3592,8 @@ eeprom@0 { }; cfam6_spi2: spi@40 { + compatible = "ibm,spi-fsi"; reg = <0x40>; - compatible = "ibm,fsi2spi"; #address-cells = <1>; #size-cells = <0>; @@ -3603,8 +3609,8 @@ eeprom@0 { }; cfam6_spi3: spi@60 { + compatible = "ibm,spi-fsi"; reg = <0x60>; - compatible = "ibm,fsi2spi"; #address-cells = <1>; #size-cells = <0>; @@ -3927,6 +3933,7 @@ fsi2spi@1c00 { #size-cells = <0>; cfam7_spi0: spi@0 { + compatible = "ibm,spi-fsi"; reg = <0x0>; #address-cells = <1>; #size-cells = <0>; @@ -3943,6 +3950,7 @@ eeprom@0 { }; cfam7_spi1: spi@20 { + compatible = "ibm,spi-fsi"; reg = <0x20>; #address-cells = <1>; #size-cells = <0>; @@ -3959,8 +3967,8 @@ eeprom@0 { }; cfam7_spi2: spi@40 { + compatible = "ibm,spi-fsi"; reg = <0x40>; - compatible = "ibm,fsi2spi"; #address-cells = <1>; #size-cells = <0>; @@ -3976,8 +3984,8 @@ eeprom@0 { }; cfam7_spi3: spi@60 { + compatible = "ibm,spi-fsi"; reg = <0x60>; - compatible = "ibm,fsi2spi"; #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/aspeed/ibm-power10-dual.dtsi b/arch/arm/boot/dts/aspeed/ibm-power10-dual.dtsi index 07ce3b2bc62a..06fac236773f 100644 --- a/arch/arm/boot/dts/aspeed/ibm-power10-dual.dtsi +++ b/arch/arm/boot/dts/aspeed/ibm-power10-dual.dtsi @@ -82,6 +82,7 @@ fsi2spi@1c00 { #size-cells = <0>; cfam0_spi0: spi@0 { + compatible = "ibm,spi-fsi"; reg = <0x0>; #address-cells = <1>; #size-cells = <0>; @@ -98,6 +99,7 @@ eeprom@0 { }; cfam0_spi1: spi@20 { + compatible = "ibm,spi-fsi"; reg = <0x20>; #address-cells = <1>; #size-cells = <0>; @@ -114,8 +116,8 @@ eeprom@0 { }; cfam0_spi2: spi@40 { + compatible = "ibm,spi-fsi"; reg = <0x40>; - compatible = "ibm,fsi2spi"; #address-cells = <1>; #size-cells = <0>; @@ -131,8 +133,8 @@ eeprom@0 { }; cfam0_spi3: spi@60 { + compatible = "ibm,spi-fsi"; reg = <0x60>; - compatible = "ibm,fsi2spi"; #address-cells = <1>; #size-cells = <0>; @@ -249,6 +251,7 @@ fsi2spi@1c00 { #size-cells = <0>; cfam1_spi0: spi@0 { + compatible = "ibm,spi-fsi"; reg = <0x0>; #address-cells = <1>; #size-cells = <0>; @@ -265,6 +268,7 @@ eeprom@0 { }; cfam1_spi1: spi@20 { + compatible = "ibm,spi-fsi"; reg = <0x20>; #address-cells = <1>; #size-cells = <0>; @@ -281,8 +285,8 @@ eeprom@0 { }; cfam1_spi2: spi@40 { + compatible = "ibm,spi-fsi"; reg = <0x40>; - compatible = "ibm,fsi2spi"; #address-cells = <1>; #size-cells = <0>; @@ -298,8 +302,8 @@ eeprom@0 { }; cfam1_spi3: spi@60 { + compatible = "ibm,spi-fsi"; reg = <0x60>; - compatible = "ibm,fsi2spi"; #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/aspeed/ibm-power10-quad.dtsi b/arch/arm/boot/dts/aspeed/ibm-power10-quad.dtsi index 57494c744b5d..9501f66d0030 100644 --- a/arch/arm/boot/dts/aspeed/ibm-power10-quad.dtsi +++ b/arch/arm/boot/dts/aspeed/ibm-power10-quad.dtsi @@ -733,6 +733,7 @@ fsi2spi@1c00 { #size-cells = <0>; cfam2_spi0: spi@0 { + compatible = "ibm,spi-fsi"; reg = <0x0>; #address-cells = <1>; #size-cells = <0>; @@ -749,6 +750,7 @@ eeprom@0 { }; cfam2_spi1: spi@20 { + compatible = "ibm,spi-fsi"; reg = <0x20>; #address-cells = <1>; #size-cells = <0>; @@ -765,8 +767,8 @@ eeprom@0 { }; cfam2_spi2: spi@40 { + compatible = "ibm,spi-fsi"; reg = <0x40>; - compatible = "ibm,fsi2spi"; #address-cells = <1>; #size-cells = <0>; @@ -782,8 +784,8 @@ eeprom@0 { }; cfam2_spi3: spi@60 { + compatible = "ibm,spi-fsi"; reg = <0x60>; - compatible = "ibm,fsi2spi"; #address-cells = <1>; #size-cells = <0>; @@ -1106,6 +1108,7 @@ fsi2spi@1c00 { #size-cells = <0>; cfam3_spi0: spi@0 { + compatible = "ibm,spi-fsi"; reg = <0x0>; #address-cells = <1>; #size-cells = <0>; @@ -1122,6 +1125,7 @@ eeprom@0 { }; cfam3_spi1: spi@20 { + compatible = "ibm,spi-fsi"; reg = <0x20>; #address-cells = <1>; #size-cells = <0>; @@ -1138,8 +1142,8 @@ eeprom@0 { }; cfam3_spi2: spi@40 { + compatible = "ibm,spi-fsi"; reg = <0x40>; - compatible = "ibm,fsi2spi"; #address-cells = <1>; #size-cells = <0>; @@ -1155,8 +1159,8 @@ eeprom@0 { }; cfam3_spi3: spi@60 { + compatible = "ibm,spi-fsi"; reg = <0x60>; - compatible = "ibm,fsi2spi"; #address-cells = <1>; #size-cells = <0>; From 5bf96232edfaa83984d7637f83dae75a9a9670eb Mon Sep 17 00:00:00 2001 From: Tan Siewert Date: Sun, 3 Aug 2025 17:19:37 +0200 Subject: [PATCH 00080/11391] ARM: dts: aspeed: e3c246d4i: convert NVMEM content to layout syntax The used bindings syntax has been deprecated and doesn't work properly anymore. Use the newer (and non-deprecated) fixed-layout approach. See commit bd912c991d2e ("dt-bindings: nvmem: layouts: add fixed-layout") for details. Signed-off-by: Tan Siewert Reviewed-by: Zev Weiss Link: https://patch.msgid.link/20250803151949.68618-1-tan@siewert.io Signed-off-by: Andrew Jeffery --- .../boot/dts/aspeed/aspeed-bmc-asrock-e3c246d4i.dts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-e3c246d4i.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-e3c246d4i.dts index 93190f4e696c..3ebd80db06f9 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-e3c246d4i.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-e3c246d4i.dts @@ -106,11 +106,15 @@ eeprom@57 { compatible = "st,24c128", "atmel,24c128"; reg = <0x57>; pagesize = <16>; - #address-cells = <1>; - #size-cells = <1>; - eth0_macaddress: macaddress@3f80 { - reg = <0x3f80 6>; + nvmem-layout { + compatible = "fixed-layout"; + #address-cells = <1>; + #size-cells = <1>; + + eth0_macaddress: macaddress@3f80 { + reg = <0x3f80 6>; + }; }; }; }; From 2660d172a346a5f6fabc8b4e07fb57751d0b2fd7 Mon Sep 17 00:00:00 2001 From: Tan Siewert Date: Sun, 3 Aug 2025 17:19:38 +0200 Subject: [PATCH 00081/11391] ARM: dts: aspeed: e3c256d4i: convert NVMEM content to layout syntax The used bindings syntax has been deprecated and doesn't work properly anymore. Use the newer (and non-deprecated) fixed-layout approach. See commit bd912c991d2e ("dt-bindings: nvmem: layouts: add fixed-layout") for details. Signed-off-by: Tan Siewert Reviewed-by: Zev Weiss Link: https://patch.msgid.link/20250803151949.68618-2-tan@siewert.io Signed-off-by: Andrew Jeffery --- .../boot/dts/aspeed/aspeed-bmc-asrock-e3c256d4i.dts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-e3c256d4i.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-e3c256d4i.dts index 9d00ce9475f2..8c57a071f488 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-e3c256d4i.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-e3c256d4i.dts @@ -191,11 +191,15 @@ eeprom@57 { compatible = "st,24c128", "atmel,24c128"; reg = <0x57>; pagesize = <16>; - #address-cells = <1>; - #size-cells = <1>; - eth0_macaddress: macaddress@3f80 { - reg = <0x3f80 6>; + nvmem-layout { + compatible = "fixed-layout"; + #address-cells = <1>; + #size-cells = <1>; + + eth0_macaddress: macaddress@3f80 { + reg = <0x3f80 6>; + }; }; }; }; From 1f5ab37b75afbfad686c56c010b2ba93a096ca87 Mon Sep 17 00:00:00 2001 From: Tan Siewert Date: Sun, 3 Aug 2025 17:19:39 +0200 Subject: [PATCH 00082/11391] ARM: dts: aspeed: romed8hm3: convert NVMEM content to layout syntax The used bindings syntax has been deprecated and doesn't work properly anymore. Use the newer (and non-deprecated) fixed-layout approach. See commit bd912c991d2e ("dt-bindings: nvmem: layouts: add fixed-layout") for details. Signed-off-by: Tan Siewert Reviewed-by: Zev Weiss Link: https://patch.msgid.link/20250803151949.68618-3-tan@siewert.io Signed-off-by: Andrew Jeffery --- .../boot/dts/aspeed/aspeed-bmc-asrock-romed8hm3.dts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-romed8hm3.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-romed8hm3.dts index 6dd221644dc6..e306655ce4a3 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-romed8hm3.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-romed8hm3.dts @@ -134,11 +134,15 @@ eeprom@50 { compatible = "st,24c128", "atmel,24c128"; reg = <0x50>; pagesize = <16>; - #address-cells = <1>; - #size-cells = <1>; - eth0_macaddress: macaddress@3f80 { - reg = <0x3f80 6>; + nvmem-layout { + compatible = "fixed-layout"; + #address-cells = <1>; + #size-cells = <1>; + + eth0_macaddress: macaddress@3f80 { + reg = <0x3f80 6>; + }; }; }; }; From b785b5d88cc27a521ea22b3afd85804c4c321d4a Mon Sep 17 00:00:00 2001 From: Tan Siewert Date: Sun, 3 Aug 2025 17:19:40 +0200 Subject: [PATCH 00083/11391] ARM: dts: aspeed: x570d4u: convert NVMEM content to layout syntax The used bindings syntax has been deprecated and doesn't work properly anymore. Use the newer (and non-deprecated) fixed-layout approach. See commit bd912c991d2e ("dt-bindings: nvmem: layouts: add fixed-layout") for details. Signed-off-by: Tan Siewert Reviewed-by: Zev Weiss Link: https://patch.msgid.link/20250803151949.68618-4-tan@siewert.io Signed-off-by: Andrew Jeffery --- .../dts/aspeed/aspeed-bmc-asrock-x570d4u.dts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-x570d4u.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-x570d4u.dts index 0943e0bf1305..e61a6cb43438 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-x570d4u.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-x570d4u.dts @@ -232,15 +232,19 @@ eeprom@57 { compatible = "st,24c128", "atmel,24c128"; reg = <0x57>; pagesize = <16>; - #address-cells = <1>; - #size-cells = <1>; - eth0_macaddress: macaddress@3f80 { - reg = <0x3f80 6>; - }; + nvmem-layout { + compatible = "fixed-layout"; + #address-cells = <1>; + #size-cells = <1>; - eth1_macaddress: macaddress@3f88 { - reg = <0x3f88 6>; + eth0_macaddress: macaddress@3f80 { + reg = <0x3f80 6>; + }; + + eth1_macaddress: macaddress@3f88 { + reg = <0x3f88 6>; + }; }; }; }; From c5313eea3e623c81ecf7dd8fe09e6ccf904e4a36 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Thu, 3 Jul 2025 13:35:07 -0500 Subject: [PATCH 00084/11391] soc: aspeed: 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. The error handling is a bit different. "memory-region" is optional, so failed lookup is not an error. But then an error in of_address_to_resource() is treated as an error. However, that distinction is not really important. Either the region is available and usable or it is not. So now, it is just of_reserved_mem_region_to_resource() which is checked for an error. Signed-off-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250703183508.2074735-1-robh@kernel.org Signed-off-by: Andrew Jeffery --- drivers/soc/aspeed/aspeed-lpc-ctrl.c | 14 +++----------- drivers/soc/aspeed/aspeed-p2a-ctrl.c | 14 +++----------- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/drivers/soc/aspeed/aspeed-lpc-ctrl.c b/drivers/soc/aspeed/aspeed-lpc-ctrl.c index ee58151bd69e..b7dbb12bd095 100644 --- a/drivers/soc/aspeed/aspeed-lpc-ctrl.c +++ b/drivers/soc/aspeed/aspeed-lpc-ctrl.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -254,17 +255,8 @@ static int aspeed_lpc_ctrl_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, lpc_ctrl); /* If memory-region is described in device tree then store */ - node = of_parse_phandle(dev->of_node, "memory-region", 0); - if (!node) { - dev_dbg(dev, "Didn't find reserved memory\n"); - } else { - rc = of_address_to_resource(node, 0, &resm); - of_node_put(node); - if (rc) { - dev_err(dev, "Couldn't address to resource for reserved memory\n"); - return -ENXIO; - } - + rc = of_reserved_mem_region_to_resource(dev->of_node, 0, &resm); + if (!rc) { lpc_ctrl->mem_size = resource_size(&resm); lpc_ctrl->mem_base = resm.start; diff --git a/drivers/soc/aspeed/aspeed-p2a-ctrl.c b/drivers/soc/aspeed/aspeed-p2a-ctrl.c index 6cc943744e12..3be2e1b1085b 100644 --- a/drivers/soc/aspeed/aspeed-p2a-ctrl.c +++ b/drivers/soc/aspeed/aspeed-p2a-ctrl.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include @@ -334,7 +334,6 @@ static int aspeed_p2a_ctrl_probe(struct platform_device *pdev) struct aspeed_p2a_ctrl *misc_ctrl; struct device *dev; struct resource resm; - struct device_node *node; int rc = 0; dev = &pdev->dev; @@ -346,15 +345,8 @@ static int aspeed_p2a_ctrl_probe(struct platform_device *pdev) mutex_init(&misc_ctrl->tracking); /* optional. */ - node = of_parse_phandle(dev->of_node, "memory-region", 0); - if (node) { - rc = of_address_to_resource(node, 0, &resm); - of_node_put(node); - if (rc) { - dev_err(dev, "Couldn't address to resource for reserved memory\n"); - return -ENODEV; - } - + rc = of_reserved_mem_region_to_resource(dev->of_node, 0, &resm); + if (!rc) { misc_ctrl->mem_size = resource_size(&resm); misc_ctrl->mem_base = resm.start; } From c30dcfd4b5a0f0e3fe7138bf287f6de6b1b00278 Mon Sep 17 00:00:00 2001 From: Ryan Chen Date: Thu, 7 Aug 2025 08:52:08 +0800 Subject: [PATCH 00085/11391] soc: aspeed: socinfo: Add AST27xx silicon IDs Extend the ASPEED SoC info driver to support AST27XX silicon IDs. Signed-off-by: Ryan Chen Link: https://patch.msgid.link/20250807005208.3517283-1-ryan_chen@aspeedtech.com Signed-off-by: Andrew Jeffery --- drivers/soc/aspeed/aspeed-socinfo.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/soc/aspeed/aspeed-socinfo.c b/drivers/soc/aspeed/aspeed-socinfo.c index 3f759121dc00..67e9ac3d08ec 100644 --- a/drivers/soc/aspeed/aspeed-socinfo.c +++ b/drivers/soc/aspeed/aspeed-socinfo.c @@ -27,6 +27,10 @@ static struct { { "AST2620", 0x05010203 }, { "AST2605", 0x05030103 }, { "AST2625", 0x05030403 }, + /* AST2700 */ + { "AST2750", 0x06000003 }, + { "AST2700", 0x06000103 }, + { "AST2720", 0x06000203 }, }; static const char *siliconid_to_name(u32 siliconid) From 7686b441c0ad921211b0a69977bad746d18e4b33 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 17 Jul 2025 16:23:02 +0200 Subject: [PATCH 00086/11391] ARM: dts: nuvoton: Use generic "ethernet" as node name Common name for Ethernet controllers is "ethernet", not "eth", also recommended by Devicetree specification in "Generic Names Recommendation". Verified lack of impact using dtx_diff. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250717142301.92548-2-krzysztof.kozlowski@linaro.org Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/nuvoton/nuvoton-common-npcm7xx.dtsi | 2 +- arch/arm/boot/dts/nuvoton/nuvoton-npcm750.dtsi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/nuvoton/nuvoton-common-npcm7xx.dtsi b/arch/arm/boot/dts/nuvoton/nuvoton-common-npcm7xx.dtsi index 791090f54d8b..98c35771534e 100644 --- a/arch/arm/boot/dts/nuvoton/nuvoton-common-npcm7xx.dtsi +++ b/arch/arm/boot/dts/nuvoton/nuvoton-common-npcm7xx.dtsi @@ -134,7 +134,7 @@ mc: memory-controller@f0824000 { status = "disabled"; }; - gmac0: eth@f0802000 { + gmac0: ethernet@f0802000 { device_type = "network"; compatible = "snps,dwmac"; reg = <0xf0802000 0x2000>; diff --git a/arch/arm/boot/dts/nuvoton/nuvoton-npcm750.dtsi b/arch/arm/boot/dts/nuvoton/nuvoton-npcm750.dtsi index f42ad259636c..65fe3a180bb1 100644 --- a/arch/arm/boot/dts/nuvoton/nuvoton-npcm750.dtsi +++ b/arch/arm/boot/dts/nuvoton/nuvoton-npcm750.dtsi @@ -44,7 +44,7 @@ timer@3fe600 { }; ahb { - gmac1: eth@f0804000 { + gmac1: ethernet@f0804000 { device_type = "network"; compatible = "snps,dwmac"; reg = <0xf0804000 0x2000>; From 91f8329e67b482faa1646609f457ea0f74b93a53 Mon Sep 17 00:00:00 2001 From: Tomer Maimon Date: Sun, 6 Jul 2025 18:35:51 +0300 Subject: [PATCH 00087/11391] arm64: dts: nuvoton: npcm845: Add pinctrl groups Add 64 missing pinctrl groups to the NPCM845 device tree source file to support additional pinmux configurations defined in the npcm845-pinctrl driver. This enhances the pinmux configuration for the NPCM845 SoC, enabling further hardware pin functionalities. Signed-off-by: Tomer Maimon Link: https://patch.msgid.link/20250706153551.2180052-1-tmaimon77@gmail.com Signed-off-by: Andrew Jeffery --- .../dts/nuvoton/nuvoton-common-npcm8xx.dtsi | 649 ++++++++++++++++++ 1 file changed, 649 insertions(+) diff --git a/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi b/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi index acd3137d2464..5be132f3fd07 100644 --- a/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi +++ b/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi @@ -235,5 +235,654 @@ gpio7: gpio@f0017000 { interrupts = ; gpio-ranges = <&pinctrl 0 224 32>; }; + + iox1_pins: iox1-mux { + groups = "iox1"; + function = "iox1"; + }; + iox2_pins: iox2-mux { + groups = "iox2"; + function = "iox2"; + }; + smb1d_pins: smb1d-mux { + groups = "smb1d"; + function = "smb1d"; + }; + smb2d_pins: smb2d-mux { + groups = "smb2d"; + function = "smb2d"; + }; + lkgpo1_pins: lkgpo1-mux { + groups = "lkgpo1"; + function = "lkgpo1"; + }; + lkgpo2_pins: lkgpo2-mux { + groups = "lkgpo2"; + function = "lkgpo2"; + }; + ioxh_pins: ioxh-mux { + groups = "ioxh"; + function = "ioxh"; + }; + gspi_pins: gspi-mux { + groups = "gspi"; + function = "gspi"; + }; + smb5b_pins: smb5b-mux { + groups = "smb5b"; + function = "smb5b"; + }; + smb5c_pins: smb5c-mux { + groups = "smb5c"; + function = "smb5c"; + }; + lkgpo0_pins: lkgpo0-mux { + groups = "lkgpo0"; + function = "lkgpo0"; + }; + pspi_pins: pspi-mux { + groups = "pspi"; + function = "pspi"; + }; + jm1_pins: jm1-mux { + groups = "jm1"; + function = "jm1"; + }; + jm2_pins: jm2-mux { + groups = "jm2"; + function = "jm2"; + }; + smb4b_pins: smb4b-mux { + groups = "smb4b"; + function = "smb4b"; + }; + smb4c_pins: smb4c-mux { + groups = "smb4c"; + function = "smb4c"; + }; + smb15_pins: smb15-mux { + groups = "smb15"; + function = "smb15"; + }; + smb16_pins: smb16-mux { + groups = "smb16"; + function = "smb16"; + }; + smb17_pins: smb17-mux { + groups = "smb17"; + function = "smb17"; + }; + smb18_pins: smb18-mux { + groups = "smb18"; + function = "smb18"; + }; + smb19_pins: smb19-mux { + groups = "smb19"; + function = "smb19"; + }; + smb20_pins: smb20-mux { + groups = "smb20"; + function = "smb20"; + }; + smb21_pins: smb21-mux { + groups = "smb21"; + function = "smb21"; + }; + smb22_pins: smb22-mux { + groups = "smb22"; + function = "smb22"; + }; + smb23_pins: smb23-mux { + groups = "smb23"; + function = "smb23"; + }; + smb23b_pins: smb23b-mux { + groups = "smb23b"; + function = "smb23b"; + }; + smb4d_pins: smb4d-mux { + groups = "smb4d"; + function = "smb4d"; + }; + smb14_pins: smb14-mux { + groups = "smb14"; + function = "smb14"; + }; + smb5_pins: smb5-mux { + groups = "smb5"; + function = "smb5"; + }; + smb4_pins: smb4-mux { + groups = "smb4"; + function = "smb4"; + }; + smb3_pins: smb3-mux { + groups = "smb3"; + function = "smb3"; + }; + spi0cs1_pins: spi0cs1-mux { + groups = "spi0cs1"; + function = "spi0cs1"; + }; + spi1cs0_pins: spi1cs0-mux { + groups = "spi1cs0"; + function = "spi1cs0"; + }; + spi1cs1_pins: spi1cs1-mux { + groups = "spi1cs1"; + function = "spi1cs1"; + }; + spi1cs2_pins: spi1cs2-mux { + groups = "spi1cs2"; + function = "spi1cs2"; + }; + spi1cs3_pins: spi1cs3-mux { + groups = "spi1cs3"; + function = "spi1cs3"; + }; + smb3c_pins: smb3c-mux { + groups = "smb3c"; + function = "smb3c"; + }; + smb3b_pins: smb3b-mux { + groups = "smb3b"; + function = "smb3b"; + }; + bmcuart0a_pins: bmcuart0a-mux { + groups = "bmcuart0a"; + function = "bmcuart0a"; + }; + uart1_pins: uart1-mux { + groups = "uart1"; + function = "uart1"; + }; + jtag2_pins: jtag2-mux { + groups = "jtag2"; + function = "jtag2"; + }; + bmcuart1_pins: bmcuart1-mux { + groups = "bmcuart1"; + function = "bmcuart1"; + }; + uart2_pins: uart2-mux { + groups = "uart2"; + function = "uart2"; + }; + bmcuart0b_pins: bmcuart0b-mux { + groups = "bmcuart0b"; + function = "bmcuart0b"; + }; + r1err_pins: r1err-mux { + groups = "r1err"; + function = "r1err"; + }; + r1md_pins: r1md-mux { + groups = "r1md"; + function = "r1md"; + }; + r1oen_pins: r1oen-mux { + groups = "r1oen"; + function = "r1oen"; + }; + r2oen_pins: r2oen-mux { + groups = "r2oen"; + function = "r2oen"; + }; + rmii3_pins: rmii3-mux { + groups = "rmii3"; + function = "rmii3"; + }; + r3oen_pins: r3oen-mux { + groups = "r3oen"; + function = "r3oen"; + }; + smb3d_pins: smb3d-mux { + groups = "smb3d"; + function = "smb3d"; + }; + fanin0_pins: fanin0-mux { + groups = "fanin0"; + function = "fanin0"; + }; + fanin1_pins: fanin1-mux { + groups = "fanin1"; + function = "fanin1"; + }; + fanin2_pins: fanin2-mux { + groups = "fanin2"; + function = "fanin2"; + }; + fanin3_pins: fanin3-mux { + groups = "fanin3"; + function = "fanin3"; + }; + fanin4_pins: fanin4-mux { + groups = "fanin4"; + function = "fanin4"; + }; + fanin5_pins: fanin5-mux { + groups = "fanin5"; + function = "fanin5"; + }; + fanin6_pins: fanin6-mux { + groups = "fanin6"; + function = "fanin6"; + }; + fanin7_pins: fanin7-mux { + groups = "fanin7"; + function = "fanin7"; + }; + fanin8_pins: fanin8-mux { + groups = "fanin8"; + function = "fanin8"; + }; + fanin9_pins: fanin9-mux { + groups = "fanin9"; + function = "fanin9"; + }; + fanin10_pins: fanin10-mux { + groups = "fanin10"; + function = "fanin10"; + }; + fanin11_pins: fanin11-mux { + groups = "fanin11"; + function = "fanin11"; + }; + fanin12_pins: fanin12-mux { + groups = "fanin12"; + function = "fanin12"; + }; + fanin13_pins: fanin13-mux { + groups = "fanin13"; + function = "fanin13"; + }; + fanin14_pins: fanin14-mux { + groups = "fanin14"; + function = "fanin14"; + }; + fanin15_pins: fanin15-mux { + groups = "fanin15"; + function = "fanin15"; + }; + pwm0_pins: pwm0-mux { + groups = "pwm0"; + function = "pwm0"; + }; + pwm1_pins: pwm1-mux { + groups = "pwm1"; + function = "pwm1"; + }; + pwm2_pins: pwm2-mux { + groups = "pwm2"; + function = "pwm2"; + }; + pwm3_pins: pwm3-mux { + groups = "pwm3"; + function = "pwm3"; + }; + r2_pins: r2-mux { + groups = "r2"; + function = "r2"; + }; + r2err_pins: r2err-mux { + groups = "r2err"; + function = "r2err"; + }; + r2md_pins: r2md-mux { + groups = "r2md"; + function = "r2md"; + }; + r3rxer_pins: r3rxer-mux { + groups = "r3rxer"; + function = "r3rxer"; + }; + ga20kbc_pins: ga20kbc-mux { + groups = "ga20kbc"; + function = "ga20kbc"; + }; + smb5d_pins: smb5d-mux { + groups = "smb5d"; + function = "smb5d"; + }; + lpc_pins: lpc-mux { + groups = "lpc"; + function = "lpc"; + }; + espi_pins: espi-mux { + groups = "espi"; + function = "espi"; + }; + sg1mdio_pins: sg1mdio-mux { + groups = "sg1mdio"; + function = "sg1mdio"; + }; + rg2_pins: rg2-mux { + groups = "rg2"; + function = "rg2"; + }; + ddr_pins: ddr-mux { + groups = "ddr"; + function = "ddr"; + }; + i3c0_pins: i3c0-mux { + groups = "i3c0"; + function = "i3c0"; + }; + i3c1_pins: i3c1-mux { + groups = "i3c1"; + function = "i3c1"; + }; + i3c2_pins: i3c2-mux { + groups = "i3c2"; + function = "i3c2"; + }; + i3c3_pins: i3c3-mux { + groups = "i3c3"; + function = "i3c3"; + }; + i3c4_pins: i3c4-mux { + groups = "i3c4"; + function = "i3c4"; + }; + i3c5_pins: i3c5-mux { + groups = "i3c5"; + function = "i3c5"; + }; + smb0_pins: smb0-mux { + groups = "smb0"; + function = "smb0"; + }; + smb1_pins: smb1-mux { + groups = "smb1"; + function = "smb1"; + }; + smb2_pins: smb2-mux { + groups = "smb2"; + function = "smb2"; + }; + smb2c_pins: smb2c-mux { + groups = "smb2c"; + function = "smb2c"; + }; + smb2b_pins: smb2b-mux { + groups = "smb2b"; + function = "smb2b"; + }; + smb1c_pins: smb1c-mux { + groups = "smb1c"; + function = "smb1c"; + }; + smb1b_pins: smb1b-mux { + groups = "smb1b"; + function = "smb1b"; + }; + smb8_pins: smb8-mux { + groups = "smb8"; + function = "smb8"; + }; + smb9_pins: smb9-mux { + groups = "smb9"; + function = "smb9"; + }; + smb10_pins: smb10-mux { + groups = "smb10"; + function = "smb10"; + }; + smb11_pins: smb11-mux { + groups = "smb11"; + function = "smb11"; + }; + sd1_pins: sd1-mux { + groups = "sd1"; + function = "sd1"; + }; + sd1pwr_pins: sd1pwr-mux { + groups = "sd1pwr"; + function = "sd1pwr"; + }; + pwm4_pins: pwm4-mux { + groups = "pwm4"; + function = "pwm4"; + }; + pwm5_pins: pwm5-mux { + groups = "pwm5"; + function = "pwm5"; + }; + pwm6_pins: pwm6-mux { + groups = "pwm6"; + function = "pwm6"; + }; + pwm7_pins: pwm7-mux { + groups = "pwm7"; + function = "pwm7"; + }; + pwm8_pins: pwm8-mux { + groups = "pwm8"; + function = "pwm8"; + }; + pwm9_pins: pwm9-mux { + groups = "pwm9"; + function = "pwm9"; + }; + pwm10_pins: pwm10-mux { + groups = "pwm10"; + function = "pwm10"; + }; + pwm11_pins: pwm11-mux { + groups = "pwm11"; + function = "pwm11"; + }; + mmc8_pins: mmc8-mux { + groups = "mmc8"; + function = "mmc8"; + }; + mmc_pins: mmc-mux { + groups = "mmc"; + function = "mmc"; + }; + mmcwp_pins: mmcwp-mux { + groups = "mmcwp"; + function = "mmcwp"; + }; + mmccd_pins: mmccd-mux { + groups = "mmccd"; + function = "mmccd"; + }; + mmcrst_pins: mmcrst-mux { + groups = "mmcrst"; + function = "mmcrst"; + }; + clkout_pins: clkout-mux { + groups = "clkout"; + function = "clkout"; + }; + serirq_pins: serirq-mux { + groups = "serirq"; + function = "serirq"; + }; + scipme_pins: scipme-mux { + groups = "scipme"; + function = "scipme"; + }; + smb6_pins: smb6-mux { + groups = "smb6"; + function = "smb6"; + }; + smb6b_pins: smb6b-mux { + groups = "smb6b"; + function = "smb6b"; + }; + smb6c_pins: smb6c-mux { + groups = "smb6c"; + function = "smb6c"; + }; + smb6d_pins: smb6d-mux { + groups = "smb6d"; + function = "smb6d"; + }; + smb7_pins: smb7-mux { + groups = "smb7"; + function = "smb7"; + }; + smb7b_pins: smb7b-mux { + groups = "smb7b"; + function = "smb7b"; + }; + smb7c_pins: smb7c-mux { + groups = "smb7c"; + function = "smb7c"; + }; + smb7d_pins: smb7d-mux { + groups = "smb7d"; + function = "smb7d"; + }; + spi1_pins: spi1-mux { + groups = "spi1"; + function = "spi1"; + }; + faninx_pins: faninx-mux { + groups = "faninx"; + function = "faninx"; + }; + r1_pins: r1-mux { + groups = "r1"; + function = "r1"; + }; + spi3_pins: spi3-mux { + groups = "spi3"; + function = "spi3"; + }; + spi3cs1_pins: spi3cs1-mux { + groups = "spi3cs1"; + function = "spi3cs1"; + }; + spi3quad_pins: spi3quad-mux { + groups = "spi3quad"; + function = "spi3quad"; + }; + spi3cs2_pins: spi3cs2-mux { + groups = "spi3cs2"; + function = "spi3cs2"; + }; + spi3cs3_pins: spi3cs3-mux { + groups = "spi3cs3"; + function = "spi3cs3"; + }; + nprd_smi_pins: nprd-smi-mux { + groups = "nprd_smi"; + function = "nprd_smi"; + }; + smi_pins: smi-mux { + groups = "smi"; + function = "smi"; + }; + smb0b_pins: smb0b-mux { + groups = "smb0b"; + function = "smb0b"; + }; + smb0c_pins: smb0c-mux { + groups = "smb0c"; + function = "smb0c"; + }; + smb0den_pins: smb0den-mux { + groups = "smb0den"; + function = "smb0den"; + }; + smb0d_pins: smb0d-mux { + groups = "smb0d"; + function = "smb0d"; + }; + ddc_pins: ddc-mux { + groups = "ddc"; + function = "ddc"; + }; + rg2mdio_pins: rg2mdio-mux { + groups = "rg2mdio"; + function = "rg2mdio"; + }; + wdog1_pins: wdog1-mux { + groups = "wdog1"; + function = "wdog1"; + }; + wdog2_pins: wdog2-mux { + groups = "wdog2"; + function = "wdog2"; + }; + smb12_pins: smb12-mux { + groups = "smb12"; + function = "smb12"; + }; + smb13_pins: smb13-mux { + groups = "smb13"; + function = "smb13"; + }; + spix_pins: spix-mux { + groups = "spix"; + function = "spix"; + }; + spixcs1_pins: spixcs1-mux { + groups = "spixcs1"; + function = "spixcs1"; + }; + clkreq_pins: clkreq-mux { + groups = "clkreq"; + function = "clkreq"; + }; + hgpio0_pins: hgpio0-mux { + groups = "hgpio0"; + function = "hgpio0"; + }; + hgpio1_pins: hgpio1-mux { + groups = "hgpio1"; + function = "hgpio1"; + }; + hgpio2_pins: hgpio2-mux { + groups = "hgpio2"; + function = "hgpio2"; + }; + hgpio3_pins: hgpio3-mux { + groups = "hgpio3"; + function = "hgpio3"; + }; + hgpio4_pins: hgpio4-mux { + groups = "hgpio4"; + function = "hgpio4"; + }; + hgpio5_pins: hgpio5-mux { + groups = "hgpio5"; + function = "hgpio5"; + }; + hgpio6_pins: hgpio6-mux { + groups = "hgpio6"; + function = "hgpio6"; + }; + hgpio7_pins: hgpio7-mux { + groups = "hgpio7"; + function = "hgpio7"; + }; + bu4_pins: bu4-mux { + groups = "bu4"; + function = "bu4"; + }; + bu4b_pins: bu4b-mux { + groups = "bu4b"; + function = "bu4b"; + }; + bu5_pins: bu5-mux { + groups = "bu5"; + function = "bu5"; + }; + bu5b_pins: bu5b-mux { + groups = "bu5b"; + function = "bu5b"; + }; + bu6_pins: bu6-mux { + groups = "bu6"; + function = "bu6"; + }; + gpo187_pins: gpo187-mux { + groups = "gpo187"; + function = "gpo187"; + }; }; }; From 2e6028f8faf07e896ea4c2603adb4b06e8cb92fa Mon Sep 17 00:00:00 2001 From: Tomer Maimon Date: Sun, 6 Jul 2025 16:42:06 +0300 Subject: [PATCH 00088/11391] arm64: dts: nuvoton: combine NPCM845 reset and clk nodes Combine the NPCM845 reset and clock controller nodes into a single node with compatible "nuvoton,npcm845-reset" in nuvoton-common-npcm8xx.dtsi, using the auxiliary device framework to provide clock functionality. Update the register range to 0xC4 to cover the shared reset and clock registers at 0xf0801000. Remove the separate nuvoton,npcm845-clk node, as the reset driver now handles clocks via an auxiliary device. Signed-off-by: Tomer Maimon Link: https://patch.msgid.link/20250706134207.2168184-2-tmaimon77@gmail.com Signed-off-by: Andrew Jeffery --- .../boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi b/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi index 5be132f3fd07..400d5c5b71ac 100644 --- a/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi +++ b/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi @@ -42,17 +42,12 @@ ahb { interrupt-parent = <&gic>; ranges; - rstc: reset-controller@f0801000 { + clk: rstc: reset-controller@f0801000 { compatible = "nuvoton,npcm845-reset"; - reg = <0x0 0xf0801000 0x0 0x78>; - #reset-cells = <2>; + reg = <0x0 0xf0801000 0x0 0xC4>; nuvoton,sysgcr = <&gcr>; - }; - - clk: clock-controller@f0801000 { - compatible = "nuvoton,npcm845-clk"; + #reset-cells = <2>; #clock-cells = <1>; - reg = <0x0 0xf0801000 0x0 0x1000>; }; apb { From 13587befb34ffa5d605196494c243420e045f28e Mon Sep 17 00:00:00 2001 From: Tomer Maimon Date: Sun, 6 Jul 2025 16:42:07 +0300 Subject: [PATCH 00089/11391] arm64: dts: nuvoton: add refclk and update peripheral clocks for NPCM845 Add a 25 MHz fixed-clock node (refclk) in the NPCM845-EVB board device tree to represent the external reference clock used by the NPCM845 reset and clock controller. Update peripherals (timer0, watchdog0-2) in the NPCM845 device tree to reference this refclk directly instead of the previous clock controller output (NPCM8XX_CLK_REFCLK). Depends-on: arm64: dts: nuvoton: Combine NPCM845 reset and clk nodes Signed-off-by: Tomer Maimon Link: https://patch.msgid.link/20250706134207.2168184-3-tmaimon77@gmail.com Signed-off-by: Andrew Jeffery --- arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi | 9 +++++---- arch/arm64/boot/dts/nuvoton/nuvoton-npcm845-evb.dts | 6 ++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi b/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi index 400d5c5b71ac..24133528b8e9 100644 --- a/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi +++ b/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi @@ -47,6 +47,7 @@ clk: rstc: reset-controller@f0801000 { reg = <0x0 0xf0801000 0x0 0xC4>; nuvoton,sysgcr = <&gcr>; #reset-cells = <2>; + clocks = <&refclk>; #clock-cells = <1>; }; @@ -71,7 +72,7 @@ timer0: timer@8000 { compatible = "nuvoton,npcm845-timer"; interrupts = ; reg = <0x8000 0x1C>; - clocks = <&clk NPCM8XX_CLK_REFCLK>; + clocks = <&refclk>; clock-names = "refclk"; }; @@ -143,7 +144,7 @@ watchdog0: watchdog@801c { interrupts = ; reg = <0x801c 0x4>; status = "disabled"; - clocks = <&clk NPCM8XX_CLK_REFCLK>; + clocks = <&refclk>; syscon = <&gcr>; }; @@ -152,7 +153,7 @@ watchdog1: watchdog@901c { interrupts = ; reg = <0x901c 0x4>; status = "disabled"; - clocks = <&clk NPCM8XX_CLK_REFCLK>; + clocks = <&refclk>; syscon = <&gcr>; }; @@ -161,7 +162,7 @@ watchdog2: watchdog@a01c { interrupts = ; reg = <0xa01c 0x4>; status = "disabled"; - clocks = <&clk NPCM8XX_CLK_REFCLK>; + clocks = <&refclk>; syscon = <&gcr>; }; }; diff --git a/arch/arm64/boot/dts/nuvoton/nuvoton-npcm845-evb.dts b/arch/arm64/boot/dts/nuvoton/nuvoton-npcm845-evb.dts index eeceb5b292a8..2638ee1c3846 100644 --- a/arch/arm64/boot/dts/nuvoton/nuvoton-npcm845-evb.dts +++ b/arch/arm64/boot/dts/nuvoton/nuvoton-npcm845-evb.dts @@ -19,6 +19,12 @@ chosen { memory@0 { reg = <0x0 0x0 0x0 0x40000000>; }; + + refclk: refclk-25mhz { + compatible = "fixed-clock"; + clock-frequency = <25000000>; + #clock-cells = <0>; + }; }; &serial0 { From 3ede313b5ec41bf1064fc35a168618eaee0d8e98 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 18 Jul 2025 18:25:38 +0300 Subject: [PATCH 00090/11391] arm64: dts: qcom: sa8775p: fix RPMh power domain indices On SA8775P power domains device doesn't use unufied (RPMHPD_foo) ABI, but it uses SoC-specific indices (SA8775P_foo). Consequently, all DSP on that platform are referencing random PDs instead of the expected ones. Correct indices used for that platform. Fixes: df54dcb34ff2 ("arm64: dts: qcom: sa8775p: add ADSP, CDSP and GPDSP nodes") Reviewed-by: Bartosz Golaszewski Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Reviewed-by: Bjorn Andersson Link: https://lore.kernel.org/r/20250718-fix-rpmhpd-abi-v2-1-0059edb9ddb3@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sa8775p.dtsi | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sa8775p.dtsi b/arch/arm64/boot/dts/qcom/sa8775p.dtsi index fed34717460f..f3bd8c9ad2ee 100644 --- a/arch/arm64/boot/dts/qcom/sa8775p.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8775p.dtsi @@ -17,7 +17,6 @@ #include #include #include -#include #include #include @@ -6055,8 +6054,8 @@ remoteproc_gpdsp0: remoteproc@20c00000 { clocks = <&rpmhcc RPMH_CXO_CLK>; clock-names = "xo"; - power-domains = <&rpmhpd RPMHPD_CX>, - <&rpmhpd RPMHPD_MXC>; + power-domains = <&rpmhpd SA8775P_CX>, + <&rpmhpd SA8775P_MXC>; power-domain-names = "cx", "mxc"; interconnects = <&gpdsp_anoc MASTER_DSP0 0 @@ -6098,8 +6097,8 @@ remoteproc_gpdsp1: remoteproc@21c00000 { clocks = <&rpmhcc RPMH_CXO_CLK>; clock-names = "xo"; - power-domains = <&rpmhpd RPMHPD_CX>, - <&rpmhpd RPMHPD_MXC>; + power-domains = <&rpmhpd SA8775P_CX>, + <&rpmhpd SA8775P_MXC>; power-domain-names = "cx", "mxc"; interconnects = <&gpdsp_anoc MASTER_DSP1 0 @@ -6239,9 +6238,9 @@ remoteproc_cdsp0: remoteproc@26300000 { clocks = <&rpmhcc RPMH_CXO_CLK>; clock-names = "xo"; - power-domains = <&rpmhpd RPMHPD_CX>, - <&rpmhpd RPMHPD_MXC>, - <&rpmhpd RPMHPD_NSP0>; + power-domains = <&rpmhpd SA8775P_CX>, + <&rpmhpd SA8775P_MXC>, + <&rpmhpd SA8775P_NSP0>; power-domain-names = "cx", "mxc", "nsp"; interconnects = <&nspa_noc MASTER_CDSP_PROC 0 @@ -6371,9 +6370,9 @@ remoteproc_cdsp1: remoteproc@2a300000 { clocks = <&rpmhcc RPMH_CXO_CLK>; clock-names = "xo"; - power-domains = <&rpmhpd RPMHPD_CX>, - <&rpmhpd RPMHPD_MXC>, - <&rpmhpd RPMHPD_NSP1>; + power-domains = <&rpmhpd SA8775P_CX>, + <&rpmhpd SA8775P_MXC>, + <&rpmhpd SA8775P_NSP1>; power-domain-names = "cx", "mxc", "nsp"; interconnects = <&nspb_noc MASTER_CDSP_PROC_B 0 @@ -6527,8 +6526,8 @@ remoteproc_adsp: remoteproc@30000000 { clocks = <&rpmhcc RPMH_CXO_CLK>; clock-names = "xo"; - power-domains = <&rpmhpd RPMHPD_LCX>, - <&rpmhpd RPMHPD_LMX>; + power-domains = <&rpmhpd SA8775P_LCX>, + <&rpmhpd SA8775P_LMX>; power-domain-names = "lcx", "lmx"; interconnects = <&lpass_ag_noc MASTER_LPASS_PROC 0 &mc_virt SLAVE_EBI1 0>; From 1d517444b21e49bb049dc1ca9df0281ba5203c86 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 18 Jul 2025 18:25:39 +0300 Subject: [PATCH 00091/11391] arm64: dts: qcom: sm8150: use correct PD for DisplayPort controller Commit 5dd110c90a50 ("arm64: dts: qcom: sm8150: add DisplayPort controller") specified SM8250_MMCX (= 6) for the DisplayPort power domain, however on SM8150 this indices maps to SM8150_MX_AO (= 6). Use correct indice instead (SM8150_MMCX = 9). Fixes: 5dd110c90a50 ("arm64: dts: qcom: sm8150: add DisplayPort controller") Signed-off-by: Dmitry Baryshkov Reviewed-by: Bjorn Andersson Link: https://lore.kernel.org/r/20250718-fix-rpmhpd-abi-v2-2-0059edb9ddb3@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index abf12e10d33f..4b347ee32441 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -3908,7 +3908,7 @@ mdss_dp: displayport-controller@ae90000 { #sound-dai-cells = <0>; operating-points-v2 = <&dp_opp_table>; - power-domains = <&rpmhpd SM8250_MMCX>; + power-domains = <&rpmhpd SM8150_MMCX>; status = "disabled"; From c48aa92720dc1b883982b1b7e110429d2e316c22 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 18 Jul 2025 18:25:40 +0300 Subject: [PATCH 00092/11391] arm64: dts: qcom: sm8250: stop using SoC-specific genpd indices The SM8250 has switched to RPMHPD_* indices for RPMh power domains, however commit 86a9264b6c56 ("arm64: dts: qcom: sm8250: Add interconnects and power-domains to QUPs") brought some more old-style indices. Convert all of them to use common RPMh PD indices. Fixes: 86a9264b6c56 ("arm64: dts: qcom: sm8250: Add interconnects and power-domains to QUPs") Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250718-fix-rpmhpd-abi-v2-3-0059edb9ddb3@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8250.dtsi | 42 ++++++++++++++-------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qcom/sm8250.dtsi index b30aea8b0540..2b3442a74a5a 100644 --- a/arch/arm64/boot/dts/qcom/sm8250.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi @@ -1030,7 +1030,7 @@ i2c14: i2c@880000 { dmas = <&gpi_dma2 0 0 QCOM_GPI_I2C>, <&gpi_dma2 1 0 QCOM_GPI_I2C>; dma-names = "tx", "rx"; - power-domains = <&rpmhpd SM8250_CX>; + power-domains = <&rpmhpd RPMHPD_CX>; interconnects = <&qup_virt MASTER_QUP_CORE_2 0 &qup_virt SLAVE_QUP_CORE_2 0>, <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_QUP_2 0>, <&aggre1_noc MASTER_QUP_2 0 &mc_virt SLAVE_EBI_CH0 0>; @@ -1075,7 +1075,7 @@ i2c15: i2c@884000 { dmas = <&gpi_dma2 0 1 QCOM_GPI_I2C>, <&gpi_dma2 1 1 QCOM_GPI_I2C>; dma-names = "tx", "rx"; - power-domains = <&rpmhpd SM8250_CX>; + power-domains = <&rpmhpd RPMHPD_CX>; interconnects = <&qup_virt MASTER_QUP_CORE_2 0 &qup_virt SLAVE_QUP_CORE_2 0>, <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_QUP_2 0>, <&aggre1_noc MASTER_QUP_2 0 &mc_virt SLAVE_EBI_CH0 0>; @@ -1120,7 +1120,7 @@ i2c16: i2c@888000 { dmas = <&gpi_dma2 0 2 QCOM_GPI_I2C>, <&gpi_dma2 1 2 QCOM_GPI_I2C>; dma-names = "tx", "rx"; - power-domains = <&rpmhpd SM8250_CX>; + power-domains = <&rpmhpd RPMHPD_CX>; interconnects = <&qup_virt MASTER_QUP_CORE_2 0 &qup_virt SLAVE_QUP_CORE_2 0>, <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_QUP_2 0>, <&aggre1_noc MASTER_QUP_2 0 &mc_virt SLAVE_EBI_CH0 0>; @@ -1165,7 +1165,7 @@ i2c17: i2c@88c000 { dmas = <&gpi_dma2 0 3 QCOM_GPI_I2C>, <&gpi_dma2 1 3 QCOM_GPI_I2C>; dma-names = "tx", "rx"; - power-domains = <&rpmhpd SM8250_CX>; + power-domains = <&rpmhpd RPMHPD_CX>; interconnects = <&qup_virt MASTER_QUP_CORE_2 0 &qup_virt SLAVE_QUP_CORE_2 0>, <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_QUP_2 0>, <&aggre1_noc MASTER_QUP_2 0 &mc_virt SLAVE_EBI_CH0 0>; @@ -1227,7 +1227,7 @@ i2c18: i2c@890000 { dmas = <&gpi_dma2 0 4 QCOM_GPI_I2C>, <&gpi_dma2 1 4 QCOM_GPI_I2C>; dma-names = "tx", "rx"; - power-domains = <&rpmhpd SM8250_CX>; + power-domains = <&rpmhpd RPMHPD_CX>; interconnects = <&qup_virt MASTER_QUP_CORE_2 0 &qup_virt SLAVE_QUP_CORE_2 0>, <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_QUP_2 0>, <&aggre1_noc MASTER_QUP_2 0 &mc_virt SLAVE_EBI_CH0 0>; @@ -1289,7 +1289,7 @@ i2c19: i2c@894000 { dmas = <&gpi_dma2 0 5 QCOM_GPI_I2C>, <&gpi_dma2 1 5 QCOM_GPI_I2C>; dma-names = "tx", "rx"; - power-domains = <&rpmhpd SM8250_CX>; + power-domains = <&rpmhpd RPMHPD_CX>; interconnects = <&qup_virt MASTER_QUP_CORE_2 0 &qup_virt SLAVE_QUP_CORE_2 0>, <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_QUP_2 0>, <&aggre1_noc MASTER_QUP_2 0 &mc_virt SLAVE_EBI_CH0 0>; @@ -1370,7 +1370,7 @@ i2c0: i2c@980000 { dmas = <&gpi_dma0 0 0 QCOM_GPI_I2C>, <&gpi_dma0 1 0 QCOM_GPI_I2C>; dma-names = "tx", "rx"; - power-domains = <&rpmhpd SM8250_CX>; + power-domains = <&rpmhpd RPMHPD_CX>; interconnects = <&qup_virt MASTER_QUP_CORE_0 0 &qup_virt SLAVE_QUP_CORE_0 0>, <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_QUP_0 0>, <&aggre2_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI_CH0 0>; @@ -1415,7 +1415,7 @@ i2c1: i2c@984000 { dmas = <&gpi_dma0 0 1 QCOM_GPI_I2C>, <&gpi_dma0 1 1 QCOM_GPI_I2C>; dma-names = "tx", "rx"; - power-domains = <&rpmhpd SM8250_CX>; + power-domains = <&rpmhpd RPMHPD_CX>; interconnects = <&qup_virt MASTER_QUP_CORE_0 0 &qup_virt SLAVE_QUP_CORE_0 0>, <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_QUP_0 0>, <&aggre2_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI_CH0 0>; @@ -1460,7 +1460,7 @@ i2c2: i2c@988000 { dmas = <&gpi_dma0 0 2 QCOM_GPI_I2C>, <&gpi_dma0 1 2 QCOM_GPI_I2C>; dma-names = "tx", "rx"; - power-domains = <&rpmhpd SM8250_CX>; + power-domains = <&rpmhpd RPMHPD_CX>; interconnects = <&qup_virt MASTER_QUP_CORE_0 0 &qup_virt SLAVE_QUP_CORE_0 0>, <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_QUP_0 0>, <&aggre2_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI_CH0 0>; @@ -1522,7 +1522,7 @@ i2c3: i2c@98c000 { dmas = <&gpi_dma0 0 3 QCOM_GPI_I2C>, <&gpi_dma0 1 3 QCOM_GPI_I2C>; dma-names = "tx", "rx"; - power-domains = <&rpmhpd SM8250_CX>; + power-domains = <&rpmhpd RPMHPD_CX>; interconnects = <&qup_virt MASTER_QUP_CORE_0 0 &qup_virt SLAVE_QUP_CORE_0 0>, <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_QUP_0 0>, <&aggre2_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI_CH0 0>; @@ -1567,7 +1567,7 @@ i2c4: i2c@990000 { dmas = <&gpi_dma0 0 4 QCOM_GPI_I2C>, <&gpi_dma0 1 4 QCOM_GPI_I2C>; dma-names = "tx", "rx"; - power-domains = <&rpmhpd SM8250_CX>; + power-domains = <&rpmhpd RPMHPD_CX>; interconnects = <&qup_virt MASTER_QUP_CORE_0 0 &qup_virt SLAVE_QUP_CORE_0 0>, <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_QUP_0 0>, <&aggre2_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI_CH0 0>; @@ -1612,7 +1612,7 @@ i2c5: i2c@994000 { dmas = <&gpi_dma0 0 5 QCOM_GPI_I2C>, <&gpi_dma0 1 5 QCOM_GPI_I2C>; dma-names = "tx", "rx"; - power-domains = <&rpmhpd SM8250_CX>; + power-domains = <&rpmhpd RPMHPD_CX>; interconnects = <&qup_virt MASTER_QUP_CORE_0 0 &qup_virt SLAVE_QUP_CORE_0 0>, <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_QUP_0 0>, <&aggre2_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI_CH0 0>; @@ -1657,7 +1657,7 @@ i2c6: i2c@998000 { dmas = <&gpi_dma0 0 6 QCOM_GPI_I2C>, <&gpi_dma0 1 6 QCOM_GPI_I2C>; dma-names = "tx", "rx"; - power-domains = <&rpmhpd SM8250_CX>; + power-domains = <&rpmhpd RPMHPD_CX>; interconnects = <&qup_virt MASTER_QUP_CORE_0 0 &qup_virt SLAVE_QUP_CORE_0 0>, <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_QUP_0 0>, <&aggre2_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI_CH0 0>; @@ -1719,7 +1719,7 @@ i2c7: i2c@99c000 { dmas = <&gpi_dma0 0 7 QCOM_GPI_I2C>, <&gpi_dma0 1 7 QCOM_GPI_I2C>; dma-names = "tx", "rx"; - power-domains = <&rpmhpd SM8250_CX>; + power-domains = <&rpmhpd RPMHPD_CX>; interconnects = <&qup_virt MASTER_QUP_CORE_0 0 &qup_virt SLAVE_QUP_CORE_0 0>, <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_QUP_0 0>, <&aggre2_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI_CH0 0>; @@ -1797,7 +1797,7 @@ i2c8: i2c@a80000 { dmas = <&gpi_dma1 0 0 QCOM_GPI_I2C>, <&gpi_dma1 1 0 QCOM_GPI_I2C>; dma-names = "tx", "rx"; - power-domains = <&rpmhpd SM8250_CX>; + power-domains = <&rpmhpd RPMHPD_CX>; interconnects = <&qup_virt MASTER_QUP_CORE_1 0 &qup_virt SLAVE_QUP_CORE_1 0>, <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_QUP_1 0>, <&aggre1_noc MASTER_QUP_1 0 &mc_virt SLAVE_EBI_CH0 0>; @@ -1842,7 +1842,7 @@ i2c9: i2c@a84000 { dmas = <&gpi_dma1 0 1 QCOM_GPI_I2C>, <&gpi_dma1 1 1 QCOM_GPI_I2C>; dma-names = "tx", "rx"; - power-domains = <&rpmhpd SM8250_CX>; + power-domains = <&rpmhpd RPMHPD_CX>; interconnects = <&qup_virt MASTER_QUP_CORE_1 0 &qup_virt SLAVE_QUP_CORE_1 0>, <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_QUP_1 0>, <&aggre1_noc MASTER_QUP_1 0 &mc_virt SLAVE_EBI_CH0 0>; @@ -1887,7 +1887,7 @@ i2c10: i2c@a88000 { dmas = <&gpi_dma1 0 2 QCOM_GPI_I2C>, <&gpi_dma1 1 2 QCOM_GPI_I2C>; dma-names = "tx", "rx"; - power-domains = <&rpmhpd SM8250_CX>; + power-domains = <&rpmhpd RPMHPD_CX>; interconnects = <&qup_virt MASTER_QUP_CORE_1 0 &qup_virt SLAVE_QUP_CORE_1 0>, <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_QUP_1 0>, <&aggre1_noc MASTER_QUP_1 0 &mc_virt SLAVE_EBI_CH0 0>; @@ -1932,7 +1932,7 @@ i2c11: i2c@a8c000 { dmas = <&gpi_dma1 0 3 QCOM_GPI_I2C>, <&gpi_dma1 1 3 QCOM_GPI_I2C>; dma-names = "tx", "rx"; - power-domains = <&rpmhpd SM8250_CX>; + power-domains = <&rpmhpd RPMHPD_CX>; interconnects = <&qup_virt MASTER_QUP_CORE_1 0 &qup_virt SLAVE_QUP_CORE_1 0>, <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_QUP_1 0>, <&aggre1_noc MASTER_QUP_1 0 &mc_virt SLAVE_EBI_CH0 0>; @@ -1977,7 +1977,7 @@ i2c12: i2c@a90000 { dmas = <&gpi_dma1 0 4 QCOM_GPI_I2C>, <&gpi_dma1 1 4 QCOM_GPI_I2C>; dma-names = "tx", "rx"; - power-domains = <&rpmhpd SM8250_CX>; + power-domains = <&rpmhpd RPMHPD_CX>; interconnects = <&qup_virt MASTER_QUP_CORE_1 0 &qup_virt SLAVE_QUP_CORE_1 0>, <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_QUP_1 0>, <&aggre1_noc MASTER_QUP_1 0 &mc_virt SLAVE_EBI_CH0 0>; @@ -2039,7 +2039,7 @@ i2c13: i2c@a94000 { dmas = <&gpi_dma1 0 5 QCOM_GPI_I2C>, <&gpi_dma1 1 5 QCOM_GPI_I2C>; dma-names = "tx", "rx"; - power-domains = <&rpmhpd SM8250_CX>; + power-domains = <&rpmhpd RPMHPD_CX>; interconnects = <&qup_virt MASTER_QUP_CORE_1 0 &qup_virt SLAVE_QUP_CORE_1 0>, <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_QUP_1 0>, <&aggre1_noc MASTER_QUP_1 0 &mc_virt SLAVE_EBI_CH0 0>; @@ -4797,7 +4797,7 @@ mdss_dp: displayport-controller@ae90000 { #sound-dai-cells = <0>; operating-points-v2 = <&dp_opp_table>; - power-domains = <&rpmhpd SM8250_MMCX>; + power-domains = <&rpmhpd RPMHPD_MMCX>; status = "disabled"; From 633ffe23173d947e4075ecf419889a59e6851ea9 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 18 Jul 2025 18:25:41 +0300 Subject: [PATCH 00093/11391] arm64: dts: qcom: sm8550: stop using SoC-specific genpd indices The SM8550 has switched to RPMHPD_* indices for RPMh power domains, however commit e271b59e39a6 ("arm64: dts: qcom: sm8550: Add camera clock controller") brought some more old-style indices. Convert all of them to use common RPMh PD indices. Fixes: e271b59e39a6 ("arm64: dts: qcom: sm8550: Add camera clock controller") Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250718-fix-rpmhpd-abi-v2-4-0059edb9ddb3@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8550.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi index 45713d46f3c5..a4ca06679c2f 100644 --- a/arch/arm64/boot/dts/qcom/sm8550.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi @@ -3623,7 +3623,7 @@ camcc: clock-controller@ade0000 { <&bi_tcxo_div2>, <&bi_tcxo_ao_div2>, <&sleep_clk>; - power-domains = <&rpmhpd SM8550_MMCX>; + power-domains = <&rpmhpd RPMHPD_MMCX>; required-opps = <&rpmhpd_opp_low_svs>; #clock-cells = <1>; #reset-cells = <1>; From c7724332e0ac88168723f4140cef4c8ba92f87e0 Mon Sep 17 00:00:00 2001 From: Wasim Nazir Date: Sun, 3 Aug 2025 16:31:05 +0530 Subject: [PATCH 00094/11391] arm64: dts: qcom: Rename sa8775p SoC to "lemans" SA8775P, QCS9100 and QCS9075 are all variants of the same die, collectively referred to as lemans. Most notably, the last of them has the SAIL (Safety Island) fused off, but remains identical otherwise. In an effort to streamline the codebase, rename the SoC DTSI, moving away from less meaningful numerical model identifiers. Reviewed-by: Konrad Dybcio Nacked-by: Krzysztof Kozlowski Signed-off-by: Wasim Nazir Link: https://lore.kernel.org/r/20250803110113.401927-2-wasim.nazir@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/{sa8775p.dtsi => lemans.dtsi} | 0 arch/arm64/boot/dts/qcom/sa8775p-ride.dtsi | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/arm64/boot/dts/qcom/{sa8775p.dtsi => lemans.dtsi} (100%) diff --git a/arch/arm64/boot/dts/qcom/sa8775p.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi similarity index 100% rename from arch/arm64/boot/dts/qcom/sa8775p.dtsi rename to arch/arm64/boot/dts/qcom/lemans.dtsi diff --git a/arch/arm64/boot/dts/qcom/sa8775p-ride.dtsi b/arch/arm64/boot/dts/qcom/sa8775p-ride.dtsi index 63b3031cfcc1..bcd284c0f939 100644 --- a/arch/arm64/boot/dts/qcom/sa8775p-ride.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8775p-ride.dtsi @@ -8,7 +8,7 @@ #include #include -#include "sa8775p.dtsi" +#include "lemans.dtsi" #include "sa8775p-pmics.dtsi" / { From 24dc241bddcde97f4099b5b8ebb3b211d5e7122c Mon Sep 17 00:00:00 2001 From: Wasim Nazir Date: Sun, 3 Aug 2025 16:31:06 +0530 Subject: [PATCH 00095/11391] arm64: dts: qcom: lemans: Update memory-map for IoT platforms The "automotive" memory map is the special case for the Lemans configuration described by this dtsi, move it aside and use the IoT memory map as the baseline. Introduce "lemans-auto" as a derivative of "lemans" that retains the old automotive memory map to support legacy use cases. As part of the IoT memory map updates: - Introduce new carveouts for gunyah_md and pil_dtb. Adjust the size and base address of the PIL carveout to accommodate these changes. - Increase the size of the video/camera PIL carveout without affecting existing functionality. - Reduce the size of the trusted apps carveout to meet IoT-specific requirements. - Remove audio_mdf_mem, tz_ffi_mem, and their corresponding SCM references, as they are not required for IoT platforms. Co-developed-by: Pratyush Brahma Signed-off-by: Pratyush Brahma Co-developed-by: Prakash Gupta Signed-off-by: Prakash Gupta Nacked-by: Krzysztof Kozlowski Signed-off-by: Wasim Nazir Link: https://lore.kernel.org/r/20250803110113.401927-3-wasim.nazir@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/lemans-auto.dtsi | 104 +++++++++++++++++++++ arch/arm64/boot/dts/qcom/lemans.dtsi | 77 ++++++++------- arch/arm64/boot/dts/qcom/sa8775p-ride.dtsi | 2 +- 3 files changed, 150 insertions(+), 33 deletions(-) create mode 100644 arch/arm64/boot/dts/qcom/lemans-auto.dtsi diff --git a/arch/arm64/boot/dts/qcom/lemans-auto.dtsi b/arch/arm64/boot/dts/qcom/lemans-auto.dtsi new file mode 100644 index 000000000000..8db958d60fd1 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/lemans-auto.dtsi @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023, Linaro Limited + */ + +/dts-v1/; + +#include "lemans.dtsi" + +/delete-node/ &pil_camera_mem; +/delete-node/ &pil_adsp_mem; +/delete-node/ &q6_adsp_dtb_mem; +/delete-node/ &q6_gdsp0_dtb_mem; +/delete-node/ &pil_gdsp0_mem; +/delete-node/ &pil_gdsp1_mem; +/delete-node/ &q6_gdsp1_dtb_mem; +/delete-node/ &q6_cdsp0_dtb_mem; +/delete-node/ &pil_cdsp0_mem; +/delete-node/ &pil_gpu_mem; +/delete-node/ &pil_cdsp1_mem; +/delete-node/ &q6_cdsp1_dtb_mem; +/delete-node/ &pil_cvp_mem; +/delete-node/ &pil_video_mem; +/delete-node/ &gunyah_md_mem; + +/ { + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + tz_ffi_mem: tz-ffi@91c00000 { + compatible = "shared-dma-pool"; + reg = <0x0 0x91c00000 0x0 0x1400000>; + no-map; + }; + + pil_camera_mem: pil-camera@95200000 { + reg = <0x0 0x95200000 0x0 0x500000>; + no-map; + }; + + pil_adsp_mem: pil-adsp@95c00000 { + reg = <0x0 0x95c00000 0x0 0x1e00000>; + no-map; + }; + + pil_gdsp0_mem: pil-gdsp0@97b00000 { + reg = <0x0 0x97b00000 0x0 0x1e00000>; + no-map; + }; + + pil_gdsp1_mem: pil-gdsp1@99900000 { + reg = <0x0 0x99900000 0x0 0x1e00000>; + no-map; + }; + + pil_cdsp0_mem: pil-cdsp0@9b800000 { + reg = <0x0 0x9b800000 0x0 0x1e00000>; + no-map; + }; + + pil_gpu_mem: pil-gpu@9d600000 { + reg = <0x0 0x9d600000 0x0 0x2000>; + no-map; + }; + + pil_cdsp1_mem: pil-cdsp1@9d700000 { + reg = <0x0 0x9d700000 0x0 0x1e00000>; + no-map; + }; + + pil_cvp_mem: pil-cvp@9f500000 { + reg = <0x0 0x9f500000 0x0 0x700000>; + no-map; + }; + + pil_video_mem: pil-video@9fc00000 { + reg = <0x0 0x9fc00000 0x0 0x700000>; + no-map; + }; + + audio_mdf_mem: audio-mdf-region@ae000000 { + reg = <0x0 0xae000000 0x0 0x1000000>; + no-map; + }; + + hyptz_reserved_mem: hyptz-reserved@beb00000 { + reg = <0x0 0xbeb00000 0x0 0x11500000>; + no-map; + }; + + trusted_apps_mem: trusted-apps@d1900000 { + reg = <0x0 0xd1900000 0x0 0x3800000>; + no-map; + }; + }; + + firmware { + scm { + memory-region = <&tz_ffi_mem>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi index f3bd8c9ad2ee..0a9c92aa7234 100644 --- a/arch/arm64/boot/dts/qcom/lemans.dtsi +++ b/arch/arm64/boot/dts/qcom/lemans.dtsi @@ -513,7 +513,6 @@ firmware { scm { compatible = "qcom,scm-sa8775p", "qcom,scm"; qcom,dload-mode = <&tcsr 0x13000>; - memory-region = <&tz_ffi_mem>; }; }; @@ -772,6 +771,11 @@ sail_ota_mem: sail-ss@90e00000 { no-map; }; + gunyah_md_mem: gunyah-md@91a80000 { + reg = <0x0 0x91a80000 0x0 0x80000>; + no-map; + }; + aoss_backup_mem: aoss-backup@91b00000 { reg = <0x0 0x91b00000 0x0 0x40000>; no-map; @@ -797,12 +801,6 @@ cdt_data_backup_mem: cdt-data-backup@91ba0000 { no-map; }; - tz_ffi_mem: tz-ffi@91c00000 { - compatible = "shared-dma-pool"; - reg = <0x0 0x91c00000 0x0 0x1400000>; - no-map; - }; - lpass_machine_learning_mem: lpass-machine-learning@93b00000 { reg = <0x0 0x93b00000 0x0 0xf00000>; no-map; @@ -814,52 +812,72 @@ adsp_rpc_remote_heap_mem: adsp-rpc-remote-heap@94a00000 { }; pil_camera_mem: pil-camera@95200000 { - reg = <0x0 0x95200000 0x0 0x500000>; + reg = <0x0 0x95200000 0x0 0x700000>; no-map; }; - pil_adsp_mem: pil-adsp@95c00000 { - reg = <0x0 0x95c00000 0x0 0x1e00000>; + pil_adsp_mem: pil-adsp@95900000 { + reg = <0x0 0x95900000 0x0 0x1e00000>; no-map; }; - pil_gdsp0_mem: pil-gdsp0@97b00000 { - reg = <0x0 0x97b00000 0x0 0x1e00000>; + q6_adsp_dtb_mem: q6-adsp-dtb@97700000 { + reg = <0x0 0x97700000 0x0 0x80000>; no-map; }; - pil_gdsp1_mem: pil-gdsp1@99900000 { - reg = <0x0 0x99900000 0x0 0x1e00000>; + q6_gdsp0_dtb_mem: q6-gdsp0-dtb@97780000 { + reg = <0x0 0x97780000 0x0 0x80000>; no-map; }; - pil_cdsp0_mem: pil-cdsp0@9b800000 { - reg = <0x0 0x9b800000 0x0 0x1e00000>; + pil_gdsp0_mem: pil-gdsp0@97800000 { + reg = <0x0 0x97800000 0x0 0x1e00000>; no-map; }; - pil_gpu_mem: pil-gpu@9d600000 { - reg = <0x0 0x9d600000 0x0 0x2000>; + pil_gdsp1_mem: pil-gdsp1@99600000 { + reg = <0x0 0x99600000 0x0 0x1e00000>; no-map; }; - pil_cdsp1_mem: pil-cdsp1@9d700000 { - reg = <0x0 0x9d700000 0x0 0x1e00000>; + q6_gdsp1_dtb_mem: q6-gdsp1-dtb@9b400000 { + reg = <0x0 0x9b400000 0x0 0x80000>; no-map; }; - pil_cvp_mem: pil-cvp@9f500000 { - reg = <0x0 0x9f500000 0x0 0x700000>; + q6_cdsp0_dtb_mem: q6-cdsp0-dtb@9b480000 { + reg = <0x0 0x9b480000 0x0 0x80000>; no-map; }; - pil_video_mem: pil-video@9fc00000 { - reg = <0x0 0x9fc00000 0x0 0x700000>; + pil_cdsp0_mem: pil-cdsp0@9b500000 { + reg = <0x0 0x9b500000 0x0 0x1e00000>; no-map; }; - audio_mdf_mem: audio-mdf-region@ae000000 { - reg = <0x0 0xae000000 0x0 0x1000000>; + pil_gpu_mem: pil-gpu@9d300000 { + reg = <0x0 0x9d300000 0x0 0x2000>; + no-map; + }; + + q6_cdsp1_dtb_mem: q6-cdsp1-dtb@9d380000 { + reg = <0x0 0x9d380000 0x0 0x80000>; + no-map; + }; + + pil_cdsp1_mem: pil-cdsp1@9d400000 { + reg = <0x0 0x9d400000 0x0 0x1e00000>; + no-map; + }; + + pil_cvp_mem: pil-cvp@9f200000 { + reg = <0x0 0x9f200000 0x0 0x700000>; + no-map; + }; + + pil_video_mem: pil-video@9f900000 { + reg = <0x0 0x9f900000 0x0 0x1000000>; no-map; }; @@ -868,11 +886,6 @@ firmware_mem: firmware-region@b0000000 { no-map; }; - hyptz_reserved_mem: hyptz-reserved@beb00000 { - reg = <0x0 0xbeb00000 0x0 0x11500000>; - no-map; - }; - scmi_mem: scmi-region@d0000000 { reg = <0x0 0xd0000000 0x0 0x40000>; no-map; @@ -914,7 +927,7 @@ deepsleep_backup_mem: deepsleep-backup@d1800000 { }; trusted_apps_mem: trusted-apps@d1900000 { - reg = <0x0 0xd1900000 0x0 0x3800000>; + reg = <0x0 0xd1900000 0x0 0x1c00000>; no-map; }; diff --git a/arch/arm64/boot/dts/qcom/sa8775p-ride.dtsi b/arch/arm64/boot/dts/qcom/sa8775p-ride.dtsi index bcd284c0f939..a9ec6ded412e 100644 --- a/arch/arm64/boot/dts/qcom/sa8775p-ride.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8775p-ride.dtsi @@ -8,7 +8,7 @@ #include #include -#include "lemans.dtsi" +#include "lemans-auto.dtsi" #include "sa8775p-pmics.dtsi" / { From 4c0c97b95a9b05e3886c3453492a465507d5c09b Mon Sep 17 00:00:00 2001 From: Wasim Nazir Date: Sun, 3 Aug 2025 16:31:07 +0530 Subject: [PATCH 00096/11391] arm64: dts: qcom: lemans: Separate out ethernet card for ride & ride-r3 Ride & Ride-r3 in lemans/lemans-auto uses different ethernet cards with different phy capabilities. Separate out the ethernet card information from main board so that it can be reused for all the variants of ride & ride-r3 platforms in lemans/lemans-auto. Lemans/lemans-auto Ride uses 1G phy while Lemans/lemans-auto Ride-r3 uses 2.5G phy. Introduce ethernet cards with 1G & 2.5G phy capabilities respectively: *-88ea1512.dtsi is for 2x 1G - SGMII (Marvell 88EA1512-B2) phy *-aqr115c.dtsi is for 2x 2.5G - HSGMII (Marvell AQR115c) phy Nacked-by: Krzysztof Kozlowski Signed-off-by: Wasim Nazir Link: https://lore.kernel.org/r/20250803110113.401927-4-wasim.nazir@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- .../qcom/lemans-ride-ethernet-88ea1512.dtsi | 205 ++++++++++++++++++ .../qcom/lemans-ride-ethernet-aqr115c.dtsi | 205 ++++++++++++++++++ arch/arm64/boot/dts/qcom/sa8775p-ride-r3.dts | 35 +-- arch/arm64/boot/dts/qcom/sa8775p-ride.dts | 35 +-- arch/arm64/boot/dts/qcom/sa8775p-ride.dtsi | 163 -------------- 5 files changed, 412 insertions(+), 231 deletions(-) create mode 100644 arch/arm64/boot/dts/qcom/lemans-ride-ethernet-88ea1512.dtsi create mode 100644 arch/arm64/boot/dts/qcom/lemans-ride-ethernet-aqr115c.dtsi diff --git a/arch/arm64/boot/dts/qcom/lemans-ride-ethernet-88ea1512.dtsi b/arch/arm64/boot/dts/qcom/lemans-ride-ethernet-88ea1512.dtsi new file mode 100644 index 000000000000..9d6bbe1447a4 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/lemans-ride-ethernet-88ea1512.dtsi @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023, Linaro Limited + */ + +/* + * Ethernet card for Lemans based Ride boards. + * It supports 2x 1G - SGMII (Marvell 88EA1512-B2) phy for Main domain + */ + +#include +#include + +/ { + aliases { + ethernet0 = ðernet0; + ethernet1 = ðernet1; + }; +}; + +&tlmm { + ethernet0_default: ethernet0-default-state { + ethernet0_mdc: ethernet0-mdc-pins { + pins = "gpio8"; + function = "emac0_mdc"; + drive-strength = <16>; + bias-pull-up; + }; + + ethernet0_mdio: ethernet0-mdio-pins { + pins = "gpio9"; + function = "emac0_mdio"; + drive-strength = <16>; + bias-pull-up; + }; + }; +}; + +ðernet0 { + phy-handle = <&sgmii_phy0>; + phy-mode = "sgmii"; + + pinctrl-0 = <ðernet0_default>; + pinctrl-names = "default"; + + snps,mtl-rx-config = <&mtl_rx_setup>; + snps,mtl-tx-config = <&mtl_tx_setup>; + snps,ps-speed = <1000>; + + status = "okay"; + + mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + sgmii_phy0: phy@8 { + compatible = "ethernet-phy-id0141.0dd4"; + reg = <0x8>; + device_type = "ethernet-phy"; + interrupts-extended = <&tlmm 7 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&pmm8654au_2_gpios 8 GPIO_ACTIVE_LOW>; + reset-assert-us = <11000>; + reset-deassert-us = <70000>; + }; + + sgmii_phy1: phy@a { + compatible = "ethernet-phy-id0141.0dd4"; + reg = <0xa>; + device_type = "ethernet-phy"; + interrupts-extended = <&tlmm 26 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&pmm8654au_2_gpios 9 GPIO_ACTIVE_LOW>; + reset-assert-us = <11000>; + reset-deassert-us = <70000>; + }; + }; + + mtl_rx_setup: rx-queues-config { + snps,rx-queues-to-use = <4>; + snps,rx-sched-sp; + + queue0 { + snps,dcb-algorithm; + snps,map-to-dma-channel = <0x0>; + snps,route-up; + snps,priority = <0x1>; + }; + + queue1 { + snps,dcb-algorithm; + snps,map-to-dma-channel = <0x1>; + snps,route-ptp; + }; + + queue2 { + snps,avb-algorithm; + snps,map-to-dma-channel = <0x2>; + snps,route-avcp; + }; + + queue3 { + snps,avb-algorithm; + snps,map-to-dma-channel = <0x3>; + snps,priority = <0xc>; + }; + }; + + mtl_tx_setup: tx-queues-config { + snps,tx-queues-to-use = <4>; + + queue0 { + snps,dcb-algorithm; + }; + + queue1 { + snps,dcb-algorithm; + }; + + queue2 { + snps,avb-algorithm; + snps,send_slope = <0x1000>; + snps,idle_slope = <0x1000>; + snps,high_credit = <0x3e800>; + snps,low_credit = <0xffc18000>; + }; + + queue3 { + snps,avb-algorithm; + snps,send_slope = <0x1000>; + snps,idle_slope = <0x1000>; + snps,high_credit = <0x3e800>; + snps,low_credit = <0xffc18000>; + }; + }; +}; + +ðernet1 { + phy-handle = <&sgmii_phy1>; + phy-mode = "sgmii"; + + snps,mtl-rx-config = <&mtl_rx_setup1>; + snps,mtl-tx-config = <&mtl_tx_setup1>; + snps,ps-speed = <1000>; + + status = "okay"; + + mtl_rx_setup1: rx-queues-config { + snps,rx-queues-to-use = <4>; + snps,rx-sched-sp; + + queue0 { + snps,dcb-algorithm; + snps,map-to-dma-channel = <0x0>; + snps,route-up; + snps,priority = <0x1>; + }; + + queue1 { + snps,dcb-algorithm; + snps,map-to-dma-channel = <0x1>; + snps,route-ptp; + }; + + queue2 { + snps,avb-algorithm; + snps,map-to-dma-channel = <0x2>; + snps,route-avcp; + }; + + queue3 { + snps,avb-algorithm; + snps,map-to-dma-channel = <0x3>; + snps,priority = <0xc>; + }; + }; + + mtl_tx_setup1: tx-queues-config { + snps,tx-queues-to-use = <4>; + + queue0 { + snps,dcb-algorithm; + }; + + queue1 { + snps,dcb-algorithm; + }; + + queue2 { + snps,avb-algorithm; + snps,send_slope = <0x1000>; + snps,idle_slope = <0x1000>; + snps,high_credit = <0x3e800>; + snps,low_credit = <0xffc18000>; + }; + + queue3 { + snps,avb-algorithm; + snps,send_slope = <0x1000>; + snps,idle_slope = <0x1000>; + snps,high_credit = <0x3e800>; + snps,low_credit = <0xffc18000>; + }; + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/lemans-ride-ethernet-aqr115c.dtsi b/arch/arm64/boot/dts/qcom/lemans-ride-ethernet-aqr115c.dtsi new file mode 100644 index 000000000000..2d2d9ee5f0d9 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/lemans-ride-ethernet-aqr115c.dtsi @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023, Linaro Limited + */ + +/* + * Ethernet card for Lemans based Ride r3 boards. + * It supports 2x 2.5G - HSGMII (Marvell hsgmii) phy for Main domain + */ + +#include +#include + +/ { + aliases { + ethernet0 = ðernet0; + ethernet1 = ðernet1; + }; +}; + +&tlmm { + ethernet0_default: ethernet0-default-state { + ethernet0_mdc: ethernet0-mdc-pins { + pins = "gpio8"; + function = "emac0_mdc"; + drive-strength = <16>; + bias-pull-up; + }; + + ethernet0_mdio: ethernet0-mdio-pins { + pins = "gpio9"; + function = "emac0_mdio"; + drive-strength = <16>; + bias-pull-up; + }; + }; +}; + +ðernet0 { + phy-handle = <&hsgmii_phy0>; + phy-mode = "2500base-x"; + + pinctrl-0 = <ðernet0_default>; + pinctrl-names = "default"; + + snps,mtl-rx-config = <&mtl_rx_setup>; + snps,mtl-tx-config = <&mtl_tx_setup>; + snps,ps-speed = <1000>; + + status = "okay"; + + mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + hsgmii_phy0: phy@8 { + compatible = "ethernet-phy-id31c3.1c33"; + reg = <0x8>; + device_type = "ethernet-phy"; + interrupts-extended = <&tlmm 7 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&pmm8654au_2_gpios 8 GPIO_ACTIVE_LOW>; + reset-assert-us = <11000>; + reset-deassert-us = <70000>; + }; + + hsgmii_phy1: phy@0 { + compatible = "ethernet-phy-id31c3.1c33"; + reg = <0x0>; + device_type = "ethernet-phy"; + interrupts-extended = <&tlmm 26 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&pmm8654au_2_gpios 9 GPIO_ACTIVE_LOW>; + reset-assert-us = <11000>; + reset-deassert-us = <70000>; + }; + }; + + mtl_rx_setup: rx-queues-config { + snps,rx-queues-to-use = <4>; + snps,rx-sched-sp; + + queue0 { + snps,dcb-algorithm; + snps,map-to-dma-channel = <0x0>; + snps,route-up; + snps,priority = <0x1>; + }; + + queue1 { + snps,dcb-algorithm; + snps,map-to-dma-channel = <0x1>; + snps,route-ptp; + }; + + queue2 { + snps,avb-algorithm; + snps,map-to-dma-channel = <0x2>; + snps,route-avcp; + }; + + queue3 { + snps,avb-algorithm; + snps,map-to-dma-channel = <0x3>; + snps,priority = <0xc>; + }; + }; + + mtl_tx_setup: tx-queues-config { + snps,tx-queues-to-use = <4>; + + queue0 { + snps,dcb-algorithm; + }; + + queue1 { + snps,dcb-algorithm; + }; + + queue2 { + snps,avb-algorithm; + snps,send_slope = <0x1000>; + snps,idle_slope = <0x1000>; + snps,high_credit = <0x3e800>; + snps,low_credit = <0xffc18000>; + }; + + queue3 { + snps,avb-algorithm; + snps,send_slope = <0x1000>; + snps,idle_slope = <0x1000>; + snps,high_credit = <0x3e800>; + snps,low_credit = <0xffc18000>; + }; + }; +}; + +ðernet1 { + phy-handle = <&hsgmii_phy1>; + phy-mode = "2500base-x"; + + snps,mtl-rx-config = <&mtl_rx_setup1>; + snps,mtl-tx-config = <&mtl_tx_setup1>; + snps,ps-speed = <1000>; + + status = "okay"; + + mtl_rx_setup1: rx-queues-config { + snps,rx-queues-to-use = <4>; + snps,rx-sched-sp; + + queue0 { + snps,dcb-algorithm; + snps,map-to-dma-channel = <0x0>; + snps,route-up; + snps,priority = <0x1>; + }; + + queue1 { + snps,dcb-algorithm; + snps,map-to-dma-channel = <0x1>; + snps,route-ptp; + }; + + queue2 { + snps,avb-algorithm; + snps,map-to-dma-channel = <0x2>; + snps,route-avcp; + }; + + queue3 { + snps,avb-algorithm; + snps,map-to-dma-channel = <0x3>; + snps,priority = <0xc>; + }; + }; + + mtl_tx_setup1: tx-queues-config { + snps,tx-queues-to-use = <4>; + + queue0 { + snps,dcb-algorithm; + }; + + queue1 { + snps,dcb-algorithm; + }; + + queue2 { + snps,avb-algorithm; + snps,send_slope = <0x1000>; + snps,idle_slope = <0x1000>; + snps,high_credit = <0x3e800>; + snps,low_credit = <0xffc18000>; + }; + + queue3 { + snps,avb-algorithm; + snps,send_slope = <0x1000>; + snps,idle_slope = <0x1000>; + snps,high_credit = <0x3e800>; + snps,low_credit = <0xffc18000>; + }; + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/sa8775p-ride-r3.dts b/arch/arm64/boot/dts/qcom/sa8775p-ride-r3.dts index ae065ae92478..a7f377dc4733 100644 --- a/arch/arm64/boot/dts/qcom/sa8775p-ride-r3.dts +++ b/arch/arm64/boot/dts/qcom/sa8775p-ride-r3.dts @@ -6,42 +6,9 @@ /dts-v1/; #include "sa8775p-ride.dtsi" +#include "lemans-ride-ethernet-aqr115c.dtsi" / { model = "Qualcomm SA8775P Ride Rev3"; compatible = "qcom,sa8775p-ride-r3", "qcom,sa8775p"; }; - -ðernet0 { - phy-mode = "2500base-x"; -}; - -ðernet1 { - phy-mode = "2500base-x"; -}; - -&mdio { - compatible = "snps,dwmac-mdio"; - #address-cells = <1>; - #size-cells = <0>; - - sgmii_phy0: phy@8 { - compatible = "ethernet-phy-id31c3.1c33"; - reg = <0x8>; - device_type = "ethernet-phy"; - interrupts-extended = <&tlmm 7 IRQ_TYPE_EDGE_FALLING>; - reset-gpios = <&pmm8654au_2_gpios 8 GPIO_ACTIVE_LOW>; - reset-assert-us = <11000>; - reset-deassert-us = <70000>; - }; - - sgmii_phy1: phy@0 { - compatible = "ethernet-phy-id31c3.1c33"; - reg = <0x0>; - device_type = "ethernet-phy"; - interrupts-extended = <&tlmm 26 IRQ_TYPE_EDGE_FALLING>; - reset-gpios = <&pmm8654au_2_gpios 9 GPIO_ACTIVE_LOW>; - reset-assert-us = <11000>; - reset-deassert-us = <70000>; - }; -}; diff --git a/arch/arm64/boot/dts/qcom/sa8775p-ride.dts b/arch/arm64/boot/dts/qcom/sa8775p-ride.dts index 2e87fd760dbd..b765794f7e54 100644 --- a/arch/arm64/boot/dts/qcom/sa8775p-ride.dts +++ b/arch/arm64/boot/dts/qcom/sa8775p-ride.dts @@ -6,42 +6,9 @@ /dts-v1/; #include "sa8775p-ride.dtsi" +#include "lemans-ride-ethernet-88ea1512.dtsi" / { model = "Qualcomm SA8775P Ride"; compatible = "qcom,sa8775p-ride", "qcom,sa8775p"; }; - -ðernet0 { - phy-mode = "sgmii"; -}; - -ðernet1 { - phy-mode = "sgmii"; -}; - -&mdio { - compatible = "snps,dwmac-mdio"; - #address-cells = <1>; - #size-cells = <0>; - - sgmii_phy0: phy@8 { - compatible = "ethernet-phy-id0141.0dd4"; - reg = <0x8>; - device_type = "ethernet-phy"; - interrupts-extended = <&tlmm 7 IRQ_TYPE_EDGE_FALLING>; - reset-gpios = <&pmm8654au_2_gpios 8 GPIO_ACTIVE_LOW>; - reset-assert-us = <11000>; - reset-deassert-us = <70000>; - }; - - sgmii_phy1: phy@a { - compatible = "ethernet-phy-id0141.0dd4"; - reg = <0xa>; - device_type = "ethernet-phy"; - interrupts-extended = <&tlmm 26 IRQ_TYPE_EDGE_FALLING>; - reset-gpios = <&pmm8654au_2_gpios 9 GPIO_ACTIVE_LOW>; - reset-assert-us = <11000>; - reset-deassert-us = <70000>; - }; -}; diff --git a/arch/arm64/boot/dts/qcom/sa8775p-ride.dtsi b/arch/arm64/boot/dts/qcom/sa8775p-ride.dtsi index a9ec6ded412e..f512363f6222 100644 --- a/arch/arm64/boot/dts/qcom/sa8775p-ride.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8775p-ride.dtsi @@ -13,8 +13,6 @@ / { aliases { - ethernet0 = ðernet0; - ethernet1 = ðernet1; i2c11 = &i2c11; i2c18 = &i2c18; serial0 = &uart10; @@ -443,151 +441,6 @@ vreg_l8e: ldo8 { }; }; -ðernet0 { - phy-handle = <&sgmii_phy0>; - - pinctrl-0 = <ðernet0_default>; - pinctrl-names = "default"; - - snps,mtl-rx-config = <&mtl_rx_setup>; - snps,mtl-tx-config = <&mtl_tx_setup>; - snps,ps-speed = <1000>; - - status = "okay"; - - mdio: mdio { - compatible = "snps,dwmac-mdio"; - #address-cells = <1>; - #size-cells = <0>; - }; - - mtl_rx_setup: rx-queues-config { - snps,rx-queues-to-use = <4>; - snps,rx-sched-sp; - - queue0 { - snps,dcb-algorithm; - snps,map-to-dma-channel = <0x0>; - snps,route-up; - snps,priority = <0x1>; - }; - - queue1 { - snps,dcb-algorithm; - snps,map-to-dma-channel = <0x1>; - snps,route-ptp; - }; - - queue2 { - snps,avb-algorithm; - snps,map-to-dma-channel = <0x2>; - snps,route-avcp; - }; - - queue3 { - snps,avb-algorithm; - snps,map-to-dma-channel = <0x3>; - snps,priority = <0xc>; - }; - }; - - mtl_tx_setup: tx-queues-config { - snps,tx-queues-to-use = <4>; - - queue0 { - snps,dcb-algorithm; - }; - - queue1 { - snps,dcb-algorithm; - }; - - queue2 { - snps,avb-algorithm; - snps,send_slope = <0x1000>; - snps,idle_slope = <0x1000>; - snps,high_credit = <0x3e800>; - snps,low_credit = <0xffc18000>; - }; - - queue3 { - snps,avb-algorithm; - snps,send_slope = <0x1000>; - snps,idle_slope = <0x1000>; - snps,high_credit = <0x3e800>; - snps,low_credit = <0xffc18000>; - }; - }; -}; - -ðernet1 { - phy-handle = <&sgmii_phy1>; - - snps,mtl-rx-config = <&mtl_rx_setup1>; - snps,mtl-tx-config = <&mtl_tx_setup1>; - snps,ps-speed = <1000>; - - status = "okay"; - - mtl_rx_setup1: rx-queues-config { - snps,rx-queues-to-use = <4>; - snps,rx-sched-sp; - - queue0 { - snps,dcb-algorithm; - snps,map-to-dma-channel = <0x0>; - snps,route-up; - snps,priority = <0x1>; - }; - - queue1 { - snps,dcb-algorithm; - snps,map-to-dma-channel = <0x1>; - snps,route-ptp; - }; - - queue2 { - snps,avb-algorithm; - snps,map-to-dma-channel = <0x2>; - snps,route-avcp; - }; - - queue3 { - snps,avb-algorithm; - snps,map-to-dma-channel = <0x3>; - snps,priority = <0xc>; - }; - }; - - mtl_tx_setup1: tx-queues-config { - snps,tx-queues-to-use = <4>; - - queue0 { - snps,dcb-algorithm; - }; - - queue1 { - snps,dcb-algorithm; - }; - - queue2 { - snps,avb-algorithm; - snps,send_slope = <0x1000>; - snps,idle_slope = <0x1000>; - snps,high_credit = <0x3e800>; - snps,low_credit = <0xffc18000>; - }; - - queue3 { - snps,avb-algorithm; - snps,send_slope = <0x1000>; - snps,idle_slope = <0x1000>; - snps,high_credit = <0x3e800>; - snps,low_credit = <0xffc18000>; - }; - }; -}; - &i2c11 { clock-frequency = <400000>; status = "okay"; @@ -960,22 +813,6 @@ dp1_hot_plug_det: dp1-hot-plug-det-state { bias-disable; }; - ethernet0_default: ethernet0-default-state { - ethernet0_mdc: ethernet0-mdc-pins { - pins = "gpio8"; - function = "emac0_mdc"; - drive-strength = <16>; - bias-pull-up; - }; - - ethernet0_mdio: ethernet0-mdio-pins { - pins = "gpio9"; - function = "emac0_mdio"; - drive-strength = <16>; - bias-pull-up; - }; - }; - io_expander_intr_active: io-expander-intr-active-state { pins = "gpio98"; function = "gpio"; From 76326da895b889f7f0b20e5ba5cc47b836521f44 Mon Sep 17 00:00:00 2001 From: Wasim Nazir Date: Sun, 3 Aug 2025 16:31:08 +0530 Subject: [PATCH 00097/11391] arm64: dts: qcom: lemans: Refactor ride/ride-r3 boards based on daughter cards Ride/Ride-r3 boards used with lemans and derivatives: - Are composed of multiple daughter cards (SoC-card, display, camera, ethernet, pcie, sensor, front & backplane, WLAN & BT). - Across lemans & its derivatives, SoM is changing. - Across Ride & Ride-r3 board, ethernet card is changing. Excluding the differences all other cards i.e SoC-card, display, camera, PCIe, sensor, front & backplane are same across Ride/Ride-r3 boards used with lemans and derivatives. Describe all the common cards in lemans-ride-common so that it can be reused for all the variants of ride & ride-r3 platforms in lemans and derivatives. Nacked-by: Krzysztof Kozlowski Signed-off-by: Wasim Nazir Link: https://lore.kernel.org/r/20250803110113.401927-5-wasim.nazir@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- .../dts/qcom/{sa8775p-ride.dtsi => lemans-ride-common.dtsi} | 5 ----- arch/arm64/boot/dts/qcom/sa8775p-ride-r3.dts | 5 ++++- arch/arm64/boot/dts/qcom/sa8775p-ride.dts | 5 ++++- 3 files changed, 8 insertions(+), 7 deletions(-) rename arch/arm64/boot/dts/qcom/{sa8775p-ride.dtsi => lemans-ride-common.dtsi} (99%) diff --git a/arch/arm64/boot/dts/qcom/sa8775p-ride.dtsi b/arch/arm64/boot/dts/qcom/lemans-ride-common.dtsi similarity index 99% rename from arch/arm64/boot/dts/qcom/sa8775p-ride.dtsi rename to arch/arm64/boot/dts/qcom/lemans-ride-common.dtsi index f512363f6222..25e756c14160 100644 --- a/arch/arm64/boot/dts/qcom/sa8775p-ride.dtsi +++ b/arch/arm64/boot/dts/qcom/lemans-ride-common.dtsi @@ -3,14 +3,9 @@ * Copyright (c) 2023, Linaro Limited */ -/dts-v1/; - #include #include -#include "lemans-auto.dtsi" -#include "sa8775p-pmics.dtsi" - / { aliases { i2c11 = &i2c11; diff --git a/arch/arm64/boot/dts/qcom/sa8775p-ride-r3.dts b/arch/arm64/boot/dts/qcom/sa8775p-ride-r3.dts index a7f377dc4733..3e19ff5e061f 100644 --- a/arch/arm64/boot/dts/qcom/sa8775p-ride-r3.dts +++ b/arch/arm64/boot/dts/qcom/sa8775p-ride-r3.dts @@ -5,7 +5,10 @@ /dts-v1/; -#include "sa8775p-ride.dtsi" +#include "lemans-auto.dtsi" + +#include "sa8775p-pmics.dtsi" +#include "lemans-ride-common.dtsi" #include "lemans-ride-ethernet-aqr115c.dtsi" / { diff --git a/arch/arm64/boot/dts/qcom/sa8775p-ride.dts b/arch/arm64/boot/dts/qcom/sa8775p-ride.dts index b765794f7e54..68a99582b538 100644 --- a/arch/arm64/boot/dts/qcom/sa8775p-ride.dts +++ b/arch/arm64/boot/dts/qcom/sa8775p-ride.dts @@ -5,7 +5,10 @@ /dts-v1/; -#include "sa8775p-ride.dtsi" +#include "lemans-auto.dtsi" + +#include "sa8775p-pmics.dtsi" +#include "lemans-ride-common.dtsi" #include "lemans-ride-ethernet-88ea1512.dtsi" / { From d39e1d737bdb0242e1d70345bb1ecfc8382289ce Mon Sep 17 00:00:00 2001 From: Wasim Nazir Date: Sun, 3 Aug 2025 16:31:09 +0530 Subject: [PATCH 00098/11391] arm64: dts: qcom: lemans: Rename sa8775p-pmics.dtsi to lemans-pmics.dtsi The existing PMIC DTSI file is named sa8775p-pmics.dtsi, which does not align with the updated naming convention for Lemans platform components. This inconsistency can lead to confusion and misalignment with other platform-specific files. Rename the file to lemans-pmics.dtsi to reflect the platform naming convention and improve clarity. Signed-off-by: Wasim Nazir Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250803110113.401927-6-wasim.nazir@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/{sa8775p-pmics.dtsi => lemans-pmics.dtsi} | 0 arch/arm64/boot/dts/qcom/sa8775p-ride-r3.dts | 2 +- arch/arm64/boot/dts/qcom/sa8775p-ride.dts | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename arch/arm64/boot/dts/qcom/{sa8775p-pmics.dtsi => lemans-pmics.dtsi} (100%) diff --git a/arch/arm64/boot/dts/qcom/sa8775p-pmics.dtsi b/arch/arm64/boot/dts/qcom/lemans-pmics.dtsi similarity index 100% rename from arch/arm64/boot/dts/qcom/sa8775p-pmics.dtsi rename to arch/arm64/boot/dts/qcom/lemans-pmics.dtsi diff --git a/arch/arm64/boot/dts/qcom/sa8775p-ride-r3.dts b/arch/arm64/boot/dts/qcom/sa8775p-ride-r3.dts index 3e19ff5e061f..b25f0b2c9410 100644 --- a/arch/arm64/boot/dts/qcom/sa8775p-ride-r3.dts +++ b/arch/arm64/boot/dts/qcom/sa8775p-ride-r3.dts @@ -7,7 +7,7 @@ #include "lemans-auto.dtsi" -#include "sa8775p-pmics.dtsi" +#include "lemans-pmics.dtsi" #include "lemans-ride-common.dtsi" #include "lemans-ride-ethernet-aqr115c.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sa8775p-ride.dts b/arch/arm64/boot/dts/qcom/sa8775p-ride.dts index 68a99582b538..2d9028cd60be 100644 --- a/arch/arm64/boot/dts/qcom/sa8775p-ride.dts +++ b/arch/arm64/boot/dts/qcom/sa8775p-ride.dts @@ -7,7 +7,7 @@ #include "lemans-auto.dtsi" -#include "sa8775p-pmics.dtsi" +#include "lemans-pmics.dtsi" #include "lemans-ride-common.dtsi" #include "lemans-ride-ethernet-88ea1512.dtsi" From b4feac9e034fe1a609619cb7feb55217fd5d6583 Mon Sep 17 00:00:00 2001 From: Wasim Nazir Date: Sun, 3 Aug 2025 16:31:10 +0530 Subject: [PATCH 00099/11391] arm64: dts: qcom: lemans: Fix dts inclusion for IoT boards and update memory map IoT boards currently inherit the automotive memory map, which is not suitable for their configuration. This leads to incorrect memory layout and inclusion of unnecessary carveouts. Use lemans.dtsi as the base for IoT boards to apply the correct memory map. Include additional DTSI files as needed to complete the board configuration. Update 'model' string to represent these boards as 'lemans'. Signed-off-by: Wasim Nazir Link: https://lore.kernel.org/r/20250803110113.401927-7-wasim.nazir@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/qcs9100-ride-r3.dts | 9 +++++++-- arch/arm64/boot/dts/qcom/qcs9100-ride.dts | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/qcs9100-ride-r3.dts b/arch/arm64/boot/dts/qcom/qcs9100-ride-r3.dts index 759d1ec694b2..7fc2de0d3d5e 100644 --- a/arch/arm64/boot/dts/qcom/qcs9100-ride-r3.dts +++ b/arch/arm64/boot/dts/qcom/qcs9100-ride-r3.dts @@ -4,8 +4,13 @@ */ /dts-v1/; -#include "sa8775p-ride-r3.dts" +#include "lemans.dtsi" +#include "lemans-pmics.dtsi" + +#include "lemans-ride-common.dtsi" +#include "lemans-ride-ethernet-aqr115c.dtsi" + / { - model = "Qualcomm QCS9100 Ride Rev3"; + model = "Qualcomm Technologies, Inc. Lemans Ride Rev3"; compatible = "qcom,qcs9100-ride-r3", "qcom,qcs9100", "qcom,sa8775p"; }; diff --git a/arch/arm64/boot/dts/qcom/qcs9100-ride.dts b/arch/arm64/boot/dts/qcom/qcs9100-ride.dts index 979462dfec30..b0c5fdde56ae 100644 --- a/arch/arm64/boot/dts/qcom/qcs9100-ride.dts +++ b/arch/arm64/boot/dts/qcom/qcs9100-ride.dts @@ -4,8 +4,13 @@ */ /dts-v1/; -#include "sa8775p-ride.dts" +#include "lemans.dtsi" +#include "lemans-pmics.dtsi" + +#include "lemans-ride-common.dtsi" +#include "lemans-ride-ethernet-88ea1512.dtsi" + / { - model = "Qualcomm QCS9100 Ride"; + model = "Qualcomm Technologies, Inc. Lemans Ride"; compatible = "qcom,qcs9100-ride", "qcom,qcs9100", "qcom,sa8775p"; }; From e9d84a1f8bfe85b6c406c4a088e537d4a5f83a87 Mon Sep 17 00:00:00 2001 From: Wasim Nazir Date: Sun, 3 Aug 2025 16:31:11 +0530 Subject: [PATCH 00100/11391] dt-bindings: arm: qcom: lemans: Add bindings for Lemans Evaluation Kit (EVK) Introduce new bindings for the Lemans EVK, an IoT board without safety features. Signed-off-by: Wasim Nazir Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250803110113.401927-8-wasim.nazir@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/arm/qcom.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml index ae43b3556580..bf5f3beb320b 100644 --- a/Documentation/devicetree/bindings/arm/qcom.yaml +++ b/Documentation/devicetree/bindings/arm/qcom.yaml @@ -969,6 +969,7 @@ properties: - items: - enum: + - qcom,lemans-evk - qcom,qcs9100-ride - qcom,qcs9100-ride-r3 - const: qcom,qcs9100 From 99ea5a0d6bc820b15727cea006561ede7339bb79 Mon Sep 17 00:00:00 2001 From: Wasim Nazir Date: Sun, 3 Aug 2025 16:31:12 +0530 Subject: [PATCH 00101/11391] arm64: dts: qcom: Add lemans evaluation kit (EVK) initial board support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lemans EVK is an IoT board without safety monitoring feature of Safety Island(SAIL) subsystem. Lemans EVK is single board supporting these peripherals: - Storage: 2 × 128 GB UFS, micro-SD card, EEPROMs for MACs, eMMC on mezzanine card - Audio/Video, Camera & Display ports - Connectivity: RJ45 2.5GbE, WLAN/Bluetooth, CAN/CAN-FD - Sensors: IMU - PCIe ports - USB & UART ports On top of lemans EVK board additional mezzanine boards can be stacked in future. Implement basic features like uart/ufs to enable 'boot to shell'. Co-developed-by: Rakesh Kota Signed-off-by: Rakesh Kota Co-developed-by: Sayali Lokhande Signed-off-by: Sayali Lokhande Reviewed-by: Konrad Dybcio Signed-off-by: Wasim Nazir Link: https://lore.kernel.org/r/20250803110113.401927-9-wasim.nazir@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/Makefile | 1 + arch/arm64/boot/dts/qcom/lemans-evk.dts | 291 ++++++++++++++++++++++++ 2 files changed, 292 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/lemans-evk.dts diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 4bfa926b6a08..dcc0f6382f51 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -29,6 +29,7 @@ dtb-$(CONFIG_ARCH_QCOM) += ipq9574-rdp433.dtb dtb-$(CONFIG_ARCH_QCOM) += ipq9574-rdp449.dtb dtb-$(CONFIG_ARCH_QCOM) += ipq9574-rdp453.dtb dtb-$(CONFIG_ARCH_QCOM) += ipq9574-rdp454.dtb +dtb-$(CONFIG_ARCH_QCOM) += lemans-evk.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8216-samsung-fortuna3g.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8916-acer-a1-724.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8916-alcatel-idol347.dtb diff --git a/arch/arm64/boot/dts/qcom/lemans-evk.dts b/arch/arm64/boot/dts/qcom/lemans-evk.dts new file mode 100644 index 000000000000..669ac52f4cf6 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/lemans-evk.dts @@ -0,0 +1,291 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2024-2025, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +/dts-v1/; + +#include +#include + +#include "lemans.dtsi" +#include "lemans-pmics.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lemans EVK"; + compatible = "qcom,lemans-evk", "qcom,qcs9100", "qcom,sa8775p"; + + aliases { + serial0 = &uart10; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; +}; + +&apps_rsc { + regulators-0 { + compatible = "qcom,pmm8654au-rpmh-regulators"; + qcom,pmic-id = "a"; + + vreg_s4a: smps4 { + regulator-name = "vreg_s4a"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1816000>; + regulator-initial-mode = ; + }; + + vreg_s5a: smps5 { + regulator-name = "vreg_s5a"; + regulator-min-microvolt = <1850000>; + regulator-max-microvolt = <1996000>; + regulator-initial-mode = ; + }; + + vreg_s9a: smps9 { + regulator-name = "vreg_s9a"; + regulator-min-microvolt = <535000>; + regulator-max-microvolt = <1120000>; + regulator-initial-mode = ; + }; + + vreg_l4a: ldo4 { + regulator-name = "vreg_l4a"; + regulator-min-microvolt = <788000>; + regulator-max-microvolt = <1050000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l5a: ldo5 { + regulator-name = "vreg_l5a"; + regulator-min-microvolt = <870000>; + regulator-max-microvolt = <950000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l6a: ldo6 { + regulator-name = "vreg_l6a"; + regulator-min-microvolt = <870000>; + regulator-max-microvolt = <970000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l7a: ldo7 { + regulator-name = "vreg_l7a"; + regulator-min-microvolt = <720000>; + regulator-max-microvolt = <950000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l8a: ldo8 { + regulator-name = "vreg_l8a"; + regulator-min-microvolt = <2504000>; + regulator-max-microvolt = <3300000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l9a: ldo9 { + regulator-name = "vreg_l9a"; + regulator-min-microvolt = <2970000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-1 { + compatible = "qcom,pmm8654au-rpmh-regulators"; + qcom,pmic-id = "c"; + + vreg_l1c: ldo1 { + regulator-name = "vreg_l1c"; + regulator-min-microvolt = <1140000>; + regulator-max-microvolt = <1260000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l2c: ldo2 { + regulator-name = "vreg_l2c"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1100000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l3c: ldo3 { + regulator-name = "vreg_l3c"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1300000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l4c: ldo4 { + regulator-name = "vreg_l4c"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l5c: ldo5 { + regulator-name = "vreg_l5c"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1300000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l6c: ldo6 { + regulator-name = "vreg_l6c"; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <1980000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l7c: ldo7 { + regulator-name = "vreg_l7c"; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l8c: ldo8 { + regulator-name = "vreg_l8c"; + regulator-min-microvolt = <2400000>; + regulator-max-microvolt = <3300000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l9c: ldo9 { + regulator-name = "vreg_l9c"; + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <2700000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-2 { + compatible = "qcom,pmm8654au-rpmh-regulators"; + qcom,pmic-id = "e"; + + vreg_s4e: smps4 { + regulator-name = "vreg_s4e"; + regulator-min-microvolt = <970000>; + regulator-max-microvolt = <1520000>; + regulator-initial-mode = ; + }; + + vreg_s7e: smps7 { + regulator-name = "vreg_s7e"; + regulator-min-microvolt = <1010000>; + regulator-max-microvolt = <1170000>; + regulator-initial-mode = ; + }; + + vreg_s9e: smps9 { + regulator-name = "vreg_s9e"; + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <570000>; + regulator-initial-mode = ; + }; + + vreg_l6e: ldo6 { + regulator-name = "vreg_l6e"; + regulator-min-microvolt = <1280000>; + regulator-max-microvolt = <1450000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l8e: ldo8 { + regulator-name = "vreg_l8e"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1950000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; +}; + +&qupv3_id_1 { + status = "okay"; +}; + +&sleep_clk { + clock-frequency = <32768>; +}; + +&uart10 { + compatible = "qcom,geni-debug-uart"; + pinctrl-0 = <&qup_uart10_default>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&ufs_mem_hc { + reset-gpios = <&tlmm 149 GPIO_ACTIVE_LOW>; + vcc-supply = <&vreg_l8a>; + vcc-max-microamp = <1100000>; + vccq-supply = <&vreg_l4c>; + vccq-max-microamp = <1200000>; + + status = "okay"; +}; + +&ufs_mem_phy { + vdda-phy-supply = <&vreg_l4a>; + vdda-pll-supply = <&vreg_l1c>; + + status = "okay"; +}; + +&xo_board_clk { + clock-frequency = <38400000>; +}; From 684339e80a9392cf8d331479d0942682ba0bb5ac Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Fri, 1 Aug 2025 15:07:27 -0500 Subject: [PATCH 00102/11391] dt-bindings: PCI: Add missing "#address-cells" to interrupt controllers An interrupt-controller node which is the parent provider for "interrupt-map" needs an "#address-cells" property. This fixes "interrupt_map" warnings in new dtc. Acked-by: Bjorn Helgaas Link: https://lore.kernel.org/r/20250801200728.3252036-2-robh@kernel.org Signed-off-by: Rob Herring (Arm) --- Documentation/devicetree/bindings/pci/brcm,iproc-pcie.yaml | 1 + .../devicetree/bindings/pci/marvell,armada-3700-pcie.yaml | 4 ++++ .../devicetree/bindings/pci/marvell,kirkwood-pcie.yaml | 3 +++ .../devicetree/bindings/pci/socionext,uniphier-pcie.yaml | 4 ++++ Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml | 3 +++ 5 files changed, 15 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/brcm,iproc-pcie.yaml b/Documentation/devicetree/bindings/pci/brcm,iproc-pcie.yaml index 5434c144d2ec..18e7981241b5 100644 --- a/Documentation/devicetree/bindings/pci/brcm,iproc-pcie.yaml +++ b/Documentation/devicetree/bindings/pci/brcm,iproc-pcie.yaml @@ -108,6 +108,7 @@ examples: #include gic: interrupt-controller { + #address-cells = <0>; interrupt-controller; #interrupt-cells = <3>; }; diff --git a/Documentation/devicetree/bindings/pci/marvell,armada-3700-pcie.yaml b/Documentation/devicetree/bindings/pci/marvell,armada-3700-pcie.yaml index 68090b3ca419..8403c79634ed 100644 --- a/Documentation/devicetree/bindings/pci/marvell,armada-3700-pcie.yaml +++ b/Documentation/devicetree/bindings/pci/marvell,armada-3700-pcie.yaml @@ -42,6 +42,9 @@ properties: additionalProperties: false properties: + '#address-cells': + const: 0 + interrupt-controller: true '#interrupt-cells': @@ -92,6 +95,7 @@ examples: reset-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>; pcie_intc: interrupt-controller { + #address-cells = <0>; interrupt-controller; #interrupt-cells = <1>; }; diff --git a/Documentation/devicetree/bindings/pci/marvell,kirkwood-pcie.yaml b/Documentation/devicetree/bindings/pci/marvell,kirkwood-pcie.yaml index 7be695320ddf..3d68bfbe6feb 100644 --- a/Documentation/devicetree/bindings/pci/marvell,kirkwood-pcie.yaml +++ b/Documentation/devicetree/bindings/pci/marvell,kirkwood-pcie.yaml @@ -101,6 +101,9 @@ patternProperties: additionalProperties: false properties: + '#address-cells': + const: 0 + interrupt-controller: true '#interrupt-cells': diff --git a/Documentation/devicetree/bindings/pci/socionext,uniphier-pcie.yaml b/Documentation/devicetree/bindings/pci/socionext,uniphier-pcie.yaml index 638b99db0433..c07b0ed51613 100644 --- a/Documentation/devicetree/bindings/pci/socionext,uniphier-pcie.yaml +++ b/Documentation/devicetree/bindings/pci/socionext,uniphier-pcie.yaml @@ -56,6 +56,9 @@ properties: additionalProperties: false properties: + '#address-cells': + const: 0 + interrupt-controller: true '#interrupt-cells': @@ -109,6 +112,7 @@ examples: <0 0 0 4 &pcie_intc 3>; pcie_intc: interrupt-controller { + #address-cells = <0>; interrupt-controller; #interrupt-cells = <1>; interrupt-parent = <&gic>; diff --git a/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml b/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml index 69b499c96c71..c704099f134b 100644 --- a/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml +++ b/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml @@ -99,6 +99,9 @@ properties: additionalProperties: false properties: + '#address-cells': + const: 0 + interrupt-controller: true '#interrupt-cells': From 5225c689dd9048b67ddf3044da68cc17ab1aa04e Mon Sep 17 00:00:00 2001 From: Ali Nasrolahi Date: Thu, 24 Jul 2025 21:28:19 +0330 Subject: [PATCH 00103/11391] 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 00104/11391] 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 00105/11391] 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 00106/11391] 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 @@ signed int rtw_set_auth(struct adapter *adapter, struct security_priv *psecurity 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 00107/11391] 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 00108/11391] 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 00109/11391] 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 00110/11391] 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 00111/11391] 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 00112/11391] 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 00113/11391] 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 00114/11391] 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 00115/11391] 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 00116/11391] 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 00117/11391] 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 00118/11391] 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 432418bf27ababad360d4c07d2efcd235107a971 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Mon, 21 Jul 2025 04:44:49 +0000 Subject: [PATCH 00119/11391] platform/chrome: cros_ec_chardev: Remove redundant struct field `ec_dev` in the `struct chardev_data` is unused. Remove the field and the whole struct as well. Link: https://lore.kernel.org/r/20250721044456.2736300-2-tzungbi@kernel.org Signed-off-by: Tzung-Bi Shih --- drivers/platform/chrome/cros_ec_chardev.c | 28 +++++++++-------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_chardev.c b/drivers/platform/chrome/cros_ec_chardev.c index 21a484385fc5..5c858d30dd52 100644 --- a/drivers/platform/chrome/cros_ec_chardev.c +++ b/drivers/platform/chrome/cros_ec_chardev.c @@ -31,11 +31,6 @@ /* Arbitrary bounded size for the event queue */ #define CROS_MAX_EVENT_LEN PAGE_SIZE -struct chardev_data { - struct cros_ec_dev *ec_dev; - struct miscdevice misc; -}; - struct chardev_priv { struct cros_ec_dev *ec_dev; struct notifier_block notifier; @@ -379,29 +374,28 @@ static int cros_ec_chardev_probe(struct platform_device *pdev) { struct cros_ec_dev *ec_dev = dev_get_drvdata(pdev->dev.parent); struct cros_ec_platform *ec_platform = dev_get_platdata(ec_dev->dev); - struct chardev_data *data; + struct miscdevice *misc; /* Create a char device: we want to create it anew */ - data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); - if (!data) + misc = devm_kzalloc(&pdev->dev, sizeof(*misc), GFP_KERNEL); + if (!misc) return -ENOMEM; - data->ec_dev = ec_dev; - data->misc.minor = MISC_DYNAMIC_MINOR; - data->misc.fops = &chardev_fops; - data->misc.name = ec_platform->ec_name; - data->misc.parent = pdev->dev.parent; + misc->minor = MISC_DYNAMIC_MINOR; + misc->fops = &chardev_fops; + misc->name = ec_platform->ec_name; + misc->parent = pdev->dev.parent; - dev_set_drvdata(&pdev->dev, data); + dev_set_drvdata(&pdev->dev, misc); - return misc_register(&data->misc); + return misc_register(misc); } static void cros_ec_chardev_remove(struct platform_device *pdev) { - struct chardev_data *data = dev_get_drvdata(&pdev->dev); + struct miscdevice *misc = dev_get_drvdata(&pdev->dev); - misc_deregister(&data->misc); + misc_deregister(misc); } static const struct platform_device_id cros_ec_chardev_id[] = { From 032c59c1d3cd456053339fb95f6ee8e68c5ad1e2 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Mon, 21 Jul 2025 04:44:51 +0000 Subject: [PATCH 00120/11391] platform/chrome: cros_ec_chardev: Decouple fops from struct cros_ec_dev The fops doesn't really need to hold a reference to struct cros_ec_dev. Remove the references from the fops. No functional changes. Link: https://lore.kernel.org/r/20250721044456.2736300-4-tzungbi@kernel.org Signed-off-by: Tzung-Bi Shih --- drivers/platform/chrome/cros_ec_chardev.c | 44 +++++++++++------------ 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_chardev.c b/drivers/platform/chrome/cros_ec_chardev.c index 5c858d30dd52..c9d80ad5b57e 100644 --- a/drivers/platform/chrome/cros_ec_chardev.c +++ b/drivers/platform/chrome/cros_ec_chardev.c @@ -32,12 +32,13 @@ #define CROS_MAX_EVENT_LEN PAGE_SIZE struct chardev_priv { - struct cros_ec_dev *ec_dev; + struct cros_ec_device *ec_dev; struct notifier_block notifier; wait_queue_head_t wait_event; unsigned long event_mask; struct list_head events; size_t event_len; + u16 cmd_offset; }; struct ec_event { @@ -47,7 +48,7 @@ struct ec_event { u8 data[]; }; -static int ec_get_version(struct cros_ec_dev *ec, char *str, int maxlen) +static int ec_get_version(struct chardev_priv *priv, char *str, int maxlen) { static const char * const current_image_name[] = { "unknown", "read-only", "read-write", "invalid", @@ -60,10 +61,10 @@ static int ec_get_version(struct cros_ec_dev *ec, char *str, int maxlen) if (!msg) return -ENOMEM; - msg->command = EC_CMD_GET_VERSION + ec->cmd_offset; + msg->command = EC_CMD_GET_VERSION + priv->cmd_offset; msg->insize = sizeof(*resp); - ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); + ret = cros_ec_cmd_xfer_status(priv->ec_dev, msg); if (ret < 0) { snprintf(str, maxlen, "Unknown EC version, returned error: %d\n", @@ -91,7 +92,7 @@ static int cros_ec_chardev_mkbp_event(struct notifier_block *nb, { struct chardev_priv *priv = container_of(nb, struct chardev_priv, notifier); - struct cros_ec_device *ec_dev = priv->ec_dev->ec_dev; + struct cros_ec_device *ec_dev = priv->ec_dev; struct ec_event *event; unsigned long event_bit = 1 << ec_dev->event_data.event_type; int total_size = sizeof(*event) + ec_dev->event_size; @@ -156,7 +157,8 @@ static struct ec_event *cros_ec_chardev_fetch_event(struct chardev_priv *priv, static int cros_ec_chardev_open(struct inode *inode, struct file *filp) { struct miscdevice *mdev = filp->private_data; - struct cros_ec_dev *ec_dev = dev_get_drvdata(mdev->parent); + struct cros_ec_dev *ec = dev_get_drvdata(mdev->parent); + struct cros_ec_device *ec_dev = ec->ec_dev; struct chardev_priv *priv; int ret; @@ -165,13 +167,14 @@ static int cros_ec_chardev_open(struct inode *inode, struct file *filp) return -ENOMEM; priv->ec_dev = ec_dev; + priv->cmd_offset = ec->cmd_offset; filp->private_data = priv; INIT_LIST_HEAD(&priv->events); init_waitqueue_head(&priv->wait_event); nonseekable_open(inode, filp); priv->notifier.notifier_call = cros_ec_chardev_mkbp_event; - ret = blocking_notifier_chain_register(&ec_dev->ec_dev->event_notifier, + ret = blocking_notifier_chain_register(&ec_dev->event_notifier, &priv->notifier); if (ret) { dev_err(ec_dev->dev, "failed to register event notifier\n"); @@ -199,7 +202,6 @@ static ssize_t cros_ec_chardev_read(struct file *filp, char __user *buffer, char msg[sizeof(struct ec_response_get_version) + sizeof(CROS_EC_DEV_VERSION)]; struct chardev_priv *priv = filp->private_data; - struct cros_ec_dev *ec_dev = priv->ec_dev; size_t count; int ret; @@ -233,7 +235,7 @@ static ssize_t cros_ec_chardev_read(struct file *filp, char __user *buffer, if (*offset != 0) return 0; - ret = ec_get_version(ec_dev, msg, sizeof(msg)); + ret = ec_get_version(priv, msg, sizeof(msg)); if (ret) return ret; @@ -249,10 +251,10 @@ static ssize_t cros_ec_chardev_read(struct file *filp, char __user *buffer, static int cros_ec_chardev_release(struct inode *inode, struct file *filp) { struct chardev_priv *priv = filp->private_data; - struct cros_ec_dev *ec_dev = priv->ec_dev; + struct cros_ec_device *ec_dev = priv->ec_dev; struct ec_event *event, *e; - blocking_notifier_chain_unregister(&ec_dev->ec_dev->event_notifier, + blocking_notifier_chain_unregister(&ec_dev->event_notifier, &priv->notifier); list_for_each_entry_safe(event, e, &priv->events, node) { @@ -267,7 +269,7 @@ static int cros_ec_chardev_release(struct inode *inode, struct file *filp) /* * Ioctls */ -static long cros_ec_chardev_ioctl_xcmd(struct cros_ec_dev *ec, void __user *arg) +static long cros_ec_chardev_ioctl_xcmd(struct chardev_priv *priv, void __user *arg) { struct cros_ec_command *s_cmd; struct cros_ec_command u_cmd; @@ -296,8 +298,8 @@ static long cros_ec_chardev_ioctl_xcmd(struct cros_ec_dev *ec, void __user *arg) goto exit; } - s_cmd->command += ec->cmd_offset; - ret = cros_ec_cmd_xfer(ec->ec_dev, s_cmd); + s_cmd->command += priv->cmd_offset; + ret = cros_ec_cmd_xfer(priv->ec_dev, s_cmd); /* Only copy data to userland if data was received. */ if (ret < 0) goto exit; @@ -309,10 +311,9 @@ static long cros_ec_chardev_ioctl_xcmd(struct cros_ec_dev *ec, void __user *arg) return ret; } -static long cros_ec_chardev_ioctl_readmem(struct cros_ec_dev *ec, - void __user *arg) +static long cros_ec_chardev_ioctl_readmem(struct chardev_priv *priv, void __user *arg) { - struct cros_ec_device *ec_dev = ec->ec_dev; + struct cros_ec_device *ec_dev = priv->ec_dev; struct cros_ec_readmem s_mem = { }; long num; @@ -341,16 +342,15 @@ static long cros_ec_chardev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct chardev_priv *priv = filp->private_data; - struct cros_ec_dev *ec = priv->ec_dev; if (_IOC_TYPE(cmd) != CROS_EC_DEV_IOC) return -ENOTTY; switch (cmd) { case CROS_EC_DEV_IOCXCMD: - return cros_ec_chardev_ioctl_xcmd(ec, (void __user *)arg); + return cros_ec_chardev_ioctl_xcmd(priv, (void __user *)arg); case CROS_EC_DEV_IOCRDMEM: - return cros_ec_chardev_ioctl_readmem(ec, (void __user *)arg); + return cros_ec_chardev_ioctl_readmem(priv, (void __user *)arg); case CROS_EC_DEV_IOCEVENTMASK: priv->event_mask = arg; return 0; @@ -372,8 +372,8 @@ static const struct file_operations chardev_fops = { static int cros_ec_chardev_probe(struct platform_device *pdev) { - struct cros_ec_dev *ec_dev = dev_get_drvdata(pdev->dev.parent); - struct cros_ec_platform *ec_platform = dev_get_platdata(ec_dev->dev); + struct cros_ec_dev *ec = dev_get_drvdata(pdev->dev.parent); + struct cros_ec_platform *ec_platform = dev_get_platdata(ec->dev); struct miscdevice *misc; /* Create a char device: we want to create it anew */ From 62498af7b1082d76031f98e4c3d6fb2b9af47772 Mon Sep 17 00:00:00 2001 From: Nicolas Frattaroli Date: Wed, 16 Jul 2025 19:51:22 +0200 Subject: [PATCH 00121/11391] dt-bindings: cpufreq: Add mediatek,mt8196-cpufreq-hw binding The MediaTek MT8196 SoC has new cpufreq hardware, with added memory register ranges to control Dynamic-Voltage-Frequency-Scaling. The DVFS hardware is controlled through a set of registers referred to as "FDVFS". They set the target frequency the DVFS hardware should aim for for each performance domain. Instead of working around the old binding and its already established meanings for the reg items, add a new binding. The FDVFS register memory region is at the beginning, which allows us to easily expand this binding for future SoCs which may have more than 3 performance domains. Signed-off-by: Nicolas Frattaroli Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Rob Herring (Arm) Signed-off-by: Viresh Kumar --- .../cpufreq/mediatek,mt8196-cpufreq-hw.yaml | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 Documentation/devicetree/bindings/cpufreq/mediatek,mt8196-cpufreq-hw.yaml diff --git a/Documentation/devicetree/bindings/cpufreq/mediatek,mt8196-cpufreq-hw.yaml b/Documentation/devicetree/bindings/cpufreq/mediatek,mt8196-cpufreq-hw.yaml new file mode 100644 index 000000000000..5f3c7db3f3aa --- /dev/null +++ b/Documentation/devicetree/bindings/cpufreq/mediatek,mt8196-cpufreq-hw.yaml @@ -0,0 +1,82 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/cpufreq/mediatek,mt8196-cpufreq-hw.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek Hybrid CPUFreq for MT8196/MT6991 series SoCs + +maintainers: + - Nicolas Frattaroli + +description: + MT8196 uses CPUFreq management hardware that supports dynamic voltage + frequency scaling (dvfs), and can support several performance domains. + +properties: + compatible: + const: mediatek,mt8196-cpufreq-hw + + reg: + items: + - description: FDVFS control register region + - description: OPP tables and control for performance domain 0 + - description: OPP tables and control for performance domain 1 + - description: OPP tables and control for performance domain 2 + + "#performance-domain-cells": + const: 1 + +required: + - compatible + - reg + - "#performance-domain-cells" + +additionalProperties: false + +examples: + - | + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a720"; + enable-method = "psci"; + performance-domains = <&performance 0>; + reg = <0x000>; + }; + + /* ... */ + + cpu6: cpu@600 { + device_type = "cpu"; + compatible = "arm,cortex-x4"; + enable-method = "psci"; + performance-domains = <&performance 1>; + reg = <0x600>; + }; + + cpu7: cpu@700 { + device_type = "cpu"; + compatible = "arm,cortex-x925"; + enable-method = "psci"; + performance-domains = <&performance 2>; + reg = <0x700>; + }; + }; + + /* ... */ + + soc { + #address-cells = <2>; + #size-cells = <2>; + + performance: performance-controller@c2c2034 { + compatible = "mediatek,mt8196-cpufreq-hw"; + reg = <0 0xc220400 0 0x20>, <0 0xc2c0f20 0 0x120>, + <0 0xc2c1040 0 0x120>, <0 0xc2c1160 0 0x120>; + #performance-domain-cells = <1>; + }; + }; From 2f5178abb9f5164061b9cbbb5dd860f4d206b03a Mon Sep 17 00:00:00 2001 From: Nicolas Frattaroli Date: Wed, 16 Jul 2025 19:51:23 +0200 Subject: [PATCH 00122/11391] cpufreq: mediatek-hw: Refactor match data into struct While the driver could get away with having the per-compatible match data just be an array of the reg offsets, the only thing it used it for right now, this doesn't really allow it to be extended in any meaningful way if some other per-variant information needs to be communicated. In preparation of adding support for hybrid "FDVFS" for MT8196, refactor the code to make the DT match data a struct, which currently only contains a single member: the reg offsets. This will allow this struct to be extended with other members for other hardware variants. Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Nicolas Frattaroli Signed-off-by: Viresh Kumar --- drivers/cpufreq/mediatek-cpufreq-hw.c | 28 +++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/cpufreq/mediatek-cpufreq-hw.c b/drivers/cpufreq/mediatek-cpufreq-hw.c index 74f1b4c796e4..b2aba1842226 100644 --- a/drivers/cpufreq/mediatek-cpufreq-hw.c +++ b/drivers/cpufreq/mediatek-cpufreq-hw.c @@ -41,15 +41,22 @@ struct mtk_cpufreq_data { struct resource *res; void __iomem *base; int nr_opp; + const struct mtk_cpufreq_variant *variant; }; -static const u16 cpufreq_mtk_offsets[REG_ARRAY_SIZE] = { - [REG_FREQ_LUT_TABLE] = 0x0, - [REG_FREQ_ENABLE] = 0x84, - [REG_FREQ_PERF_STATE] = 0x88, - [REG_FREQ_HW_STATE] = 0x8c, - [REG_EM_POWER_TBL] = 0x90, - [REG_FREQ_LATENCY] = 0x110, +struct mtk_cpufreq_variant { + const u16 reg_offsets[REG_ARRAY_SIZE]; +}; + +static const struct mtk_cpufreq_variant cpufreq_mtk_base_variant = { + .reg_offsets = { + [REG_FREQ_LUT_TABLE] = 0x0, + [REG_FREQ_ENABLE] = 0x84, + [REG_FREQ_PERF_STATE] = 0x88, + [REG_FREQ_HW_STATE] = 0x8c, + [REG_EM_POWER_TBL] = 0x90, + [REG_FREQ_LATENCY] = 0x110, + }, }; static int __maybe_unused @@ -157,7 +164,7 @@ static int mtk_cpu_create_freq_table(struct platform_device *pdev, static int mtk_cpu_resources_init(struct platform_device *pdev, struct cpufreq_policy *policy, - const u16 *offsets) + const struct mtk_cpufreq_variant *variant) { struct mtk_cpufreq_data *data; struct device *dev = &pdev->dev; @@ -200,9 +207,10 @@ static int mtk_cpu_resources_init(struct platform_device *pdev, data->base = base; data->res = res; + data->variant = variant; for (i = REG_FREQ_LUT_TABLE; i < REG_ARRAY_SIZE; i++) - data->reg_bases[i] = base + offsets[i]; + data->reg_bases[i] = base + variant->reg_offsets[i]; ret = mtk_cpu_create_freq_table(pdev, data); if (ret) { @@ -336,7 +344,7 @@ static void mtk_cpufreq_hw_driver_remove(struct platform_device *pdev) } static const struct of_device_id mtk_cpufreq_hw_match[] = { - { .compatible = "mediatek,cpufreq-hw", .data = &cpufreq_mtk_offsets }, + { .compatible = "mediatek,cpufreq-hw", .data = &cpufreq_mtk_base_variant }, {} }; MODULE_DEVICE_TABLE(of, mtk_cpufreq_hw_match); From 35eb6b78854d2e9671ce8ee6b735aa0114c48da8 Mon Sep 17 00:00:00 2001 From: Nicolas Frattaroli Date: Wed, 16 Jul 2025 19:51:24 +0200 Subject: [PATCH 00123/11391] cpufreq: mediatek-hw: Separate per-domain and per-instance data As it stood, the mediatek cpufreq driver could get away with never really having a private driver instance struct. This is because all data was stored in the per-domain structs. However, this complicates matters when actual per-instance data like the variant struct is introduced. Instead of having a pointer to it for every domain, have a pointer to a global "priv" struct that can be extended over time, and rename the "data" struct to "domain" to distinguish its purpose better. Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Nicolas Frattaroli Signed-off-by: Viresh Kumar --- drivers/cpufreq/mediatek-cpufreq-hw.c | 42 +++++++++++++++++---------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/drivers/cpufreq/mediatek-cpufreq-hw.c b/drivers/cpufreq/mediatek-cpufreq-hw.c index b2aba1842226..53611077d0d9 100644 --- a/drivers/cpufreq/mediatek-cpufreq-hw.c +++ b/drivers/cpufreq/mediatek-cpufreq-hw.c @@ -35,13 +35,17 @@ enum { REG_ARRAY_SIZE, }; -struct mtk_cpufreq_data { +struct mtk_cpufreq_priv { + const struct mtk_cpufreq_variant *variant; +}; + +struct mtk_cpufreq_domain { + struct mtk_cpufreq_priv *parent; struct cpufreq_frequency_table *table; void __iomem *reg_bases[REG_ARRAY_SIZE]; struct resource *res; void __iomem *base; int nr_opp; - const struct mtk_cpufreq_variant *variant; }; struct mtk_cpufreq_variant { @@ -63,7 +67,7 @@ static int __maybe_unused mtk_cpufreq_get_cpu_power(struct device *cpu_dev, unsigned long *uW, unsigned long *KHz) { - struct mtk_cpufreq_data *data; + struct mtk_cpufreq_domain *data; struct cpufreq_policy *policy; int i; @@ -90,7 +94,7 @@ mtk_cpufreq_get_cpu_power(struct device *cpu_dev, unsigned long *uW, static int mtk_cpufreq_hw_target_index(struct cpufreq_policy *policy, unsigned int index) { - struct mtk_cpufreq_data *data = policy->driver_data; + struct mtk_cpufreq_domain *data = policy->driver_data; writel_relaxed(index, data->reg_bases[REG_FREQ_PERF_STATE]); @@ -99,7 +103,7 @@ static int mtk_cpufreq_hw_target_index(struct cpufreq_policy *policy, static unsigned int mtk_cpufreq_hw_get(unsigned int cpu) { - struct mtk_cpufreq_data *data; + struct mtk_cpufreq_domain *data; struct cpufreq_policy *policy; unsigned int index; @@ -118,7 +122,7 @@ static unsigned int mtk_cpufreq_hw_get(unsigned int cpu) static unsigned int mtk_cpufreq_hw_fast_switch(struct cpufreq_policy *policy, unsigned int target_freq) { - struct mtk_cpufreq_data *data = policy->driver_data; + struct mtk_cpufreq_domain *data = policy->driver_data; unsigned int index; index = cpufreq_table_find_index_dl(policy, target_freq, false); @@ -129,7 +133,7 @@ static unsigned int mtk_cpufreq_hw_fast_switch(struct cpufreq_policy *policy, } static int mtk_cpu_create_freq_table(struct platform_device *pdev, - struct mtk_cpufreq_data *data) + struct mtk_cpufreq_domain *data) { struct device *dev = &pdev->dev; u32 temp, i, freq, prev_freq = 0; @@ -164,9 +168,9 @@ static int mtk_cpu_create_freq_table(struct platform_device *pdev, static int mtk_cpu_resources_init(struct platform_device *pdev, struct cpufreq_policy *policy, - const struct mtk_cpufreq_variant *variant) + struct mtk_cpufreq_priv *priv) { - struct mtk_cpufreq_data *data; + struct mtk_cpufreq_domain *data; struct device *dev = &pdev->dev; struct resource *res; struct of_phandle_args args; @@ -187,6 +191,8 @@ static int mtk_cpu_resources_init(struct platform_device *pdev, index = args.args[0]; of_node_put(args.np); + data->parent = priv; + res = platform_get_resource(pdev, IORESOURCE_MEM, index); if (!res) { dev_err(dev, "failed to get mem resource %d\n", index); @@ -207,10 +213,9 @@ static int mtk_cpu_resources_init(struct platform_device *pdev, data->base = base; data->res = res; - data->variant = variant; for (i = REG_FREQ_LUT_TABLE; i < REG_ARRAY_SIZE; i++) - data->reg_bases[i] = base + variant->reg_offsets[i]; + data->reg_bases[i] = base + priv->variant->reg_offsets[i]; ret = mtk_cpu_create_freq_table(pdev, data); if (ret) { @@ -231,7 +236,7 @@ static int mtk_cpufreq_hw_cpu_init(struct cpufreq_policy *policy) { struct platform_device *pdev = cpufreq_get_driver_data(); int sig, pwr_hw = CPUFREQ_HW_STATUS | SVS_HW_STATUS; - struct mtk_cpufreq_data *data; + struct mtk_cpufreq_domain *data; unsigned int latency; int ret; @@ -270,7 +275,7 @@ static int mtk_cpufreq_hw_cpu_init(struct cpufreq_policy *policy) static void mtk_cpufreq_hw_cpu_exit(struct cpufreq_policy *policy) { - struct mtk_cpufreq_data *data = policy->driver_data; + struct mtk_cpufreq_domain *data = policy->driver_data; struct resource *res = data->res; void __iomem *base = data->base; @@ -283,7 +288,7 @@ static void mtk_cpufreq_hw_cpu_exit(struct cpufreq_policy *policy) static void mtk_cpufreq_register_em(struct cpufreq_policy *policy) { struct em_data_callback em_cb = EM_DATA_CB(mtk_cpufreq_get_cpu_power); - struct mtk_cpufreq_data *data = policy->driver_data; + struct mtk_cpufreq_domain *data = policy->driver_data; em_dev_register_perf_domain(get_cpu_device(policy->cpu), data->nr_opp, &em_cb, policy->cpus, true); @@ -305,6 +310,7 @@ static struct cpufreq_driver cpufreq_mtk_hw_driver = { static int mtk_cpufreq_hw_driver_probe(struct platform_device *pdev) { + struct mtk_cpufreq_priv *priv; const void *data; int ret, cpu; struct device *cpu_dev; @@ -328,7 +334,13 @@ static int mtk_cpufreq_hw_driver_probe(struct platform_device *pdev) if (!data) return -EINVAL; - platform_set_drvdata(pdev, (void *) data); + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->variant = data; + + platform_set_drvdata(pdev, priv); cpufreq_mtk_hw_driver.driver_data = pdev; ret = cpufreq_register_driver(&cpufreq_mtk_hw_driver); From 32e0d669f3ac9574862a64a56c9a6dff675f8600 Mon Sep 17 00:00:00 2001 From: Nicolas Frattaroli Date: Wed, 16 Jul 2025 19:51:25 +0200 Subject: [PATCH 00124/11391] cpufreq: mediatek-hw: Add support for MT8196 The MT8196 SoC uses DVFS to set a desired target frequency for each CPU core. It also uses slightly different register offsets. Add support for it, which necessitates reworking how the mmio regs are acquired, as mt8196 has the fdvfs register before the performance domain registers. I've verified with both `sysbench cpu run` and `head -c 10G \ /dev/urandom | pigz -p 8 -c - | pv -ba > /dev/null` that we don't just get a higher reported clock frequency, but that the observed performance also increases, by a factor of 2.64 in an 8 thread sysbench test. Signed-off-by: Nicolas Frattaroli Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Viresh Kumar --- drivers/cpufreq/mediatek-cpufreq-hw.c | 70 ++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/mediatek-cpufreq-hw.c b/drivers/cpufreq/mediatek-cpufreq-hw.c index 53611077d0d9..e4eadce6f937 100644 --- a/drivers/cpufreq/mediatek-cpufreq-hw.c +++ b/drivers/cpufreq/mediatek-cpufreq-hw.c @@ -24,6 +24,8 @@ #define POLL_USEC 1000 #define TIMEOUT_USEC 300000 +#define FDVFS_FDIV_HZ (26 * 1000) + enum { REG_FREQ_LUT_TABLE, REG_FREQ_ENABLE, @@ -36,7 +38,9 @@ enum { }; struct mtk_cpufreq_priv { + struct device *dev; const struct mtk_cpufreq_variant *variant; + void __iomem *fdvfs; }; struct mtk_cpufreq_domain { @@ -49,7 +53,9 @@ struct mtk_cpufreq_domain { }; struct mtk_cpufreq_variant { + int (*init)(struct mtk_cpufreq_priv *priv); const u16 reg_offsets[REG_ARRAY_SIZE]; + const bool is_hybrid_dvfs; }; static const struct mtk_cpufreq_variant cpufreq_mtk_base_variant = { @@ -63,6 +69,29 @@ static const struct mtk_cpufreq_variant cpufreq_mtk_base_variant = { }, }; +static int mtk_cpufreq_hw_mt8196_init(struct mtk_cpufreq_priv *priv) +{ + priv->fdvfs = devm_of_iomap(priv->dev, priv->dev->of_node, 0, NULL); + if (IS_ERR_OR_NULL(priv->fdvfs)) + return dev_err_probe(priv->dev, PTR_ERR(priv->fdvfs), + "failed to get fdvfs iomem\n"); + + return 0; +} + +static const struct mtk_cpufreq_variant cpufreq_mtk_mt8196_variant = { + .init = mtk_cpufreq_hw_mt8196_init, + .reg_offsets = { + [REG_FREQ_LUT_TABLE] = 0x0, + [REG_FREQ_ENABLE] = 0x84, + [REG_FREQ_PERF_STATE] = 0x88, + [REG_FREQ_HW_STATE] = 0x8c, + [REG_EM_POWER_TBL] = 0x90, + [REG_FREQ_LATENCY] = 0x114, + }, + .is_hybrid_dvfs = true, +}; + static int __maybe_unused mtk_cpufreq_get_cpu_power(struct device *cpu_dev, unsigned long *uW, unsigned long *KHz) @@ -91,12 +120,31 @@ mtk_cpufreq_get_cpu_power(struct device *cpu_dev, unsigned long *uW, return 0; } +static void mtk_cpufreq_hw_fdvfs_switch(unsigned int target_freq, + struct cpufreq_policy *policy) +{ + struct mtk_cpufreq_domain *data = policy->driver_data; + struct mtk_cpufreq_priv *priv = data->parent; + unsigned int cpu; + + target_freq = DIV_ROUND_UP(target_freq, FDVFS_FDIV_HZ); + for_each_cpu(cpu, policy->real_cpus) { + writel_relaxed(target_freq, priv->fdvfs + cpu * 4); + } +} + static int mtk_cpufreq_hw_target_index(struct cpufreq_policy *policy, unsigned int index) { struct mtk_cpufreq_domain *data = policy->driver_data; + unsigned int target_freq; - writel_relaxed(index, data->reg_bases[REG_FREQ_PERF_STATE]); + if (data->parent->fdvfs) { + target_freq = policy->freq_table[index].frequency; + mtk_cpufreq_hw_fdvfs_switch(target_freq, policy); + } else { + writel_relaxed(index, data->reg_bases[REG_FREQ_PERF_STATE]); + } return 0; } @@ -127,7 +175,10 @@ static unsigned int mtk_cpufreq_hw_fast_switch(struct cpufreq_policy *policy, index = cpufreq_table_find_index_dl(policy, target_freq, false); - writel_relaxed(index, data->reg_bases[REG_FREQ_PERF_STATE]); + if (data->parent->fdvfs) + mtk_cpufreq_hw_fdvfs_switch(target_freq, policy); + else + writel_relaxed(index, data->reg_bases[REG_FREQ_PERF_STATE]); return policy->freq_table[index].frequency; } @@ -191,6 +242,13 @@ static int mtk_cpu_resources_init(struct platform_device *pdev, index = args.args[0]; of_node_put(args.np); + /* + * In a cpufreq with hybrid DVFS, such as the MT8196, the first declared + * register range is for FDVFS, followed by the frequency domain MMIOs. + */ + if (priv->variant->is_hybrid_dvfs) + index++; + data->parent = priv; res = platform_get_resource(pdev, IORESOURCE_MEM, index); @@ -339,6 +397,13 @@ static int mtk_cpufreq_hw_driver_probe(struct platform_device *pdev) return -ENOMEM; priv->variant = data; + priv->dev = &pdev->dev; + + if (priv->variant->init) { + ret = priv->variant->init(priv); + if (ret) + return ret; + } platform_set_drvdata(pdev, priv); cpufreq_mtk_hw_driver.driver_data = pdev; @@ -357,6 +422,7 @@ static void mtk_cpufreq_hw_driver_remove(struct platform_device *pdev) static const struct of_device_id mtk_cpufreq_hw_match[] = { { .compatible = "mediatek,cpufreq-hw", .data = &cpufreq_mtk_base_variant }, + { .compatible = "mediatek,mt8196-cpufreq-hw", .data = &cpufreq_mtk_mt8196_variant }, {} }; MODULE_DEVICE_TABLE(of, mtk_cpufreq_hw_match); From 8640689f17fd550c3e89d2b47ecb02536c58baf3 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Sat, 9 Aug 2025 13:28:30 +0200 Subject: [PATCH 00125/11391] cpufreq: airoha: Add support for AN7583 SoC New Airoha AN7583 SoC use the same exact logic to control the CPU frequency. Add the Device compatible to the block list for cpufreq-dt-plat and to the Airoha CPUFreq driver compatible list. Signed-off-by: Christian Marangi Signed-off-by: Viresh Kumar --- drivers/cpufreq/airoha-cpufreq.c | 1 + drivers/cpufreq/cpufreq-dt-platdev.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/cpufreq/airoha-cpufreq.c b/drivers/cpufreq/airoha-cpufreq.c index 4fe39eadd163..b6b1cdc4d11d 100644 --- a/drivers/cpufreq/airoha-cpufreq.c +++ b/drivers/cpufreq/airoha-cpufreq.c @@ -107,6 +107,7 @@ static struct platform_driver airoha_cpufreq_driver = { }; static const struct of_device_id airoha_cpufreq_match_list[] __initconst = { + { .compatible = "airoha,an7583" }, { .compatible = "airoha,en7581" }, {}, }; diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c index 015dd393eaba..0f954b07dcb3 100644 --- a/drivers/cpufreq/cpufreq-dt-platdev.c +++ b/drivers/cpufreq/cpufreq-dt-platdev.c @@ -103,6 +103,7 @@ static const struct of_device_id allowlist[] __initconst = { * platforms using "operating-points-v2" property. */ static const struct of_device_id blocklist[] __initconst = { + { .compatible = "airoha,an7583", }, { .compatible = "airoha,en7581", }, { .compatible = "allwinner,sun50i-a100" }, From 17bd9599f07ff700b9fb7d15dfa1f1de42947a54 Mon Sep 17 00:00:00 2001 From: Akhilesh Patil Date: Sat, 9 Aug 2025 19:46:58 +0530 Subject: [PATCH 00126/11391] cpufreq: armada-37xx: use max() to calculate target_vm Use max() macro while calculating target_vm to simplify and improve the armada-37xx-cpufreq driver code. Reported-by: kernel test robot Closes: https://lore.kernel.org/r/202503251256.rrl65HgY-lkp@intel.com/ Reported-by: Yang Ruibin <11162571@vivo.com> Closes: https://lore.kernel.org/lkml/2c55fb07-b29e-43e0-8697-f75d1f0df89a@vivo.com/ Signed-off-by: Akhilesh Patil Signed-off-by: Viresh Kumar --- drivers/cpufreq/armada-37xx-cpufreq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/armada-37xx-cpufreq.c b/drivers/cpufreq/armada-37xx-cpufreq.c index f28a4435fba7..0efe403a5980 100644 --- a/drivers/cpufreq/armada-37xx-cpufreq.c +++ b/drivers/cpufreq/armada-37xx-cpufreq.c @@ -265,7 +265,7 @@ static void __init armada37xx_cpufreq_avs_configure(struct regmap *base, */ target_vm = avs_map[l0_vdd_min] - 100; - target_vm = target_vm > MIN_VOLT_MV ? target_vm : MIN_VOLT_MV; + target_vm = max(target_vm, MIN_VOLT_MV); dvfs->avs[1] = armada_37xx_avs_val_match(target_vm); /* @@ -273,7 +273,7 @@ static void __init armada37xx_cpufreq_avs_configure(struct regmap *base, * be larger than 1000mv */ target_vm = avs_map[l0_vdd_min] - 150; - target_vm = target_vm > MIN_VOLT_MV ? target_vm : MIN_VOLT_MV; + target_vm = max(target_vm, MIN_VOLT_MV); dvfs->avs[2] = dvfs->avs[3] = armada_37xx_avs_val_match(target_vm); /* From 91ec67fa33250059a0c52bbf3148302f364a6e99 Mon Sep 17 00:00:00 2001 From: Anton Kirilov Date: Thu, 7 Aug 2025 18:00:11 +0100 Subject: [PATCH 00127/11391] arm64: dts: rockchip: Enable HDMI audio output for NanoPi R6C/R6S Enable HDMI audio output for FriendlyElec NanoPi R6C/R6S boards. Signed-off-by: Anton Kirilov Link: https://lore.kernel.org/r/20250807170012.88178-1-anton.kirilov@arm.com Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6.dtsi index fbf062ec3bf1..2e9d5143476d 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6.dtsi @@ -251,6 +251,10 @@ hdmi0_out_con: endpoint { }; }; +&hdmi0_sound { + status = "okay"; +}; + &hdptxphy0 { status = "okay"; }; @@ -335,6 +339,10 @@ hym8563: rtc@51 { }; }; +&i2s5_8ch { + status = "okay"; +}; + &mdio1 { rgmii_phy1: ethernet-phy@1 { compatible = "ethernet-phy-id001c.c916"; From 16d39e2bf96075dc266fdcf0f2507fc075c33676 Mon Sep 17 00:00:00 2001 From: BowenYu Date: Wed, 30 Jul 2025 11:06:49 +0800 Subject: [PATCH 00128/11391] cpufreq: Remove unused parameter in cppc_perf_from_fbctrs() Remove the unused parameter cppc_cpudata* cpu_data in cppc_perf_from_fbctrs(). Signed-off-by: BowenYu Signed-off-by: Viresh Kumar --- drivers/cpufreq/cppc_cpufreq.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index 4a17162a392d..ecbeb12f46e6 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -50,8 +50,7 @@ struct cppc_freq_invariance { static DEFINE_PER_CPU(struct cppc_freq_invariance, cppc_freq_inv); static struct kthread_worker *kworker_fie; -static int cppc_perf_from_fbctrs(struct cppc_cpudata *cpu_data, - struct cppc_perf_fb_ctrs *fb_ctrs_t0, +static int cppc_perf_from_fbctrs(struct cppc_perf_fb_ctrs *fb_ctrs_t0, struct cppc_perf_fb_ctrs *fb_ctrs_t1); /** @@ -87,8 +86,7 @@ static void cppc_scale_freq_workfn(struct kthread_work *work) return; } - perf = cppc_perf_from_fbctrs(cpu_data, &cppc_fi->prev_perf_fb_ctrs, - &fb_ctrs); + perf = cppc_perf_from_fbctrs(&cppc_fi->prev_perf_fb_ctrs, &fb_ctrs); if (!perf) return; @@ -684,8 +682,7 @@ static inline u64 get_delta(u64 t1, u64 t0) return (u32)t1 - (u32)t0; } -static int cppc_perf_from_fbctrs(struct cppc_cpudata *cpu_data, - struct cppc_perf_fb_ctrs *fb_ctrs_t0, +static int cppc_perf_from_fbctrs(struct cppc_perf_fb_ctrs *fb_ctrs_t0, struct cppc_perf_fb_ctrs *fb_ctrs_t1) { u64 delta_reference, delta_delivered; @@ -747,8 +744,7 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpu) return 0; } - delivered_perf = cppc_perf_from_fbctrs(cpu_data, &fb_ctrs_t0, - &fb_ctrs_t1); + delivered_perf = cppc_perf_from_fbctrs(&fb_ctrs_t0, &fb_ctrs_t1); if (!delivered_perf) goto out_invalid_counters; From 6f36b1fdb80dd1fdd24742af4ca435f76f73dfe9 Mon Sep 17 00:00:00 2001 From: Chukun Pan Date: Sun, 10 Aug 2025 18:00:20 +0800 Subject: [PATCH 00129/11391] arm64: dts: rockchip: set LAN LEDs to default-off on Radxa E52C The NICs have default-trigger of "netdev" in order to show up as LAN/WAN connected, so their default-state should be set to "off". Signed-off-by: Chukun Pan Link: https://lore.kernel.org/r/20250810100020.445053-3-amadeus@jmu.edu.cn Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3582-radxa-e52c.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3582-radxa-e52c.dts b/arch/arm64/boot/dts/rockchip/rk3582-radxa-e52c.dts index e04f21d8c831..63e5dfb77ab1 100644 --- a/arch/arm64/boot/dts/rockchip/rk3582-radxa-e52c.dts +++ b/arch/arm64/boot/dts/rockchip/rk3582-radxa-e52c.dts @@ -71,7 +71,7 @@ leds-1 { led-1 { color = ; - default-state = "on"; + default-state = "off"; function = LED_FUNCTION_LAN; linux,default-trigger = "netdev"; pwms = <&pwm14 0 1000000 PWM_POLARITY_INVERTED>; @@ -80,7 +80,7 @@ led-1 { led-2 { color = ; - default-state = "on"; + default-state = "off"; function = LED_FUNCTION_WAN; linux,default-trigger = "netdev"; pwms = <&pwm11 0 1000000 PWM_POLARITY_INVERTED>; From 6294d0590d5f65725e505b89978895bd04b55650 Mon Sep 17 00:00:00 2001 From: Chaoyi Chen Date: Thu, 31 Jul 2025 14:24:15 +0800 Subject: [PATCH 00130/11391] arm64: dts: rockchip: Enable eMMC on rk3576-evb1-v10 Some rk3576-evb1 boards use eMMC instead of UFS. Enable eMMC for it. Signed-off-by: Chaoyi Chen Link: https://lore.kernel.org/r/20250731062415.212-1-kernel@airkyi.com Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3576-evb1-v10.dts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3576-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3576-evb1-v10.dts index 56527c56830e..a60dee0de9f9 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576-evb1-v10.dts +++ b/arch/arm64/boot/dts/rockchip/rk3576-evb1-v10.dts @@ -723,6 +723,18 @@ usbc0_int: usbc0-int { }; }; +&sdhci { + bus-width = <8>; + full-pwr-cycle-in-suspend; + max-frequency = <200000000>; + mmc-hs400-1_8v; + mmc-hs400-enhanced-strobe; + no-sdio; + no-sd; + non-removable; + status = "okay"; +}; + &sdmmc { bus-width = <4>; cap-mmc-highspeed; From 15e8ba9d8b14ae6de415186622379f5f4dcfd141 Mon Sep 17 00:00:00 2001 From: Nicolas Frattaroli Date: Tue, 10 Jun 2025 14:32:42 +0200 Subject: [PATCH 00131/11391] arm64: dts: rockchip: Add thermal nodes to RK3576 Add the TSADC node to the RK3576. Additionally, add everything the TSADC needs to function, i.e. thermal zones, their trip points and maps, as well as adjust the CPU cooling-cells property. The polling-delay properties are set to 0 as we do have interrupts for this TSADC on this particular SoC, though the polling-delay-passive properties are set to 100 for the thermal zones that have a passive cooling device, as otherwise the thermal throttling behaviour never unthrottles. Signed-off-by: Nicolas Frattaroli Link: https://lore.kernel.org/r/20250610-rk3576-tsadc-upstream-v6-6-b6e9efbf1015@collabora.com Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3576.dtsi | 164 ++++++++++++++++++++++- 1 file changed, 162 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3576.dtsi b/arch/arm64/boot/dts/rockchip/rk3576.dtsi index c3cdae8a5494..2ec752b12b41 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3576.dtsi @@ -11,6 +11,7 @@ #include #include #include +#include / { compatible = "rockchip,rk3576"; @@ -113,9 +114,9 @@ cpu_l0: cpu@0 { capacity-dmips-mhz = <485>; clocks = <&scmi_clk SCMI_ARMCLK_L>; operating-points-v2 = <&cluster0_opp_table>; - #cooling-cells = <2>; dynamic-power-coefficient = <120>; cpu-idle-states = <&CPU_SLEEP>; + #cooling-cells = <2>; }; cpu_l1: cpu@1 { @@ -127,6 +128,7 @@ cpu_l1: cpu@1 { clocks = <&scmi_clk SCMI_ARMCLK_L>; operating-points-v2 = <&cluster0_opp_table>; cpu-idle-states = <&CPU_SLEEP>; + #cooling-cells = <2>; }; cpu_l2: cpu@2 { @@ -138,6 +140,7 @@ cpu_l2: cpu@2 { clocks = <&scmi_clk SCMI_ARMCLK_L>; operating-points-v2 = <&cluster0_opp_table>; cpu-idle-states = <&CPU_SLEEP>; + #cooling-cells = <2>; }; cpu_l3: cpu@3 { @@ -149,6 +152,7 @@ cpu_l3: cpu@3 { clocks = <&scmi_clk SCMI_ARMCLK_L>; operating-points-v2 = <&cluster0_opp_table>; cpu-idle-states = <&CPU_SLEEP>; + #cooling-cells = <2>; }; cpu_b0: cpu@100 { @@ -159,9 +163,9 @@ cpu_b0: cpu@100 { capacity-dmips-mhz = <1024>; clocks = <&scmi_clk SCMI_ARMCLK_B>; operating-points-v2 = <&cluster1_opp_table>; - #cooling-cells = <2>; dynamic-power-coefficient = <320>; cpu-idle-states = <&CPU_SLEEP>; + #cooling-cells = <2>; }; cpu_b1: cpu@101 { @@ -173,6 +177,7 @@ cpu_b1: cpu@101 { clocks = <&scmi_clk SCMI_ARMCLK_B>; operating-points-v2 = <&cluster1_opp_table>; cpu-idle-states = <&CPU_SLEEP>; + #cooling-cells = <2>; }; cpu_b2: cpu@102 { @@ -184,6 +189,7 @@ cpu_b2: cpu@102 { clocks = <&scmi_clk SCMI_ARMCLK_B>; operating-points-v2 = <&cluster1_opp_table>; cpu-idle-states = <&CPU_SLEEP>; + #cooling-cells = <2>; }; cpu_b3: cpu@103 { @@ -195,6 +201,7 @@ cpu_b3: cpu@103 { clocks = <&scmi_clk SCMI_ARMCLK_B>; operating-points-v2 = <&cluster1_opp_table>; cpu-idle-states = <&CPU_SLEEP>; + #cooling-cells = <2>; }; idle-states { @@ -520,6 +527,143 @@ psci { method = "smc"; }; + thermal_zones: thermal-zones { + /* sensor near the center of the SoC */ + package_thermal: package-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsadc 0>; + + trips { + package_crit: package-crit { + temperature = <115000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + /* sensor for cluster1 (big Cortex-A72 cores) */ + bigcore_thermal: bigcore-thermal { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-sensors = <&tsadc 1>; + + trips { + bigcore_alert: bigcore-alert { + temperature = <85000>; + hysteresis = <2000>; + type = "passive"; + }; + + bigcore_crit: bigcore-crit { + temperature = <115000>; + hysteresis = <0>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&bigcore_alert>; + cooling-device = + <&cpu_b0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu_b1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu_b2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu_b3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + + /* sensor for cluster0 (little Cortex-A53 cores) */ + littlecore_thermal: littlecore-thermal { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-sensors = <&tsadc 2>; + + trips { + littlecore_alert: littlecore-alert { + temperature = <85000>; + hysteresis = <2000>; + type = "passive"; + }; + + littlecore_crit: littlecore-crit { + temperature = <115000>; + hysteresis = <0>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&littlecore_alert>; + cooling-device = + <&cpu_l0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu_l1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu_l2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu_l3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + + gpu_thermal: gpu-thermal { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-sensors = <&tsadc 3>; + + trips { + gpu_alert: gpu-alert { + temperature = <85000>; + hysteresis = <2000>; + type = "passive"; + }; + + gpu_crit: gpu-crit { + temperature = <115000>; + hysteresis = <0>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&gpu_alert>; + cooling-device = + <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + + npu_thermal: npu-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsadc 4>; + + trips { + npu_crit: npu-crit { + temperature = <115000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + ddr_thermal: ddr-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsadc 5>; + + trips { + ddr_crit: ddr-crit { + temperature = <115000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + }; + timer { compatible = "arm,armv8-timer"; interrupts = , @@ -2303,6 +2447,22 @@ saradc: adc@2ae00000 { status = "disabled"; }; + tsadc: tsadc@2ae70000 { + compatible = "rockchip,rk3576-tsadc"; + reg = <0x0 0x2ae70000 0x0 0x400>; + interrupts = ; + clocks = <&cru CLK_TSADC>, <&cru PCLK_TSADC>; + clock-names = "tsadc", "apb_pclk"; + assigned-clocks = <&cru CLK_TSADC>; + assigned-clock-rates = <2000000>; + resets = <&cru SRST_P_TSADC>, <&cru SRST_TSADC>; + reset-names = "tsadc-apb", "tsadc"; + #thermal-sensor-cells = <1>; + rockchip,hw-tshut-temp = <120000>; + rockchip,hw-tshut-mode = <0>; /* tshut mode 0:CRU 1:GPIO */ + rockchip,hw-tshut-polarity = <0>; /* tshut polarity 0:LOW 1:HIGH */ + }; + i2c9: i2c@2ae80000 { compatible = "rockchip,rk3576-i2c", "rockchip,rk3399-i2c"; reg = <0x0 0x2ae80000 0x0 0x1000>; From a4053badacf3699023527392c947314b074f5e0e Mon Sep 17 00:00:00 2001 From: Nicolas Frattaroli Date: Tue, 10 Jun 2025 14:32:43 +0200 Subject: [PATCH 00132/11391] arm64: dts: rockchip: Add thermal trim OTP and tsadc nodes Thanks to Heiko's work getting OTP working on the RK3576, we can specify the thermal sensor trim values which are stored there now, and with my driver addition to rockchip_thermal, we can make use of these. Add them to the devicetree for the SoC. Signed-off-by: Nicolas Frattaroli Link: https://lore.kernel.org/r/20250610-rk3576-tsadc-upstream-v6-7-b6e9efbf1015@collabora.com Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3576.dtsi | 57 ++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3576.dtsi b/arch/arm64/boot/dts/rockchip/rk3576.dtsi index 2ec752b12b41..f28c5a3e4f4c 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3576.dtsi @@ -1937,6 +1937,30 @@ gpu_leakage: gpu-leakage@21 { log_leakage: log-leakage@22 { reg = <0x22 0x1>; }; + bigcore_tsadc_trim: bigcore-tsadc-trim@24 { + reg = <0x24 0x2>; + bits = <0 10>; + }; + litcore_tsadc_trim: litcore-tsadc-trim@26 { + reg = <0x26 0x2>; + bits = <0 10>; + }; + ddr_tsadc_trim: ddr-tsadc-trim@28 { + reg = <0x28 0x2>; + bits = <0 10>; + }; + npu_tsadc_trim: npu-tsadc-trim@2a { + reg = <0x2a 0x2>; + bits = <0 10>; + }; + gpu_tsadc_trim: gpu-tsadc-trim@2c { + reg = <0x2c 0x2>; + bits = <0 10>; + }; + soc_tsadc_trim: soc-tsadc-trim@64 { + reg = <0x64 0x2>; + bits = <0 10>; + }; }; sai0: sai@2a600000 { @@ -2461,6 +2485,39 @@ tsadc: tsadc@2ae70000 { rockchip,hw-tshut-temp = <120000>; rockchip,hw-tshut-mode = <0>; /* tshut mode 0:CRU 1:GPIO */ rockchip,hw-tshut-polarity = <0>; /* tshut polarity 0:LOW 1:HIGH */ + #address-cells = <1>; + #size-cells = <0>; + + sensor@0 { + reg = <0>; + nvmem-cells = <&soc_tsadc_trim>; + nvmem-cell-names = "trim"; + }; + sensor@1 { + reg = <1>; + nvmem-cells = <&bigcore_tsadc_trim>; + nvmem-cell-names = "trim"; + }; + sensor@2 { + reg = <2>; + nvmem-cells = <&litcore_tsadc_trim>; + nvmem-cell-names = "trim"; + }; + sensor@3 { + reg = <3>; + nvmem-cells = <&ddr_tsadc_trim>; + nvmem-cell-names = "trim"; + }; + sensor@4 { + reg = <4>; + nvmem-cells = <&npu_tsadc_trim>; + nvmem-cell-names = "trim"; + }; + sensor@5 { + reg = <5>; + nvmem-cells = <&gpu_tsadc_trim>; + nvmem-cell-names = "trim"; + }; }; i2c9: i2c@2ae80000 { From 2b5066a3a19a2870f353f8783f1ee63e61b8e371 Mon Sep 17 00:00:00 2001 From: Md Sadre Alam Date: Wed, 6 Aug 2025 16:58:06 +0530 Subject: [PATCH 00133/11391] cpufreq: qcom-nvmem: Enable cpufreq for ipq5424 IPQ5424 have different OPPs available for the CPU based on SoC variant. This can be determined through use of an eFuse register present in the silicon. Added support for ipq5424 on nvmem driver which helps to determine OPPs at runtime based on the eFuse register which has the CPU frequency limits. opp-supported-hw dt binding can be used to indicate the available OPPs for each limit. nvmem driver also creates the "cpufreq-dt" platform_device after passing the version matching data to the OPP framework so that the cpufreq-dt handles the actual cpufreq implementation. Signed-off-by: Md Sadre Alam Signed-off-by: Sricharan Ramabadhran Reviewed-by: Konrad Dybcio [ Changed '!=' based check to '==' based check ] Signed-off-by: Varadarajan Narayanan Signed-off-by: Viresh Kumar --- drivers/cpufreq/cpufreq-dt-platdev.c | 1 + drivers/cpufreq/qcom-cpufreq-nvmem.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c index 0f954b07dcb3..1a9d9d008002 100644 --- a/drivers/cpufreq/cpufreq-dt-platdev.c +++ b/drivers/cpufreq/cpufreq-dt-platdev.c @@ -192,6 +192,7 @@ static const struct of_device_id blocklist[] __initconst = { { .compatible = "ti,am62p5", }, { .compatible = "qcom,ipq5332", }, + { .compatible = "qcom,ipq5424", }, { .compatible = "qcom,ipq6018", }, { .compatible = "qcom,ipq8064", }, { .compatible = "qcom,ipq8074", }, diff --git a/drivers/cpufreq/qcom-cpufreq-nvmem.c b/drivers/cpufreq/qcom-cpufreq-nvmem.c index 54f8117103c8..765a5bb81829 100644 --- a/drivers/cpufreq/qcom-cpufreq-nvmem.c +++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c @@ -200,6 +200,10 @@ static int qcom_cpufreq_kryo_name_version(struct device *cpu_dev, case QCOM_ID_IPQ9574: drv->versions = 1 << (unsigned int)(*speedbin); break; + case QCOM_ID_IPQ5424: + case QCOM_ID_IPQ5404: + drv->versions = (*speedbin == 0x3b) ? BIT(1) : BIT(0); + break; case QCOM_ID_MSM8996SG: case QCOM_ID_APQ8096SG: drv->versions = 1 << ((unsigned int)(*speedbin) + 4); @@ -591,6 +595,7 @@ static const struct of_device_id qcom_cpufreq_match_list[] __initconst __maybe_u { .compatible = "qcom,msm8996", .data = &match_data_kryo }, { .compatible = "qcom,qcs404", .data = &match_data_qcs404 }, { .compatible = "qcom,ipq5332", .data = &match_data_kryo }, + { .compatible = "qcom,ipq5424", .data = &match_data_kryo }, { .compatible = "qcom,ipq6018", .data = &match_data_ipq6018 }, { .compatible = "qcom,ipq8064", .data = &match_data_ipq8064 }, { .compatible = "qcom,ipq8074", .data = &match_data_ipq8074 }, From 78b72897a5c8bb9d3b51fc6494a1eb09265487a4 Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Thu, 17 Jul 2025 17:22:36 +0100 Subject: [PATCH 00134/11391] soc: samsung: exynos-pmu: Enable CPU Idle for gs101 Register cpu pm notifiers for gs101 which call the gs101_cpu_pmu_online/offline callbacks which in turn program the ACPM C2 hint. This hint is required to actually enter the C2 idle state in addition to the PSCI calls due to limitations in the el3mon/ACPM firmware. A couple of corner cases are handled, namely when the system is rebooting or suspending we ignore the request. Additionally the request is ignored if the CPU is in CPU hot plug. Some common code is refactored so that it can be called from both the CPU hot plug callbacks and CPU PM notifier taking into account that CPU PM notifiers are called with IRQs disabled whereas CPU hotplug callbacks are not. Additionally due to CPU PM notifiers using raw_spinlock the locking is updated to use raw_spinlock variants, this includes updating the pmu_regs regmap to use .use_raw_spinlock = true and additionally creating and registering a custom pmu-intr-gen regmap instead of using the regmap provided by syscon. Note: this patch has a runtime dependency on adding 'local-timer-stop' dt property to the CPU nodes. This informs the time framework to switch to a broadcast timer as the local timer will be shutdown. Without that DT property specified the system hangs in early boot with this patch applied. Signed-off-by: Peter Griffin Link: https://lore.kernel.org/r/20250717-gs101-cpuidle-v7-1-33d51770114b@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/soc/samsung/exynos-pmu.c | 276 ++++++++++++++++++++++++++++--- 1 file changed, 254 insertions(+), 22 deletions(-) diff --git a/drivers/soc/samsung/exynos-pmu.c b/drivers/soc/samsung/exynos-pmu.c index a77288f49d24..22c50ca2aa79 100644 --- a/drivers/soc/samsung/exynos-pmu.c +++ b/drivers/soc/samsung/exynos-pmu.c @@ -7,7 +7,9 @@ #include #include +#include #include +#include #include #include #include @@ -15,6 +17,7 @@ #include #include #include +#include #include #include @@ -35,6 +38,15 @@ struct exynos_pmu_context { const struct exynos_pmu_data *pmu_data; struct regmap *pmureg; struct regmap *pmuintrgen; + /* + * Serialization lock for CPU hot plug and cpuidle ACPM hint + * programming. Also protects in_cpuhp, sys_insuspend & sys_inreboot + * flags. + */ + raw_spinlock_t cpupm_lock; + unsigned long *in_cpuhp; + bool sys_insuspend; + bool sys_inreboot; }; void __iomem *pmu_base_addr; @@ -221,6 +233,15 @@ static const struct regmap_config regmap_smccfg = { .reg_read = tensor_sec_reg_read, .reg_write = tensor_sec_reg_write, .reg_update_bits = tensor_sec_update_bits, + .use_raw_spinlock = true, +}; + +static const struct regmap_config regmap_pmu_intr = { + .name = "pmu_intr_gen", + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .use_raw_spinlock = true, }; static const struct exynos_pmu_data gs101_pmu_data = { @@ -330,13 +351,19 @@ struct regmap *exynos_get_pmu_regmap_by_phandle(struct device_node *np, EXPORT_SYMBOL_GPL(exynos_get_pmu_regmap_by_phandle); /* - * CPU_INFORM register hint values which are used by - * EL3 firmware (el3mon). + * CPU_INFORM register "hint" values are required to be programmed in addition to + * the standard PSCI calls to have functional CPU hotplug and CPU idle states. + * This is required to workaround limitations in the el3mon/ACPM firmware. */ #define CPU_INFORM_CLEAR 0 #define CPU_INFORM_C2 1 -static int gs101_cpuhp_pmu_online(unsigned int cpu) +/* + * __gs101_cpu_pmu_ prefix functions are common code shared by CPU PM notifiers + * (CPUIdle) and CPU hotplug callbacks. Functions should be called with IRQs + * disabled and cpupm_lock held. + */ +static int __gs101_cpu_pmu_online(unsigned int cpu) { unsigned int cpuhint = smp_processor_id(); u32 reg, mask; @@ -358,10 +385,48 @@ static int gs101_cpuhp_pmu_online(unsigned int cpu) return 0; } -static int gs101_cpuhp_pmu_offline(unsigned int cpu) +/* Called from CPU PM notifier (CPUIdle code path) with IRQs disabled */ +static int gs101_cpu_pmu_online(void) +{ + int cpu; + + raw_spin_lock(&pmu_context->cpupm_lock); + + if (pmu_context->sys_inreboot) { + raw_spin_unlock(&pmu_context->cpupm_lock); + return NOTIFY_OK; + } + + cpu = smp_processor_id(); + __gs101_cpu_pmu_online(cpu); + raw_spin_unlock(&pmu_context->cpupm_lock); + + return NOTIFY_OK; +} + +/* Called from CPU hot plug callback with IRQs enabled */ +static int gs101_cpuhp_pmu_online(unsigned int cpu) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&pmu_context->cpupm_lock, flags); + + __gs101_cpu_pmu_online(cpu); + /* + * Mark this CPU as having finished the hotplug. + * This means this CPU can now enter C2 idle state. + */ + clear_bit(cpu, pmu_context->in_cpuhp); + raw_spin_unlock_irqrestore(&pmu_context->cpupm_lock, flags); + + return 0; +} + +/* Common function shared by both CPU hot plug and CPUIdle */ +static int __gs101_cpu_pmu_offline(unsigned int cpu) { - u32 reg, mask; unsigned int cpuhint = smp_processor_id(); + u32 reg, mask; /* set cpu inform hint */ regmap_write(pmu_context->pmureg, GS101_CPU_INFORM(cpuhint), @@ -379,6 +444,165 @@ static int gs101_cpuhp_pmu_offline(unsigned int cpu) regmap_read(pmu_context->pmuintrgen, GS101_GRP1_INTR_BID_UPEND, ®); regmap_write(pmu_context->pmuintrgen, GS101_GRP1_INTR_BID_CLEAR, reg & mask); + + return 0; +} + +/* Called from CPU PM notifier (CPUIdle code path) with IRQs disabled */ +static int gs101_cpu_pmu_offline(void) +{ + int cpu; + + raw_spin_lock(&pmu_context->cpupm_lock); + cpu = smp_processor_id(); + + if (test_bit(cpu, pmu_context->in_cpuhp)) { + raw_spin_unlock(&pmu_context->cpupm_lock); + return NOTIFY_BAD; + } + + /* Ignore CPU_PM_ENTER event in reboot or suspend sequence. */ + if (pmu_context->sys_insuspend || pmu_context->sys_inreboot) { + raw_spin_unlock(&pmu_context->cpupm_lock); + return NOTIFY_OK; + } + + __gs101_cpu_pmu_offline(cpu); + raw_spin_unlock(&pmu_context->cpupm_lock); + + return NOTIFY_OK; +} + +/* Called from CPU hot plug callback with IRQs enabled */ +static int gs101_cpuhp_pmu_offline(unsigned int cpu) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&pmu_context->cpupm_lock, flags); + /* + * Mark this CPU as entering hotplug. So as not to confuse + * ACPM the CPU entering hotplug should not enter C2 idle state. + */ + set_bit(cpu, pmu_context->in_cpuhp); + __gs101_cpu_pmu_offline(cpu); + + raw_spin_unlock_irqrestore(&pmu_context->cpupm_lock, flags); + + return 0; +} + +static int gs101_cpu_pm_notify_callback(struct notifier_block *self, + unsigned long action, void *v) +{ + switch (action) { + case CPU_PM_ENTER: + return gs101_cpu_pmu_offline(); + + case CPU_PM_EXIT: + return gs101_cpu_pmu_online(); + } + + return NOTIFY_OK; +} + +static struct notifier_block gs101_cpu_pm_notifier = { + .notifier_call = gs101_cpu_pm_notify_callback, + /* + * We want to be called first, as the ACPM hint and handshake is what + * puts the CPU into C2. + */ + .priority = INT_MAX +}; + +static int exynos_cpupm_reboot_notifier(struct notifier_block *nb, + unsigned long event, void *v) +{ + unsigned long flags; + + switch (event) { + case SYS_POWER_OFF: + case SYS_RESTART: + raw_spin_lock_irqsave(&pmu_context->cpupm_lock, flags); + pmu_context->sys_inreboot = true; + raw_spin_unlock_irqrestore(&pmu_context->cpupm_lock, flags); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block exynos_cpupm_reboot_nb = { + .priority = INT_MAX, + .notifier_call = exynos_cpupm_reboot_notifier, +}; + +static int setup_cpuhp_and_cpuidle(struct device *dev) +{ + struct device_node *intr_gen_node; + struct resource intrgen_res; + void __iomem *virt_addr; + int ret, cpu; + + intr_gen_node = of_parse_phandle(dev->of_node, + "google,pmu-intr-gen-syscon", 0); + if (!intr_gen_node) { + /* + * To maintain support for older DTs that didn't specify syscon + * phandle just issue a warning rather than fail to probe. + */ + dev_warn(dev, "pmu-intr-gen syscon unavailable\n"); + return 0; + } + + /* + * To avoid lockdep issues (CPU PM notifiers use raw spinlocks) create + * a mmio regmap for pmu-intr-gen that uses raw spinlocks instead of + * syscon provided regmap. + */ + ret = of_address_to_resource(intr_gen_node, 0, &intrgen_res); + of_node_put(intr_gen_node); + + virt_addr = devm_ioremap(dev, intrgen_res.start, + resource_size(&intrgen_res)); + if (!virt_addr) + return -ENOMEM; + + pmu_context->pmuintrgen = devm_regmap_init_mmio(dev, virt_addr, + ®map_pmu_intr); + if (IS_ERR(pmu_context->pmuintrgen)) { + dev_err(dev, "failed to initialize pmu-intr-gen regmap\n"); + return PTR_ERR(pmu_context->pmuintrgen); + } + + /* register custom mmio regmap with syscon */ + ret = of_syscon_register_regmap(intr_gen_node, + pmu_context->pmuintrgen); + if (ret) + return ret; + + pmu_context->in_cpuhp = devm_bitmap_zalloc(dev, num_possible_cpus(), + GFP_KERNEL); + if (!pmu_context->in_cpuhp) + return -ENOMEM; + + raw_spin_lock_init(&pmu_context->cpupm_lock); + pmu_context->sys_inreboot = false; + pmu_context->sys_insuspend = false; + + /* set PMU to power on */ + for_each_online_cpu(cpu) + gs101_cpuhp_pmu_online(cpu); + + /* register CPU hotplug callbacks */ + cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "soc/exynos-pmu:prepare", + gs101_cpuhp_pmu_online, NULL); + + cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "soc/exynos-pmu:online", + NULL, gs101_cpuhp_pmu_offline); + + /* register CPU PM notifiers for cpuidle */ + cpu_pm_register_notifier(&gs101_cpu_pm_notifier); + register_reboot_notifier(&exynos_cpupm_reboot_nb); return 0; } @@ -435,23 +659,9 @@ static int exynos_pmu_probe(struct platform_device *pdev) pmu_context->dev = dev; if (pmu_context->pmu_data && pmu_context->pmu_data->pmu_cpuhp) { - pmu_context->pmuintrgen = syscon_regmap_lookup_by_phandle(dev->of_node, - "google,pmu-intr-gen-syscon"); - if (IS_ERR(pmu_context->pmuintrgen)) { - /* - * To maintain support for older DTs that didn't specify syscon phandle - * just issue a warning rather than fail to probe. - */ - dev_warn(&pdev->dev, "pmu-intr-gen syscon unavailable\n"); - } else { - cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, - "soc/exynos-pmu:prepare", - gs101_cpuhp_pmu_online, NULL); - - cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, - "soc/exynos-pmu:online", - NULL, gs101_cpuhp_pmu_offline); - } + ret = setup_cpuhp_and_cpuidle(dev); + if (ret) + return ret; } if (pmu_context->pmu_data && pmu_context->pmu_data->pmu_init) @@ -471,10 +681,32 @@ static int exynos_pmu_probe(struct platform_device *pdev) return 0; } +static int exynos_cpupm_suspend_noirq(struct device *dev) +{ + raw_spin_lock(&pmu_context->cpupm_lock); + pmu_context->sys_insuspend = true; + raw_spin_unlock(&pmu_context->cpupm_lock); + return 0; +} + +static int exynos_cpupm_resume_noirq(struct device *dev) +{ + raw_spin_lock(&pmu_context->cpupm_lock); + pmu_context->sys_insuspend = false; + raw_spin_unlock(&pmu_context->cpupm_lock); + return 0; +} + +static const struct dev_pm_ops cpupm_pm_ops = { + NOIRQ_SYSTEM_SLEEP_PM_OPS(exynos_cpupm_suspend_noirq, + exynos_cpupm_resume_noirq) +}; + static struct platform_driver exynos_pmu_driver = { .driver = { .name = "exynos-pmu", .of_match_table = exynos_pmu_of_device_ids, + .pm = pm_sleep_ptr(&cpupm_pm_ops), }, .probe = exynos_pmu_probe, }; From 03714939b1e65e4456b69d2cb0c6d2555c7aaa76 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 8 Aug 2025 11:46:21 +0100 Subject: [PATCH 00135/11391] ALSA: hda: Fix spelling mistake "dismatch" -> "mismatch" There is a spelling mistake (or neologism of dis and match) in a dev_err message. Fix it. Signed-off-by: Colin Ian King Link: https://patch.msgid.link/20250808104621.829448-1-colin.i.king@gmail.com Signed-off-by: Takashi Iwai --- sound/hda/codecs/side-codecs/tas2781_hda_i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c index 45ac5e41bd4f..e1d60da50897 100644 --- a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c +++ b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c @@ -356,7 +356,7 @@ static int tas2563_save_calibration(struct tas2781_hda *h) } if (cd->total_sz != offset) { - dev_err(p->dev, "%s: tot_size(%lu) and offset(%u) dismatch\n", + dev_err(p->dev, "%s: tot_size(%lu) and offset(%u) mismatch\n", __func__, cd->total_sz, offset); return -EINVAL; } From f4ee43ae6ea8c509d470f20e7b446adf5a167dba Mon Sep 17 00:00:00 2001 From: Baojun Xu Date: Sun, 10 Aug 2025 20:23:58 +0800 Subject: [PATCH 00136/11391] ALSA: hda: Add TAS5825 support Add TAS5825 support in TI's HDA driver. TAS5825 is an on-chip DSP, but no calibration is required, and no global address support smart amplifier devices. Signed-off-by: Baojun Xu Acked-by: Mark Brown Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250810122358.1575-1-baojun.xu@ti.com --- include/sound/tas2781-dsp.h | 3 + include/sound/tas2781.h | 4 +- include/sound/tas5825-tlv.h | 24 +++++++ .../hda/codecs/side-codecs/tas2781_hda_i2c.c | 28 ++++++++ sound/soc/codecs/tas2781-fmwlib.c | 67 ++++++++++++++++++- 5 files changed, 121 insertions(+), 5 deletions(-) create mode 100644 include/sound/tas5825-tlv.h diff --git a/include/sound/tas2781-dsp.h b/include/sound/tas2781-dsp.h index c3a9efa73d5d..49bbf24d6559 100644 --- a/include/sound/tas2781-dsp.h +++ b/include/sound/tas2781-dsp.h @@ -34,6 +34,7 @@ #define PPC3_VERSION_TAS2781_BASIC_MIN 0x14600 #define PPC3_VERSION_TAS2781_ALPHA_MIN 0x4a00 #define PPC3_VERSION_TAS2781_BETA_MIN 0x19400 +#define PPC3_VERSION_TAS5825_BASE 0x114200 #define TASDEVICE_DEVICE_SUM 8 #define TASDEVICE_CONFIG_SUM 64 @@ -53,6 +54,8 @@ enum tasdevice_dsp_dev_idx { TASDEVICE_DSP_TAS_2781_DUAL_MONO, TASDEVICE_DSP_TAS_2781_21, TASDEVICE_DSP_TAS_2781_QUAD, + TASDEVICE_DSP_TAS_5825_MONO, + TASDEVICE_DSP_TAS_5825_DUAL, TASDEVICE_DSP_TAS_MAX_DEVICE }; diff --git a/include/sound/tas2781.h b/include/sound/tas2781.h index 3875e92f1ec5..f0aefc04a957 100644 --- a/include/sound/tas2781.h +++ b/include/sound/tas2781.h @@ -49,9 +49,9 @@ #define TASDEVICE_REG(book, page, reg) (((book * 256 * 128) + \ (page * 128)) + reg) -/* Software Reset */ +/* Software Reset, compatble with new device (TAS5825). */ #define TASDEVICE_REG_SWRESET TASDEVICE_REG(0x0, 0x0, 0x01) -#define TASDEVICE_REG_SWRESET_RESET BIT(0) +#define TASDEVICE_REG_SWRESET_RESET (BIT(0) | BIT(4)) /* Checksum */ #define TASDEVICE_CHECKSUM_REG TASDEVICE_REG(0x0, 0x0, 0x7e) diff --git a/include/sound/tas5825-tlv.h b/include/sound/tas5825-tlv.h new file mode 100644 index 000000000000..95f2d3fad120 --- /dev/null +++ b/include/sound/tas5825-tlv.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +// +// ALSA SoC Texas Instruments TAS5825 Audio Smart Amplifier +// +// Copyright (C) 2025 Texas Instruments Incorporated +// https://www.ti.com +// +// The TAS5825 hda driver implements for one or two TAS5825 chips. +// +// Author: Baojun Xu +// + +#ifndef __TAS5825_TLV_H__ +#define __TAS5825_TLV_H__ + +#define TAS5825_DVC_LEVEL TASDEVICE_REG(0x0, 0x0, 0x4c) +#define TAS5825_AMP_LEVEL TASDEVICE_REG(0x0, 0x0, 0x54) + +static const __maybe_unused DECLARE_TLV_DB_SCALE( + tas5825_dvc_tlv, -10300, 50, 0); +static const __maybe_unused DECLARE_TLV_DB_SCALE( + tas5825_amp_tlv, -1550, 50, 0); + +#endif diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c index e1d60da50897..8fae0fea37a0 100644 --- a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c +++ b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "hda_local.h" #include "hda_auto_parser.h" @@ -50,6 +51,7 @@ enum device_chip_id { HDA_TAS2563, HDA_TAS2770, HDA_TAS2781, + HDA_TAS5825, HDA_OTHERS }; @@ -272,6 +274,17 @@ static const struct snd_kcontrol_new tas2781_snd_controls[] = { tas2781_force_fwload_get, tas2781_force_fwload_put), }; +static const struct snd_kcontrol_new tas5825_snd_controls[] = { + ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Volume", TAS5825_AMP_LEVEL, + 0, 0, 31, 1, tas2781_amp_getvol, + tas2781_amp_putvol, tas5825_amp_tlv), + ACARD_SINGLE_RANGE_EXT_TLV("Speaker Digital Volume", TAS5825_DVC_LEVEL, + 0, 0, 254, 1, tas2781_amp_getvol, + tas2781_amp_putvol, tas5825_dvc_tlv), + ACARD_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0, + tas2781_force_fwload_get, tas2781_force_fwload_put), +}; + static const struct snd_kcontrol_new tasdevice_prof_ctrl = { .name = "Speaker Profile Id", .iface = SNDRV_CTL_ELEM_IFACE_CARD, @@ -501,6 +514,12 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context) ARRAY_SIZE(tas2781_snd_controls)); tasdevice_dspfw_init(context); break; + case HDA_TAS5825: + tasdev_add_kcontrols(tas_priv, hda_priv->snd_ctls, codec, + &tas5825_snd_controls[0], + ARRAY_SIZE(tas5825_snd_controls)); + tasdevice_dspfw_init(context); + break; case HDA_TAS2563: tasdevice_dspfw_init(context); break; @@ -628,6 +647,7 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt) } else if (strstarts(dev_name(&clt->dev), "i2c-TXNW2781:00-tas2781-hda.0")) { device_name = "TXNW2781"; + hda_priv->hda_chip_id = HDA_TAS2781; hda_priv->save_calibration = tas2781_save_calibration; tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR; } else if (strstr(dev_name(&clt->dev), "INT8866")) { @@ -639,6 +659,13 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt) hda_priv->hda_chip_id = HDA_TAS2563; hda_priv->save_calibration = tas2563_save_calibration; tas_hda->priv->global_addr = TAS2563_GLOBAL_ADDR; + } else if (strstarts(dev_name(&clt->dev), "i2c-TXNW5825")) { + /* + * TAS5825, integrated on-chip DSP without + * global I2C address and calibration supported. + */ + device_name = "TXNW5825"; + hda_priv->hda_chip_id = HDA_TAS5825; } else { return -ENODEV; } @@ -775,6 +802,7 @@ static const struct acpi_device_id tas2781_acpi_hda_match[] = { {"TIAS2781", 0 }, {"TXNW2770", 0 }, {"TXNW2781", 0 }, + {"TXNW5825", 0 }, {} }; MODULE_DEVICE_TABLE(acpi, tas2781_acpi_hda_match); diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c index c9c1e608ddb7..d69faef8a4d7 100644 --- a/sound/soc/codecs/tas2781-fmwlib.c +++ b/sound/soc/codecs/tas2781-fmwlib.c @@ -91,7 +91,7 @@ struct blktyp_devidx_map { }; static const char deviceNumber[TASDEVICE_DSP_TAS_MAX_DEVICE] = { - 1, 2, 1, 2, 1, 1, 0, 2, 4, 3, 1, 2, 3, 4 + 1, 2, 1, 2, 1, 1, 0, 2, 4, 3, 1, 2, 3, 4, 1, 2 }; /* fixed m68k compiling issue: mapping table can save code field */ @@ -509,6 +509,56 @@ static int fw_parse_data_kernel(struct tasdevice_fw *tas_fmw, return offset; } +static int fw_parse_tas5825_program_data_kernel( + struct tasdevice_priv *tas_priv, struct tasdevice_fw *tas_fmw, + const struct firmware *fmw, int offset) +{ + struct tasdevice_prog *program; + unsigned int i; + + for (i = 0; i < tas_fmw->nr_programs; i++) { + program = &(tas_fmw->programs[i]); + if (offset + 72 > fmw->size) { + dev_err(tas_priv->dev, "%s: mpName error\n", __func__); + return -EINVAL; + } + /* Skip 65 unused byts*/ + offset += 65; + offset = fw_parse_data_kernel(tas_fmw, &(program->dev_data), + fmw, offset); + if (offset < 0) + return offset; + } + + return offset; +} + +static int fw_parse_tas5825_configuration_data_kernel( + struct tasdevice_priv *tas_priv, + struct tasdevice_fw *tas_fmw, const struct firmware *fmw, int offset) +{ + const unsigned char *data = fmw->data; + struct tasdevice_config *config; + unsigned int i; + + for (i = 0; i < tas_fmw->nr_configurations; i++) { + config = &(tas_fmw->configs[i]); + if (offset + 80 > fmw->size) { + dev_err(tas_priv->dev, "%s: mpName error\n", __func__); + return -EINVAL; + } + memcpy(config->name, &data[offset], 64); + /* Skip extra 8 bytes*/ + offset += 72; + offset = fw_parse_data_kernel(tas_fmw, &(config->dev_data), + fmw, offset); + if (offset < 0) + return offset; + } + + return offset; +} + static int fw_parse_program_data_kernel( struct tasdevice_priv *tas_priv, struct tasdevice_fw *tas_fmw, const struct firmware *fmw, int offset) @@ -1826,7 +1876,8 @@ static void dspbin_type_check(struct tasdevice_priv *tas_priv, else tas_priv->dspbin_typ = TASDEV_ALPHA; } - if (tas_priv->dspbin_typ != TASDEV_BASIC) + if ((tas_priv->dspbin_typ != TASDEV_BASIC) && + (ppcver < PPC3_VERSION_TAS5825_BASE)) tas_priv->fw_parse_fct_param_address = fw_parse_fct_param_address; } @@ -1837,7 +1888,17 @@ static int dspfw_default_callback(struct tasdevice_priv *tas_priv, int rc = 0; if (drv_ver == 0x100) { - if (ppcver >= PPC3_VERSION_BASE) { + if (ppcver >= PPC3_VERSION_TAS5825_BASE) { + tas_priv->fw_parse_variable_header = + fw_parse_variable_header_kernel; + tas_priv->fw_parse_program_data = + fw_parse_tas5825_program_data_kernel; + tas_priv->fw_parse_configuration_data = + fw_parse_tas5825_configuration_data_kernel; + tas_priv->tasdevice_load_block = + tasdevice_load_block_kernel; + dspbin_type_check(tas_priv, ppcver); + } else if (ppcver >= PPC3_VERSION_BASE) { tas_priv->fw_parse_variable_header = fw_parse_variable_header_kernel; tas_priv->fw_parse_program_data = From 6d64bceb97a1c93b3cc2131f7e023ef2f9cf33f2 Mon Sep 17 00:00:00 2001 From: Nicolas Frattaroli Date: Mon, 21 Jul 2025 11:17:34 +0200 Subject: [PATCH 00137/11391] arm64: dts: rockchip: add pd_npu label for RK3588 power domains The NPU of the RK3588 has an external supply. This supply also affects the power domain of the NPU, not just the NPU device nodes themselves. Since correctly modelled boards will want the power domain to be aware of the regulator so that it doesn't always have to be on, add a label to the NPU power domain node so board files can reference it. Signed-off-by: Nicolas Frattaroli Tested-by: Heiko Stuebner Signed-off-by: Tomeu Vizoso Link: https://lore.kernel.org/r/20250721-6-10-rocket-v9-7-77ebd484941e@tomeuvizoso.net Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3588-base.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi index 70f03e68ba55..1eddc69fd9c9 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi @@ -841,7 +841,7 @@ power: power-controller { status = "okay"; /* These power domains are grouped by VD_NPU */ - power-domain@RK3588_PD_NPU { + pd_npu: power-domain@RK3588_PD_NPU { reg = ; #power-domain-cells = <0>; #address-cells = <1>; From a31dfc060a747f08705ace36d8de006bc13318fa Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Mon, 21 Jul 2025 11:17:35 +0200 Subject: [PATCH 00138/11391] arm64: dts: rockchip: Add nodes for NPU and its MMU to rk3588-base See Chapter 36 "RKNN" from the RK3588 TRM (Part 1). The IP is divided in three cores, programmed independently. The first core though is special, being able to delegate work to the other cores. The IOMMU of the first core is also special in that it has two subunits (read/write?) that need to be programmed in sync. v2: - Have one device for each NPU core (Sebastian Reichel) - Have one device for each IOMMU (Sebastian Reichel) - Correctly sort nodes (Diederik de Haas) - Add rockchip,iommu compatible to IOMMU nodes (Sebastian Reichel) v3: - Adapt to a split of the register block in the DT bindings (Nicolas Frattaroli) v4: - Adapt to changes in bindings v6: - pclk and npu clocks are needed by all clocks (Rob Herring) v8: - Remove notion of top core (Robin Murphy) Tested-by: Heiko Stuebner Signed-off-by: Tomeu Vizoso Link: https://lore.kernel.org/r/20250721-6-10-rocket-v9-8-77ebd484941e@tomeuvizoso.net Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3588-base.dtsi | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi index 1eddc69fd9c9..a18aa1e6c3f1 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi @@ -1140,6 +1140,97 @@ power-domain@RK3588_PD_SDMMC { }; }; + rknn_core_0: npu@fdab0000 { + compatible = "rockchip,rk3588-rknn-core"; + reg = <0x0 0xfdab0000 0x0 0x1000>, + <0x0 0xfdab1000 0x0 0x1000>, + <0x0 0xfdab3000 0x0 0x1000>; + reg-names = "pc", "cna", "core"; + interrupts = ; + clocks = <&cru ACLK_NPU0>, <&cru HCLK_NPU0>, + <&scmi_clk SCMI_CLK_NPU>, <&cru PCLK_NPU_ROOT>; + clock-names = "aclk", "hclk", "npu", "pclk"; + assigned-clocks = <&scmi_clk SCMI_CLK_NPU>; + assigned-clock-rates = <200000000>; + resets = <&cru SRST_A_RKNN0>, <&cru SRST_H_RKNN0>; + reset-names = "srst_a", "srst_h"; + power-domains = <&power RK3588_PD_NPUTOP>; + iommus = <&rknn_mmu_0>; + status = "disabled"; + }; + + rknn_mmu_0: iommu@fdab9000 { + compatible = "rockchip,rk3588-iommu", "rockchip,rk3568-iommu"; + reg = <0x0 0xfdab9000 0x0 0x100>, + <0x0 0xfdaba000 0x0 0x100>; + interrupts = ; + clocks = <&cru ACLK_NPU0>, <&cru HCLK_NPU0>; + clock-names = "aclk", "iface"; + #iommu-cells = <0>; + power-domains = <&power RK3588_PD_NPUTOP>; + status = "disabled"; + }; + + rknn_core_1: npu@fdac0000 { + compatible = "rockchip,rk3588-rknn-core"; + reg = <0x0 0xfdac0000 0x0 0x1000>, + <0x0 0xfdac1000 0x0 0x1000>, + <0x0 0xfdac3000 0x0 0x1000>; + reg-names = "pc", "cna", "core"; + interrupts = ; + clocks = <&cru ACLK_NPU1>, <&cru HCLK_NPU1>, + <&scmi_clk SCMI_CLK_NPU>, <&cru PCLK_NPU_ROOT>; + clock-names = "aclk", "hclk", "npu", "pclk"; + assigned-clocks = <&scmi_clk SCMI_CLK_NPU>; + assigned-clock-rates = <200000000>; + resets = <&cru SRST_A_RKNN1>, <&cru SRST_H_RKNN1>; + reset-names = "srst_a", "srst_h"; + power-domains = <&power RK3588_PD_NPU1>; + iommus = <&rknn_mmu_1>; + status = "disabled"; + }; + + rknn_mmu_1: iommu@fdac9000 { + compatible = "rockchip,rk3588-iommu", "rockchip,rk3568-iommu"; + reg = <0x0 0xfdaca000 0x0 0x100>; + interrupts = ; + clocks = <&cru ACLK_NPU1>, <&cru HCLK_NPU1>; + clock-names = "aclk", "iface"; + #iommu-cells = <0>; + power-domains = <&power RK3588_PD_NPU1>; + status = "disabled"; + }; + + rknn_core_2: npu@fdad0000 { + compatible = "rockchip,rk3588-rknn-core"; + reg = <0x0 0xfdad0000 0x0 0x1000>, + <0x0 0xfdad1000 0x0 0x1000>, + <0x0 0xfdad3000 0x0 0x1000>; + reg-names = "pc", "cna", "core"; + interrupts = ; + clocks = <&cru ACLK_NPU2>, <&cru HCLK_NPU2>, + <&scmi_clk SCMI_CLK_NPU>, <&cru PCLK_NPU_ROOT>; + clock-names = "aclk", "hclk", "npu", "pclk"; + assigned-clocks = <&scmi_clk SCMI_CLK_NPU>; + assigned-clock-rates = <200000000>; + resets = <&cru SRST_A_RKNN2>, <&cru SRST_H_RKNN2>; + reset-names = "srst_a", "srst_h"; + power-domains = <&power RK3588_PD_NPU2>; + iommus = <&rknn_mmu_2>; + status = "disabled"; + }; + + rknn_mmu_2: iommu@fdad9000 { + compatible = "rockchip,rk3588-iommu", "rockchip,rk3568-iommu"; + reg = <0x0 0xfdada000 0x0 0x100>; + interrupts = ; + clocks = <&cru ACLK_NPU2>, <&cru HCLK_NPU2>; + clock-names = "aclk", "iface"; + #iommu-cells = <0>; + power-domains = <&power RK3588_PD_NPU2>; + status = "disabled"; + }; + vpu121: video-codec@fdb50000 { compatible = "rockchip,rk3588-vpu121", "rockchip,rk3568-vpu"; reg = <0x0 0xfdb50000 0x0 0x800>; From 640366d644b1e282771a09c72be37162b6eda438 Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Mon, 21 Jul 2025 11:17:36 +0200 Subject: [PATCH 00139/11391] arm64: dts: rockchip: Enable the NPU on quartzpro64 Enable the nodes added in a previous commit to the rk3588s device tree. v2: - Split nodes (Sebastian Reichel) - Sort nodes (Sebastian Reichel) - Add board regulators (Sebastian Reichel) v8: - Remove notion of top core (Robin Murphy) Tested-by: Heiko Stuebner Signed-off-by: Tomeu Vizoso Link: https://lore.kernel.org/r/20250721-6-10-rocket-v9-9-77ebd484941e@tomeuvizoso.net Signed-off-by: Heiko Stuebner --- .../boot/dts/rockchip/rk3588-quartzpro64.dts | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3588-quartzpro64.dts b/arch/arm64/boot/dts/rockchip/rk3588-quartzpro64.dts index 78aaa6635b5d..b2336c36da01 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-quartzpro64.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-quartzpro64.dts @@ -415,6 +415,36 @@ &pcie3x4 { status = "okay"; }; +&rknn_core_0 { + npu-supply = <&vdd_npu_s0>; + sram-supply = <&vdd_npu_mem_s0>; + status = "okay"; +}; + +&rknn_core_1 { + npu-supply = <&vdd_npu_s0>; + sram-supply = <&vdd_npu_mem_s0>; + status = "okay"; +}; + +&rknn_core_2 { + npu-supply = <&vdd_npu_s0>; + sram-supply = <&vdd_npu_mem_s0>; + status = "okay"; +}; + +&rknn_mmu_0 { + status = "okay"; +}; + +&rknn_mmu_1 { + status = "okay"; +}; + +&rknn_mmu_2 { + status = "okay"; +}; + &saradc { vref-supply = <&vcc_1v8_s0>; status = "okay"; From 3af6a83fc85033e44ce5cd0e1de54dc20b7e15af Mon Sep 17 00:00:00 2001 From: Nicolas Frattaroli Date: Mon, 21 Jul 2025 11:17:37 +0200 Subject: [PATCH 00140/11391] arm64: dts: rockchip: enable NPU on ROCK 5B The NPU on the ROCK5B uses the same regulator for both the sram-supply and the npu's supply. Add this regulator, and enable all the NPU bits. Also add the regulator as a domain-supply to the pd_npu power domain. v8: - Remove notion of top core (Robin Murphy) Signed-off-by: Nicolas Frattaroli Tested-by: Heiko Stuebner Signed-off-by: Tomeu Vizoso Link: https://lore.kernel.org/r/20250721-6-10-rocket-v9-10-77ebd484941e@tomeuvizoso.net Signed-off-by: Heiko Stuebner --- .../dts/rockchip/rk3588-rock-5b-5bp-5t.dtsi | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b-5bp-5t.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b-5bp-5t.dtsi index 973d39a7e0e0..612808d2b4c5 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b-5bp-5t.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b-5bp-5t.dtsi @@ -268,6 +268,29 @@ regulator-state-mem { }; }; +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1m2_xfer>; + status = "okay"; + + vdd_npu_s0: regulator@42 { + compatible = "rockchip,rk8602"; + reg = <0x42>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "vdd_npu_s0"; + regulator-boot-on; + regulator-enable-ramp-delay = <500>; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc5v0_sys>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; +}; + &i2c6 { status = "okay"; @@ -392,6 +415,10 @@ &pd_gpu { domain-supply = <&vdd_gpu_s0>; }; +&pd_npu { + domain-supply = <&vdd_npu_s0>; +}; + &pinctrl { hym8563 { hym8563_int: hym8563-int { @@ -424,6 +451,36 @@ &pwm1 { status = "okay"; }; +&rknn_core_0 { + npu-supply = <&vdd_npu_s0>; + sram-supply = <&vdd_npu_s0>; + status = "okay"; +}; + +&rknn_core_1 { + npu-supply = <&vdd_npu_s0>; + sram-supply = <&vdd_npu_s0>; + status = "okay"; +}; + +&rknn_core_2 { + npu-supply = <&vdd_npu_s0>; + sram-supply = <&vdd_npu_s0>; + status = "okay"; +}; + +&rknn_mmu_0 { + status = "okay"; +}; + +&rknn_mmu_1 { + status = "okay"; +}; + +&rknn_mmu_2 { + status = "okay"; +}; + &saradc { vref-supply = <&avcc_1v8_s0>; status = "okay"; From 1bce3444df79910512587a1f18022c396e9430b5 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Fri, 20 Jun 2025 22:17:15 +0200 Subject: [PATCH 00141/11391] arm64: dts: rockchip: convert rk3528 power-domains to dt-binding constants Now that the binding head has been merged, convert the power-domain ids back to these constants for easier handling. Reviewed-by: Jonas Karlman Signed-off-by: Heiko Stuebner Link: https://lore.kernel.org/r/20250620201715.1572609-1-heiko@sntech.de Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3528.dtsi | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3528.dtsi b/arch/arm64/boot/dts/rockchip/rk3528.dtsi index 001a555c83b7..54fa8089c4d3 100644 --- a/arch/arm64/boot/dts/rockchip/rk3528.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3528.dtsi @@ -9,6 +9,7 @@ #include #include #include +#include #include / { @@ -480,8 +481,8 @@ power: power-controller { #size-cells = <0>; /* These power domains are grouped by VD_GPU */ - power-domain@4 { - reg = <4>; + power-domain@RK3528_PD_GPU { + reg = ; clocks = <&cru ACLK_GPU_MALI>, <&cru PCLK_GPU_ROOT>; pm_qos = <&qos_gpu_m0>, @@ -490,20 +491,20 @@ power-domain@4 { }; /* These power domains are grouped by VD_LOGIC */ - power-domain@5 { - reg = <5>; + power-domain@RK3528_PD_RKVDEC { + reg = ; pm_qos = <&qos_rkvdec>; #power-domain-cells = <0>; status = "disabled"; }; - power-domain@6 { - reg = <6>; + power-domain@RK3528_PD_RKVENC { + reg = ; pm_qos = <&qos_rkvenc>; #power-domain-cells = <0>; status = "disabled"; }; - power-domain@7 { - reg = <7>; + power-domain@RK3528_PD_VO { + reg = ; pm_qos = <&qos_gmac0>, <&qos_hdcp>, <&qos_jpegdec>, @@ -516,8 +517,8 @@ power-domain@7 { #power-domain-cells = <0>; status = "disabled"; }; - power-domain@8 { - reg = <8>; + power-domain@RK3528_PD_VPU { + reg = ; pm_qos = <&qos_emmc>, <&qos_fspi>, <&qos_gmac1>, @@ -556,7 +557,7 @@ gpu: gpu@ff700000 { "pp1", "ppmmu1"; operating-points-v2 = <&gpu_opp_table>; - power-domains = <&power 4>; + power-domains = <&power RK3528_PD_GPU>; resets = <&cru SRST_A_GPU>; status = "disabled"; }; From 187a3426a664737381a70a3fca3b8108f2300de9 Mon Sep 17 00:00:00 2001 From: Ivaylo Ivanov Date: Wed, 30 Jul 2025 10:27:30 +0300 Subject: [PATCH 00142/11391] dt-bindings: soc: samsung: usi: add samsung,exynos2200-usi compatible Add samsung,exynos2200-usi dedicated compatible for representing the USI of Samsung Exynos 2200 SoC. Signed-off-by: Ivaylo Ivanov Reviewed-by: Sam Protsenko Link: https://lore.kernel.org/r/20250730072730.1882549-1-ivo.ivanov.ivanov1@gmail.com Signed-off-by: Krzysztof Kozlowski --- Documentation/devicetree/bindings/soc/samsung/exynos-usi.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/soc/samsung/exynos-usi.yaml b/Documentation/devicetree/bindings/soc/samsung/exynos-usi.yaml index cb22637091e8..c694926e56ef 100644 --- a/Documentation/devicetree/bindings/soc/samsung/exynos-usi.yaml +++ b/Documentation/devicetree/bindings/soc/samsung/exynos-usi.yaml @@ -36,6 +36,7 @@ properties: - items: - enum: - google,gs101-usi + - samsung,exynos2200-usi - samsung,exynosautov9-usi - samsung,exynosautov920-usi - const: samsung,exynos850-usi From 03db20aaa3ba3998b5a025e243b04e33b5bdefa5 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Mon, 28 Jul 2025 08:05:43 +0200 Subject: [PATCH 00143/11391] gpio: stmpe: Allow to compile as a module Add the necessary boilerplate to also make this driver modular. Keep the subsys_initcall to not change registration order for built-in. Also add OF match table for module autoloading. Signed-off-by: Alexander Stein Link: https://lore.kernel.org/r/20250728060544.18169-1-alexander.stein@ew.tq-group.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/Kconfig | 2 +- drivers/gpio/gpio-stmpe.c | 20 ++++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index e43abb322fa6..a437fe652dbc 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1559,7 +1559,7 @@ config GPIO_SL28CPLD called gpio-sl28cpld. config GPIO_STMPE - bool "STMPE GPIOs" + tristate "STMPE GPIOs" depends on MFD_STMPE depends on OF_GPIO select GPIOLIB_IRQCHIP diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 5dd4c21a8e60..7bf270af07fe 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -534,10 +534,16 @@ static int stmpe_gpio_probe(struct platform_device *pdev) return devm_gpiochip_add_data(dev, &stmpe_gpio->chip, stmpe_gpio); } +static const struct of_device_id stmpe_gpio_of_matches[] = { + { .compatible = "st,stmpe-gpio", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, stmpe_gpio_of_matches); + static struct platform_driver stmpe_gpio_driver = { .driver = { - .suppress_bind_attrs = true, - .name = "stmpe-gpio", + .name = "stmpe-gpio", + .of_match_table = stmpe_gpio_of_matches, }, .probe = stmpe_gpio_probe, }; @@ -547,3 +553,13 @@ static int __init stmpe_gpio_init(void) return platform_driver_register(&stmpe_gpio_driver); } subsys_initcall(stmpe_gpio_init); + +static void __exit stmpe_gpio_exit(void) +{ + platform_driver_unregister(&stmpe_gpio_driver); +} +module_exit(stmpe_gpio_exit); + +MODULE_DESCRIPTION("STMPE expander GPIO"); +MODULE_AUTHOR("Rabin Vincent "); +MODULE_LICENSE("GPL"); From 7ce73ee6dc5977fd9dbe8194e7e8073a2f9a50fb Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 31 Jul 2025 17:16:37 +0800 Subject: [PATCH 00144/11391] gpio: aggregator: fix macros coding style error These changes just fix Linux Kernel Coding Style, no functional improve. -Macros with complex values should be enclosed in parentheses Signed-off-by: Li Jun Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20250731091637.595136-1-lijun01@kylinos.cn Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-aggregator.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index af9d8b3a711d..f83aa60d8945 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -247,8 +247,8 @@ struct gpiochip_fwd { unsigned long tmp[]; /* values and descs for multiple ops */ }; -#define fwd_tmp_values(fwd) &(fwd)->tmp[0] -#define fwd_tmp_descs(fwd) (void *)&(fwd)->tmp[BITS_TO_LONGS((fwd)->chip.ngpio)] +#define fwd_tmp_values(fwd) (&(fwd)->tmp[0]) +#define fwd_tmp_descs(fwd) ((void *)&(fwd)->tmp[BITS_TO_LONGS((fwd)->chip.ngpio)]) #define fwd_tmp_size(ngpios) (BITS_TO_LONGS((ngpios)) + (ngpios)) From 0d1e68fb1efd2fe951d68cf05460e3672d4a846d Mon Sep 17 00:00:00 2001 From: Waqar Hameed Date: Tue, 5 Aug 2025 11:33:33 +0200 Subject: [PATCH 00145/11391] gpio: twl4030: 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 Link: https://lore.kernel.org/r/pndjz3im7te.a.out@axis.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-twl4030.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index a33dc7c7e7a0..a851702befde 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -597,9 +597,7 @@ static int gpio_twl4030_probe(struct platform_device *pdev) ret = devm_add_action_or_reset(&pdev->dev, gpio_twl4030_power_off_action, d); if (ret) - return dev_err_probe(&pdev->dev, ret, - "failed to install power off handler\n"); - + return ret; } return 0; From 9f683dfe8099639f9ac859287744a9ed1c3698a0 Mon Sep 17 00:00:00 2001 From: Petr Tesarik Date: Thu, 10 Jul 2025 10:38:29 +0200 Subject: [PATCH 00146/11391] dma-direct: clean up the logic in __dma_direct_alloc_pages() Convert a goto-based loop to a while() loop. To allow the simplification, return early when allocation from CMA is successful. As a bonus, this early return avoids a repeated dma_coherent_ok() check. No functional change. Signed-off-by: Petr Tesarik Signed-off-by: Marek Szyprowski Link: https://lore.kernel.org/r/20250710083829.1853466-1-ptesarik@suse.com --- kernel/dma/direct.c | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c index 24c359d9c879..302e89580972 100644 --- a/kernel/dma/direct.c +++ b/kernel/dma/direct.c @@ -120,7 +120,7 @@ static struct page *__dma_direct_alloc_pages(struct device *dev, size_t size, gfp_t gfp, bool allow_highmem) { int node = dev_to_node(dev); - struct page *page = NULL; + struct page *page; u64 phys_limit; WARN_ON_ONCE(!PAGE_ALIGNED(size)); @@ -131,30 +131,25 @@ static struct page *__dma_direct_alloc_pages(struct device *dev, size_t size, gfp |= dma_direct_optimal_gfp_mask(dev, &phys_limit); page = dma_alloc_contiguous(dev, size, gfp); if (page) { - if (!dma_coherent_ok(dev, page_to_phys(page), size) || - (!allow_highmem && PageHighMem(page))) { - dma_free_contiguous(dev, page, size); - page = NULL; - } + if (dma_coherent_ok(dev, page_to_phys(page), size) && + (allow_highmem || !PageHighMem(page))) + return page; + + dma_free_contiguous(dev, page, size); } -again: - if (!page) - page = alloc_pages_node(node, gfp, get_order(size)); - if (page && !dma_coherent_ok(dev, page_to_phys(page), size)) { + + while ((page = alloc_pages_node(node, gfp, get_order(size))) + && !dma_coherent_ok(dev, page_to_phys(page), size)) { __free_pages(page, get_order(size)); - page = NULL; if (IS_ENABLED(CONFIG_ZONE_DMA32) && phys_limit < DMA_BIT_MASK(64) && - !(gfp & (GFP_DMA32 | GFP_DMA))) { + !(gfp & (GFP_DMA32 | GFP_DMA))) gfp |= GFP_DMA32; - goto again; - } - - if (IS_ENABLED(CONFIG_ZONE_DMA) && !(gfp & GFP_DMA)) { + else if (IS_ENABLED(CONFIG_ZONE_DMA) && !(gfp & GFP_DMA)) gfp = (gfp & ~GFP_DMA32) | GFP_DMA; - goto again; - } + else + return NULL; } return page; From 110aa2c74dbd9de862afc8546d1b9be4c86f9eb0 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Tue, 5 Aug 2025 10:32:22 +0800 Subject: [PATCH 00147/11391] swiotlb: 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 Signed-off-by: Marek Szyprowski Link: https://lore.kernel.org/r/20250805023222.332920-1-rongqianfeng@vivo.com --- kernel/dma/swiotlb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c index abcf3fa63a56..0d37da3d95b6 100644 --- a/kernel/dma/swiotlb.c +++ b/kernel/dma/swiotlb.c @@ -1209,7 +1209,7 @@ static int swiotlb_find_slots(struct device *dev, phys_addr_t orig_addr, nslabs = nr_slots(alloc_size); phys_limit = min_not_zero(*dev->dma_mask, dev->bus_dma_limit); pool = swiotlb_alloc_pool(dev, nslabs, nslabs, 1, phys_limit, - GFP_NOWAIT | __GFP_NOWARN); + GFP_NOWAIT); if (!pool) return -1; From 8d81298d87f4a864ab8c786e82ca196a5001a531 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Mon, 28 Jul 2025 11:52:37 +0200 Subject: [PATCH 00148/11391] MAINTAINERS: Use https:// protocol for Reset Controller Framework tree Use https:// protocol, the git.pengutronix.de server does not support git:// anymore. Reported-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20250728095237.494132-1-p.zabel@pengutronix.de Signed-off-by: Philipp Zabel --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index fe168477caa4..be6d0c77aa9f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -21544,7 +21544,7 @@ F: drivers/iio/potentiometer/x9250.c RESET CONTROLLER FRAMEWORK M: Philipp Zabel S: Maintained -T: git git://git.pengutronix.de/git/pza/linux +T: git https://git.pengutronix.de/git/pza/linux.git F: Documentation/devicetree/bindings/reset/ F: Documentation/driver-api/reset.rst F: drivers/reset/ From 8912b2862b9b74a0dc4e3ea1aacdec2f8abd7e1d Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Wed, 9 Jul 2025 17:08:13 +0100 Subject: [PATCH 00149/11391] pinctrl: renesas: rzg2l: Fix invalid unsigned return in rzg3s_oen_read() rzg3s_oen_read() returns a u32 value, but previously propagated a negative error code from rzg3s_pin_to_oen_bit(), resulting in an unintended large positive value due to unsigned conversion. This caused incorrect output-enable reporting for certain pins. Without this patch, pins P1_0-P1_4 and P7_0-P7_4 are incorrectly reported as "output enabled" in the pinconf-pins debugfs file. With this fix, only P1_0-P1_1 and P7_0-P7_1 are shown as "output enabled", which matches the hardware manual. Fix this by returning 0 when the OEN bit lookup fails, treating the pin as output-disabled by default. Fixes: a9024a323af2 ("pinctrl: renesas: rzg2l: Clean up and refactor OEN read/write functions") Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250709160819.306875-2-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/renesas/pinctrl-rzg2l.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c index c52263c2a7b0..22bc5b8f65fd 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c +++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c @@ -1124,7 +1124,7 @@ static u32 rzg3s_oen_read(struct rzg2l_pinctrl *pctrl, unsigned int _pin) bit = rzg3s_pin_to_oen_bit(pctrl, _pin); if (bit < 0) - return bit; + return 0; return !(readb(pctrl->base + ETH_MODE) & BIT(bit)); } From 27c76cc93c6c2ee6c0d7fec6dedc1214a977e66f Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Wed, 6 Aug 2025 20:55:50 +0100 Subject: [PATCH 00150/11391] pinctrl: renesas: rzg2l: Parameterize OEN register offset Prepare for supporting SoCs with varying OEN register locations by parameterizing the OEN offset in the rzg2l driver. Introduce an `oen` field in the rzg2l_register_offsets structure and update rzg2l_read_oen(), rzg2l_write_oen(), suspend/resume caching, and SoC hwcfg entries to use this offset instead of the hard-coded ETH_MODE value. As part of this change, rename the field `eth_mode` in the register cache to `oen` to better reflect its general purpose and decouple the naming from a specific register. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250806195555.1372317-3-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/renesas/pinctrl-rzg2l.c | 29 +++++++++++++++---------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c index 22bc5b8f65fd..55f40103b7da 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c +++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c @@ -146,7 +146,6 @@ #define SD_CH(off, ch) ((off) + (ch) * 4) #define ETH_POC(off, ch) ((off) + (ch) * 4) #define QSPI (0x3008) -#define ETH_MODE (0x3018) #define PFC_OEN (0x3C40) /* known on RZ/V2H(P) only */ #define PVDD_2500 2 /* I/O domain voltage 2.5V */ @@ -221,11 +220,13 @@ static const struct pin_config_item renesas_rzv2h_conf_items[] = { * @pwpr: PWPR register offset * @sd_ch: SD_CH register offset * @eth_poc: ETH_POC register offset + * @oen: OEN register offset */ struct rzg2l_register_offsets { u16 pwpr; u16 sd_ch; u16 eth_poc; + u16 oen; }; /** @@ -322,7 +323,7 @@ struct rzg2l_pinctrl_pin_settings { * @ien: IEN registers cache * @sd_ch: SD_CH registers cache * @eth_poc: ET_POC registers cache - * @eth_mode: ETH_MODE register cache + * @oen: Output Enable register cache * @qspi: QSPI registers cache */ struct rzg2l_pinctrl_reg_cache { @@ -335,7 +336,7 @@ struct rzg2l_pinctrl_reg_cache { u32 *pupd[2]; u8 sd_ch[2]; u8 eth_poc[2]; - u8 eth_mode; + u8 oen; u8 qspi; }; @@ -1073,11 +1074,12 @@ static u32 rzg2l_read_oen(struct rzg2l_pinctrl *pctrl, unsigned int _pin) if (bit < 0) return 0; - return !(readb(pctrl->base + ETH_MODE) & BIT(bit)); + return !(readb(pctrl->base + pctrl->data->hwcfg->regs.oen) & BIT(bit)); } static int rzg2l_write_oen(struct rzg2l_pinctrl *pctrl, unsigned int _pin, u8 oen) { + u16 oen_offset = pctrl->data->hwcfg->regs.oen; unsigned long flags; int bit; u8 val; @@ -1087,12 +1089,12 @@ static int rzg2l_write_oen(struct rzg2l_pinctrl *pctrl, unsigned int _pin, u8 oe return bit; spin_lock_irqsave(&pctrl->lock, flags); - val = readb(pctrl->base + ETH_MODE); + val = readb(pctrl->base + oen_offset); if (oen) val &= ~BIT(bit); else val |= BIT(bit); - writeb(val, pctrl->base + ETH_MODE); + writeb(val, pctrl->base + oen_offset); spin_unlock_irqrestore(&pctrl->lock, flags); return 0; @@ -1126,11 +1128,12 @@ static u32 rzg3s_oen_read(struct rzg2l_pinctrl *pctrl, unsigned int _pin) if (bit < 0) return 0; - return !(readb(pctrl->base + ETH_MODE) & BIT(bit)); + return !(readb(pctrl->base + pctrl->data->hwcfg->regs.oen) & BIT(bit)); } static int rzg3s_oen_write(struct rzg2l_pinctrl *pctrl, unsigned int _pin, u8 oen) { + u16 oen_offset = pctrl->data->hwcfg->regs.oen; unsigned long flags; int bit; u8 val; @@ -1140,12 +1143,12 @@ static int rzg3s_oen_write(struct rzg2l_pinctrl *pctrl, unsigned int _pin, u8 oe return bit; spin_lock_irqsave(&pctrl->lock, flags); - val = readb(pctrl->base + ETH_MODE); + val = readb(pctrl->base + oen_offset); if (oen) val &= ~BIT(bit); else val |= BIT(bit); - writeb(val, pctrl->base + ETH_MODE); + writeb(val, pctrl->base + oen_offset); spin_unlock_irqrestore(&pctrl->lock, flags); return 0; @@ -3164,7 +3167,8 @@ static int rzg2l_pinctrl_suspend_noirq(struct device *dev) } cache->qspi = readb(pctrl->base + QSPI); - cache->eth_mode = readb(pctrl->base + ETH_MODE); + if (pctrl->data->hwcfg->regs.oen) + cache->oen = readb(pctrl->base + pctrl->data->hwcfg->regs.oen); if (!atomic_read(&pctrl->wakeup_path)) clk_disable_unprepare(pctrl->clk); @@ -3189,7 +3193,8 @@ static int rzg2l_pinctrl_resume_noirq(struct device *dev) } writeb(cache->qspi, pctrl->base + QSPI); - writeb(cache->eth_mode, pctrl->base + ETH_MODE); + if (pctrl->data->hwcfg->regs.oen) + writeb(cache->oen, pctrl->base + pctrl->data->hwcfg->regs.oen); for (u8 i = 0; i < 2; i++) { if (regs->sd_ch) writeb(cache->sd_ch[i], pctrl->base + SD_CH(regs->sd_ch, i)); @@ -3241,6 +3246,7 @@ static const struct rzg2l_hwcfg rzg2l_hwcfg = { .pwpr = 0x3014, .sd_ch = 0x3000, .eth_poc = 0x300c, + .oen = 0x3018, }, .iolh_groupa_ua = { /* 3v3 power source */ @@ -3256,6 +3262,7 @@ static const struct rzg2l_hwcfg rzg3s_hwcfg = { .pwpr = 0x3000, .sd_ch = 0x3004, .eth_poc = 0x3010, + .oen = 0x3018, }, .iolh_groupa_ua = { /* 1v8 power source */ From a3455a0c24834eaa20f032b214d53b1607d60073 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Wed, 6 Aug 2025 20:55:51 +0100 Subject: [PATCH 00151/11391] pinctrl: renesas: rzg2l: Unify OEN access by making pin-to-bit mapping configurable Refactor the RZG2L pinctrl driver to support reuse of the common rzg2l_read_oen() and rzg2l_write_oen() helpers across SoCs with different output-enable (OEN) bit mappings. Introduce a new `pin_to_oen_bit` callback in `struct rzg2l_pinctrl_data` to allow SoCs to provide custom logic for mapping a pin to its OEN bit. Update the generic OEN read/write paths to use this callback when present. With this change, SoCs like RZ/G3S can reuse the common OEN handling code by simply supplying their own `pin_to_oen_bit` implementation. The previously duplicated `rzg3s_oen_read()` and `rzg3s_oen_write()` functions are now removed. This improves maintainability and prepares the driver for supporting future SoCs with minimal duplication. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250806195555.1372317-4-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/renesas/pinctrl-rzg2l.c | 54 +++++++------------------ 1 file changed, 15 insertions(+), 39 deletions(-) diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c index 55f40103b7da..0245c657a3ad 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c +++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c @@ -296,6 +296,7 @@ struct rzg2l_pinctrl_data { #endif void (*pwpr_pfc_lock_unlock)(struct rzg2l_pinctrl *pctrl, bool lock); void (*pmc_writeb)(struct rzg2l_pinctrl *pctrl, u8 val, u16 offset); + int (*pin_to_oen_bit)(struct rzg2l_pinctrl *pctrl, unsigned int _pin); u32 (*oen_read)(struct rzg2l_pinctrl *pctrl, unsigned int _pin); int (*oen_write)(struct rzg2l_pinctrl *pctrl, unsigned int _pin, u8 oen); int (*hw_to_bias_param)(unsigned int val); @@ -1070,7 +1071,10 @@ static u32 rzg2l_read_oen(struct rzg2l_pinctrl *pctrl, unsigned int _pin) { int bit; - bit = rzg2l_pin_to_oen_bit(pctrl, _pin); + if (!pctrl->data->pin_to_oen_bit) + return 0; + + bit = pctrl->data->pin_to_oen_bit(pctrl, _pin); if (bit < 0) return 0; @@ -1084,9 +1088,12 @@ static int rzg2l_write_oen(struct rzg2l_pinctrl *pctrl, unsigned int _pin, u8 oe int bit; u8 val; - bit = rzg2l_pin_to_oen_bit(pctrl, _pin); + if (!pctrl->data->pin_to_oen_bit) + return -EINVAL; + + bit = pctrl->data->pin_to_oen_bit(pctrl, _pin); if (bit < 0) - return bit; + return -EINVAL; spin_lock_irqsave(&pctrl->lock, flags); val = readb(pctrl->base + oen_offset); @@ -1120,40 +1127,6 @@ static int rzg3s_pin_to_oen_bit(struct rzg2l_pinctrl *pctrl, unsigned int _pin) return bit; } -static u32 rzg3s_oen_read(struct rzg2l_pinctrl *pctrl, unsigned int _pin) -{ - int bit; - - bit = rzg3s_pin_to_oen_bit(pctrl, _pin); - if (bit < 0) - return 0; - - return !(readb(pctrl->base + pctrl->data->hwcfg->regs.oen) & BIT(bit)); -} - -static int rzg3s_oen_write(struct rzg2l_pinctrl *pctrl, unsigned int _pin, u8 oen) -{ - u16 oen_offset = pctrl->data->hwcfg->regs.oen; - unsigned long flags; - int bit; - u8 val; - - bit = rzg3s_pin_to_oen_bit(pctrl, _pin); - if (bit < 0) - return bit; - - spin_lock_irqsave(&pctrl->lock, flags); - val = readb(pctrl->base + oen_offset); - if (oen) - val &= ~BIT(bit); - else - val |= BIT(bit); - writeb(val, pctrl->base + oen_offset); - spin_unlock_irqrestore(&pctrl->lock, flags); - - return 0; -} - static int rzg2l_hw_to_bias_param(unsigned int bias) { switch (bias) { @@ -3312,6 +3285,7 @@ static struct rzg2l_pinctrl_data r9a07g043_data = { #endif .pwpr_pfc_lock_unlock = &rzg2l_pwpr_pfc_lock_unlock, .pmc_writeb = &rzg2l_pmc_writeb, + .pin_to_oen_bit = &rzg2l_pin_to_oen_bit, .oen_read = &rzg2l_read_oen, .oen_write = &rzg2l_write_oen, .hw_to_bias_param = &rzg2l_hw_to_bias_param, @@ -3329,6 +3303,7 @@ static struct rzg2l_pinctrl_data r9a07g044_data = { .hwcfg = &rzg2l_hwcfg, .pwpr_pfc_lock_unlock = &rzg2l_pwpr_pfc_lock_unlock, .pmc_writeb = &rzg2l_pmc_writeb, + .pin_to_oen_bit = &rzg2l_pin_to_oen_bit, .oen_read = &rzg2l_read_oen, .oen_write = &rzg2l_write_oen, .hw_to_bias_param = &rzg2l_hw_to_bias_param, @@ -3345,8 +3320,9 @@ static struct rzg2l_pinctrl_data r9a08g045_data = { .hwcfg = &rzg3s_hwcfg, .pwpr_pfc_lock_unlock = &rzg2l_pwpr_pfc_lock_unlock, .pmc_writeb = &rzg2l_pmc_writeb, - .oen_read = &rzg3s_oen_read, - .oen_write = &rzg3s_oen_write, + .pin_to_oen_bit = &rzg3s_pin_to_oen_bit, + .oen_read = &rzg2l_read_oen, + .oen_write = &rzg2l_write_oen, .hw_to_bias_param = &rzg2l_hw_to_bias_param, .bias_param_to_hw = &rzg2l_bias_param_to_hw, }; From dd0d40d8f4ac8c2cb5967fdb2e1efa70cfc0c9ee Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Wed, 6 Aug 2025 20:55:52 +0100 Subject: [PATCH 00152/11391] pinctrl: renesas: rzg2l: Remove OEN ops for RZ/G3E The RZ/G3E pin controller does not advertise PIN_CFG_OEN capability, so there is no valid mapping for output-enable bits on this SoC. Remove the oen_read and oen_write callbacks from the RZ/G3E driver data to defer OEN support until PIN_CFG_OEN support is added. This is a preparatory change for future unification of OEN handling across the driver. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250806195555.1372317-5-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/renesas/pinctrl-rzg2l.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c index 0245c657a3ad..3aa552e1d7ab 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c +++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c @@ -3344,8 +3344,6 @@ static struct rzg2l_pinctrl_data r9a09g047_data = { #endif .pwpr_pfc_lock_unlock = &rzv2h_pwpr_pfc_lock_unlock, .pmc_writeb = &rzv2h_pmc_writeb, - .oen_read = &rzv2h_oen_read, - .oen_write = &rzv2h_oen_write, .hw_to_bias_param = &rzv2h_hw_to_bias_param, .bias_param_to_hw = &rzv2h_bias_param_to_hw, }; From cd39805be85b8ff45b0ad2715d8de48dbe404cee Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Wed, 6 Aug 2025 20:55:53 +0100 Subject: [PATCH 00153/11391] pinctrl: renesas: rzg2l: Unify OEN handling across RZ/{G2L,V2H,V2N} Unify the OEN handling on RZ/V2H(P) and RZ/V2N SoCs by reusing the existing rzg2l_read_oen and rzg2l_write_oen functions from RZ/G2L. Add a pin_to_oen_bit callback in rzg2l_pinctrl_data to look up per-pin OEN bit positions, and introduce an oen_pwpr_lock flag in the hwcfg to manage PWPR locking on SoCs that require it (RZ/V2H(P) family). Remove the hardcoded PFC_OEN define and obsolete per-SoC OEN helpers. Also drop redundant checks for the OEN offset in the suspend/resume paths, as all supported SoCs now provide a valid offset through the `regs.oen` field. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250806195555.1372317-6-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/renesas/pinctrl-rzg2l.c | 68 ++++++++----------------- 1 file changed, 22 insertions(+), 46 deletions(-) diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c index 3aa552e1d7ab..bb79d08482e1 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c +++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c @@ -146,7 +146,6 @@ #define SD_CH(off, ch) ((off) + (ch) * 4) #define ETH_POC(off, ch) ((off) + (ch) * 4) #define QSPI (0x3008) -#define PFC_OEN (0x3C40) /* known on RZ/V2H(P) only */ #define PVDD_2500 2 /* I/O domain voltage 2.5V */ #define PVDD_1800 1 /* I/O domain voltage <= 1.8V */ @@ -255,6 +254,7 @@ enum rzg2l_iolh_index { * @iolh_groupb_oi: IOLH group B output impedance specific values * @tint_start_index: the start index for the TINT interrupts * @drive_strength_ua: drive strength in uA is supported (otherwise mA is supported) + * @oen_pwpr_lock: flag indicating if the OEN register is locked by PWPR * @func_base: base number for port function (see register PFC) * @oen_max_pin: the maximum pin number supporting output enable * @oen_max_port: the maximum port number supporting output enable @@ -267,6 +267,7 @@ struct rzg2l_hwcfg { u16 iolh_groupb_oi[4]; u16 tint_start_index; bool drive_strength_ua; + bool oen_pwpr_lock; u8 func_base; u8 oen_max_pin; u8 oen_max_port; @@ -1083,10 +1084,11 @@ static u32 rzg2l_read_oen(struct rzg2l_pinctrl *pctrl, unsigned int _pin) static int rzg2l_write_oen(struct rzg2l_pinctrl *pctrl, unsigned int _pin, u8 oen) { + const struct rzg2l_register_offsets *regs = &pctrl->data->hwcfg->regs; u16 oen_offset = pctrl->data->hwcfg->regs.oen; unsigned long flags; + u8 val, pwpr; int bit; - u8 val; if (!pctrl->data->pin_to_oen_bit) return -EINVAL; @@ -1101,7 +1103,13 @@ static int rzg2l_write_oen(struct rzg2l_pinctrl *pctrl, unsigned int _pin, u8 oe val &= ~BIT(bit); else val |= BIT(bit); + if (pctrl->data->hwcfg->oen_pwpr_lock) { + pwpr = readb(pctrl->base + regs->pwpr); + writeb(pwpr | PWPR_REGWE_B, pctrl->base + regs->pwpr); + } writeb(val, pctrl->base + oen_offset); + if (pctrl->data->hwcfg->oen_pwpr_lock) + writeb(pwpr & ~PWPR_REGWE_B, pctrl->base + regs->pwpr); spin_unlock_irqrestore(&pctrl->lock, flags); return 0; @@ -1192,7 +1200,7 @@ static int rzv2h_bias_param_to_hw(enum pin_config_param param) return -EINVAL; } -static u8 rzv2h_pin_to_oen_bit(struct rzg2l_pinctrl *pctrl, unsigned int _pin) +static int rzv2h_pin_to_oen_bit(struct rzg2l_pinctrl *pctrl, unsigned int _pin) { static const char * const pin_names[] = { "ET0_TXC_TXCLK", "ET1_TXC_TXCLK", "XSPI0_RESET0N", "XSPI0_CS0N", @@ -1206,41 +1214,7 @@ static u8 rzv2h_pin_to_oen_bit(struct rzg2l_pinctrl *pctrl, unsigned int _pin) } /* Should not happen. */ - return 0; -} - -static u32 rzv2h_oen_read(struct rzg2l_pinctrl *pctrl, unsigned int _pin) -{ - u8 bit; - - bit = rzv2h_pin_to_oen_bit(pctrl, _pin); - - return !(readb(pctrl->base + PFC_OEN) & BIT(bit)); -} - -static int rzv2h_oen_write(struct rzg2l_pinctrl *pctrl, unsigned int _pin, u8 oen) -{ - const struct rzg2l_hwcfg *hwcfg = pctrl->data->hwcfg; - const struct rzg2l_register_offsets *regs = &hwcfg->regs; - unsigned long flags; - u8 val, bit; - u8 pwpr; - - bit = rzv2h_pin_to_oen_bit(pctrl, _pin); - spin_lock_irqsave(&pctrl->lock, flags); - val = readb(pctrl->base + PFC_OEN); - if (oen) - val &= ~BIT(bit); - else - val |= BIT(bit); - - pwpr = readb(pctrl->base + regs->pwpr); - writeb(pwpr | PWPR_REGWE_B, pctrl->base + regs->pwpr); - writeb(val, pctrl->base + PFC_OEN); - writeb(pwpr & ~PWPR_REGWE_B, pctrl->base + regs->pwpr); - spin_unlock_irqrestore(&pctrl->lock, flags); - - return 0; + return -EINVAL; } static int rzg2l_pinctrl_pinconf_get(struct pinctrl_dev *pctldev, @@ -3140,8 +3114,7 @@ static int rzg2l_pinctrl_suspend_noirq(struct device *dev) } cache->qspi = readb(pctrl->base + QSPI); - if (pctrl->data->hwcfg->regs.oen) - cache->oen = readb(pctrl->base + pctrl->data->hwcfg->regs.oen); + cache->oen = readb(pctrl->base + pctrl->data->hwcfg->regs.oen); if (!atomic_read(&pctrl->wakeup_path)) clk_disable_unprepare(pctrl->clk); @@ -3166,8 +3139,7 @@ static int rzg2l_pinctrl_resume_noirq(struct device *dev) } writeb(cache->qspi, pctrl->base + QSPI); - if (pctrl->data->hwcfg->regs.oen) - writeb(cache->oen, pctrl->base + pctrl->data->hwcfg->regs.oen); + writeb(cache->oen, pctrl->base + pctrl->data->hwcfg->regs.oen); for (u8 i = 0; i < 2; i++) { if (regs->sd_ch) writeb(cache->sd_ch[i], pctrl->base + SD_CH(regs->sd_ch, i)); @@ -3267,8 +3239,10 @@ static const struct rzg2l_hwcfg rzg3s_hwcfg = { static const struct rzg2l_hwcfg rzv2h_hwcfg = { .regs = { .pwpr = 0x3c04, + .oen = 0x3c40, }, .tint_start_index = 17, + .oen_pwpr_lock = true, }; static struct rzg2l_pinctrl_data r9a07g043_data = { @@ -3365,8 +3339,9 @@ static struct rzg2l_pinctrl_data r9a09g056_data = { #endif .pwpr_pfc_lock_unlock = &rzv2h_pwpr_pfc_lock_unlock, .pmc_writeb = &rzv2h_pmc_writeb, - .oen_read = &rzv2h_oen_read, - .oen_write = &rzv2h_oen_write, + .pin_to_oen_bit = &rzv2h_pin_to_oen_bit, + .oen_read = &rzg2l_read_oen, + .oen_write = &rzg2l_write_oen, .hw_to_bias_param = &rzv2h_hw_to_bias_param, .bias_param_to_hw = &rzv2h_bias_param_to_hw, }; @@ -3389,8 +3364,9 @@ static struct rzg2l_pinctrl_data r9a09g057_data = { #endif .pwpr_pfc_lock_unlock = &rzv2h_pwpr_pfc_lock_unlock, .pmc_writeb = &rzv2h_pmc_writeb, - .oen_read = &rzv2h_oen_read, - .oen_write = &rzv2h_oen_write, + .pin_to_oen_bit = &rzv2h_pin_to_oen_bit, + .oen_read = &rzg2l_read_oen, + .oen_write = &rzg2l_write_oen, .hw_to_bias_param = &rzv2h_hw_to_bias_param, .bias_param_to_hw = &rzv2h_bias_param_to_hw, }; From 54ac76e13ace31cf732bf5261811ef5af67022b7 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Wed, 6 Aug 2025 20:55:54 +0100 Subject: [PATCH 00154/11391] pinctrl: renesas: rzg2l: Add PFC_OEN support for RZ/G3E SoC Add support for configuring the PFC_OEN register on the RZ/G3E SoC to enable output-enable control for specific pins. On this SoC, certain pins such as TXC_TXCLK need to support switching between input and output modes depending on the PHY interface mode (e.g., MII vs RGMII). This functionality maps to the 'output-enable' property in the device tree and requires explicit control via the PFC_OEN register. This change updates the r9a09g047_variable_pin_cfg array to mark PB1, PE1, PL0, PL1, PL2, and PL4 with the PIN_CFG_OEN flag to indicate output-enable support. A new helper, rzg3e_pin_to_oen_bit(), is introduced to map these pin names to their respective OEN bit positions, and the corresponding callbacks are wired into the RZ/G3E SoC configuration using the generic rzg2l_read_oen() and rzg2l_write_oen() accessors. Additionally, the GPIO configuration for the PB, PE, and PL ports is updated to use the variable port pack macro, enabling per-pin configuration necessary for OEN handling. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250806195555.1372317-7-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/renesas/pinctrl-rzg2l.c | 61 +++++++++++++++++++++---- 1 file changed, 52 insertions(+), 9 deletions(-) diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c index bb79d08482e1..9ac9f3019c92 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c +++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c @@ -397,6 +397,14 @@ static const u64 r9a09g047_variable_pin_cfg[] = { RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PA, 5, RZV2H_MPXED_PIN_FUNCS), RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PA, 6, RZV2H_MPXED_PIN_FUNCS), RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PA, 7, RZV2H_MPXED_PIN_FUNCS), + RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PB, 0, RZV2H_MPXED_PIN_FUNCS), + RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PB, 1, RZV2H_MPXED_PIN_FUNCS | PIN_CFG_OEN), + RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PB, 2, RZV2H_MPXED_PIN_FUNCS), + RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PB, 3, RZV2H_MPXED_PIN_FUNCS), + RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PB, 4, RZV2H_MPXED_PIN_FUNCS), + RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PB, 5, RZV2H_MPXED_PIN_FUNCS), + RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PB, 6, RZV2H_MPXED_PIN_FUNCS), + RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PB, 7, RZV2H_MPXED_PIN_FUNCS), RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PD, 0, RZV2H_MPXED_PIN_FUNCS | PIN_CFG_IEN), RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PD, 1, RZV2H_MPXED_PIN_FUNCS), RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PD, 2, RZV2H_MPXED_PIN_FUNCS), @@ -405,6 +413,14 @@ static const u64 r9a09g047_variable_pin_cfg[] = { RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PD, 5, RZV2H_MPXED_PIN_FUNCS), RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PD, 6, RZV2H_MPXED_PIN_FUNCS), RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PD, 7, RZV2H_MPXED_PIN_FUNCS), + RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PE, 0, RZV2H_MPXED_PIN_FUNCS), + RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PE, 1, RZV2H_MPXED_PIN_FUNCS | PIN_CFG_OEN), + RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PE, 2, RZV2H_MPXED_PIN_FUNCS), + RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PE, 3, RZV2H_MPXED_PIN_FUNCS), + RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PE, 4, RZV2H_MPXED_PIN_FUNCS), + RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PE, 5, RZV2H_MPXED_PIN_FUNCS), + RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PE, 6, RZV2H_MPXED_PIN_FUNCS), + RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PE, 7, RZV2H_MPXED_PIN_FUNCS), RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PG, 0, RZV2H_MPXED_PIN_FUNCS), RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PG, 1, RZV2H_MPXED_PIN_FUNCS | PIN_CFG_IEN), RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PG, 2, RZV2H_MPXED_PIN_FUNCS | PIN_CFG_IEN), @@ -424,6 +440,14 @@ static const u64 r9a09g047_variable_pin_cfg[] = { RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PJ, 2, RZV2H_MPXED_PIN_FUNCS), RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PJ, 3, RZV2H_MPXED_PIN_FUNCS), RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PJ, 4, RZV2H_MPXED_PIN_FUNCS), + RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PL, 0, RZV2H_MPXED_PIN_FUNCS | PIN_CFG_OEN), + RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PL, 1, RZV2H_MPXED_PIN_FUNCS | PIN_CFG_OEN), + RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PL, 2, RZV2H_MPXED_PIN_FUNCS | PIN_CFG_OEN), + RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PL, 3, RZV2H_MPXED_PIN_FUNCS), + RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PL, 4, RZV2H_MPXED_PIN_FUNCS | PIN_CFG_OEN), + RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PL, 5, RZV2H_MPXED_PIN_FUNCS), + RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PL, 6, RZV2H_MPXED_PIN_FUNCS), + RZG2L_VARIABLE_PIN_CFG_PACK(RZG3E_PL, 7, RZV2H_MPXED_PIN_FUNCS), }; static const u64 r9a09g057_variable_pin_cfg[] = { @@ -1200,23 +1224,39 @@ static int rzv2h_bias_param_to_hw(enum pin_config_param param) return -EINVAL; } -static int rzv2h_pin_to_oen_bit(struct rzg2l_pinctrl *pctrl, unsigned int _pin) +static int rzg2l_pin_names_to_oen_bit(struct rzg2l_pinctrl *pctrl, unsigned int _pin, + const char * const pin_names[], unsigned int count) { - static const char * const pin_names[] = { "ET0_TXC_TXCLK", "ET1_TXC_TXCLK", - "XSPI0_RESET0N", "XSPI0_CS0N", - "XSPI0_CKN", "XSPI0_CKP" }; const struct pinctrl_pin_desc *pin_desc = &pctrl->desc.pins[_pin]; unsigned int i; - for (i = 0; i < ARRAY_SIZE(pin_names); i++) { + for (i = 0; i < count; i++) { if (!strcmp(pin_desc->name, pin_names[i])) return i; } - /* Should not happen. */ return -EINVAL; } +static int rzv2h_pin_to_oen_bit(struct rzg2l_pinctrl *pctrl, unsigned int _pin) +{ + static const char * const pin_names[] = { + "ET0_TXC_TXCLK", "ET1_TXC_TXCLK", "XSPI0_RESET0N", + "XSPI0_CS0N", "XSPI0_CKN", "XSPI0_CKP" + }; + + return rzg2l_pin_names_to_oen_bit(pctrl, _pin, pin_names, ARRAY_SIZE(pin_names)); +} + +static int rzg3e_pin_to_oen_bit(struct rzg2l_pinctrl *pctrl, unsigned int _pin) +{ + static const char * const pin_names[] = { + "PB1", "PE1", "PL4", "PL1", "PL2", "PL0" + }; + + return rzg2l_pin_names_to_oen_bit(pctrl, _pin, pin_names, ARRAY_SIZE(pin_names)); +} + static int rzg2l_pinctrl_pinconf_get(struct pinctrl_dev *pctldev, unsigned int _pin, unsigned long *config) @@ -2008,17 +2048,17 @@ static const u64 r9a09g047_gpio_configs[] = { RZG2L_GPIO_PORT_PACK(6, 0x28, RZV2H_MPXED_PIN_FUNCS), /* P8 */ 0x0, RZG2L_GPIO_PORT_PACK_VARIABLE(8, 0x2a), /* PA */ - RZG2L_GPIO_PORT_PACK(8, 0x2b, RZV2H_MPXED_PIN_FUNCS), /* PB */ + RZG2L_GPIO_PORT_PACK_VARIABLE(8, 0x2b), /* PB */ RZG2L_GPIO_PORT_PACK(3, 0x2c, RZV2H_MPXED_PIN_FUNCS), /* PC */ RZG2L_GPIO_PORT_PACK_VARIABLE(8, 0x2d), /* PD */ - RZG2L_GPIO_PORT_PACK(8, 0x2e, RZV2H_MPXED_PIN_FUNCS), /* PE */ + RZG2L_GPIO_PORT_PACK_VARIABLE(8, 0x2e), /* PE */ RZG2L_GPIO_PORT_PACK(3, 0x2f, RZV2H_MPXED_PIN_FUNCS), /* PF */ RZG2L_GPIO_PORT_PACK_VARIABLE(8, 0x30), /* PG */ RZG2L_GPIO_PORT_PACK_VARIABLE(6, 0x31), /* PH */ 0x0, RZG2L_GPIO_PORT_PACK_VARIABLE(5, 0x33), /* PJ */ RZG2L_GPIO_PORT_PACK(4, 0x34, RZV2H_MPXED_PIN_FUNCS), /* PK */ - RZG2L_GPIO_PORT_PACK(8, 0x35, RZV2H_MPXED_PIN_FUNCS), /* PL */ + RZG2L_GPIO_PORT_PACK_VARIABLE(8, 0x35), /* PL */ RZG2L_GPIO_PORT_PACK(8, 0x36, RZV2H_MPXED_PIN_FUNCS), /* PM */ 0x0, 0x0, @@ -3318,6 +3358,9 @@ static struct rzg2l_pinctrl_data r9a09g047_data = { #endif .pwpr_pfc_lock_unlock = &rzv2h_pwpr_pfc_lock_unlock, .pmc_writeb = &rzv2h_pmc_writeb, + .pin_to_oen_bit = &rzg3e_pin_to_oen_bit, + .oen_read = &rzg2l_read_oen, + .oen_write = &rzg2l_write_oen, .hw_to_bias_param = &rzv2h_hw_to_bias_param, .bias_param_to_hw = &rzv2h_bias_param_to_hw, }; From 560c633d378a0cf34afcd66c99321d6306a7e937 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Wed, 6 Aug 2025 20:55:55 +0100 Subject: [PATCH 00155/11391] pinctrl: renesas: rzg2l: Drop oen_read and oen_write callbacks Remove oen_read and oen_write callbacks from rzg2l_pinctrl_data as all SoCs now use the same rzg2l_read_oen() and rzg2l_write_oen() functions directly. Change rzg2l_read_oen() return type to int for proper error reporting and update callers to handle errors consistently. This simplifies the code by removing redundant callbacks and ensures uniform OEN handling across all supported SoCs. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250806195555.1372317-8-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/renesas/pinctrl-rzg2l.c | 35 +++++++------------------ 1 file changed, 9 insertions(+), 26 deletions(-) diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c index 9ac9f3019c92..b182b3b8a542 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c +++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c @@ -298,8 +298,6 @@ struct rzg2l_pinctrl_data { void (*pwpr_pfc_lock_unlock)(struct rzg2l_pinctrl *pctrl, bool lock); void (*pmc_writeb)(struct rzg2l_pinctrl *pctrl, u8 val, u16 offset); int (*pin_to_oen_bit)(struct rzg2l_pinctrl *pctrl, unsigned int _pin); - u32 (*oen_read)(struct rzg2l_pinctrl *pctrl, unsigned int _pin); - int (*oen_write)(struct rzg2l_pinctrl *pctrl, unsigned int _pin, u8 oen); int (*hw_to_bias_param)(unsigned int val); int (*bias_param_to_hw)(enum pin_config_param param); }; @@ -1092,16 +1090,16 @@ static int rzg2l_pin_to_oen_bit(struct rzg2l_pinctrl *pctrl, unsigned int _pin) return -EINVAL; } -static u32 rzg2l_read_oen(struct rzg2l_pinctrl *pctrl, unsigned int _pin) +static int rzg2l_read_oen(struct rzg2l_pinctrl *pctrl, unsigned int _pin) { int bit; if (!pctrl->data->pin_to_oen_bit) - return 0; + return -EOPNOTSUPP; bit = pctrl->data->pin_to_oen_bit(pctrl, _pin); if (bit < 0) - return 0; + return -EINVAL; return !(readb(pctrl->base + pctrl->data->hwcfg->regs.oen) & BIT(bit)); } @@ -1115,7 +1113,7 @@ static int rzg2l_write_oen(struct rzg2l_pinctrl *pctrl, unsigned int _pin, u8 oe int bit; if (!pctrl->data->pin_to_oen_bit) - return -EINVAL; + return -EOPNOTSUPP; bit = pctrl->data->pin_to_oen_bit(pctrl, _pin); if (bit < 0) @@ -1298,11 +1296,10 @@ static int rzg2l_pinctrl_pinconf_get(struct pinctrl_dev *pctldev, case PIN_CONFIG_OUTPUT_ENABLE: if (!(cfg & PIN_CFG_OEN)) return -EINVAL; - if (!pctrl->data->oen_read) - return -EOPNOTSUPP; - arg = pctrl->data->oen_read(pctrl, _pin); - if (!arg) - return -EINVAL; + ret = rzg2l_read_oen(pctrl, _pin); + if (ret < 0) + return ret; + arg = ret; break; case PIN_CONFIG_POWER_SOURCE: @@ -1461,9 +1458,7 @@ static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev, case PIN_CONFIG_OUTPUT_ENABLE: if (!(cfg & PIN_CFG_OEN)) return -EINVAL; - if (!pctrl->data->oen_write) - return -EOPNOTSUPP; - ret = pctrl->data->oen_write(pctrl, _pin, !!arg); + ret = rzg2l_write_oen(pctrl, _pin, !!arg); if (ret) return ret; break; @@ -3300,8 +3295,6 @@ static struct rzg2l_pinctrl_data r9a07g043_data = { .pwpr_pfc_lock_unlock = &rzg2l_pwpr_pfc_lock_unlock, .pmc_writeb = &rzg2l_pmc_writeb, .pin_to_oen_bit = &rzg2l_pin_to_oen_bit, - .oen_read = &rzg2l_read_oen, - .oen_write = &rzg2l_write_oen, .hw_to_bias_param = &rzg2l_hw_to_bias_param, .bias_param_to_hw = &rzg2l_bias_param_to_hw, }; @@ -3318,8 +3311,6 @@ static struct rzg2l_pinctrl_data r9a07g044_data = { .pwpr_pfc_lock_unlock = &rzg2l_pwpr_pfc_lock_unlock, .pmc_writeb = &rzg2l_pmc_writeb, .pin_to_oen_bit = &rzg2l_pin_to_oen_bit, - .oen_read = &rzg2l_read_oen, - .oen_write = &rzg2l_write_oen, .hw_to_bias_param = &rzg2l_hw_to_bias_param, .bias_param_to_hw = &rzg2l_bias_param_to_hw, }; @@ -3335,8 +3326,6 @@ static struct rzg2l_pinctrl_data r9a08g045_data = { .pwpr_pfc_lock_unlock = &rzg2l_pwpr_pfc_lock_unlock, .pmc_writeb = &rzg2l_pmc_writeb, .pin_to_oen_bit = &rzg3s_pin_to_oen_bit, - .oen_read = &rzg2l_read_oen, - .oen_write = &rzg2l_write_oen, .hw_to_bias_param = &rzg2l_hw_to_bias_param, .bias_param_to_hw = &rzg2l_bias_param_to_hw, }; @@ -3359,8 +3348,6 @@ static struct rzg2l_pinctrl_data r9a09g047_data = { .pwpr_pfc_lock_unlock = &rzv2h_pwpr_pfc_lock_unlock, .pmc_writeb = &rzv2h_pmc_writeb, .pin_to_oen_bit = &rzg3e_pin_to_oen_bit, - .oen_read = &rzg2l_read_oen, - .oen_write = &rzg2l_write_oen, .hw_to_bias_param = &rzv2h_hw_to_bias_param, .bias_param_to_hw = &rzv2h_bias_param_to_hw, }; @@ -3383,8 +3370,6 @@ static struct rzg2l_pinctrl_data r9a09g056_data = { .pwpr_pfc_lock_unlock = &rzv2h_pwpr_pfc_lock_unlock, .pmc_writeb = &rzv2h_pmc_writeb, .pin_to_oen_bit = &rzv2h_pin_to_oen_bit, - .oen_read = &rzg2l_read_oen, - .oen_write = &rzg2l_write_oen, .hw_to_bias_param = &rzv2h_hw_to_bias_param, .bias_param_to_hw = &rzv2h_bias_param_to_hw, }; @@ -3408,8 +3393,6 @@ static struct rzg2l_pinctrl_data r9a09g057_data = { .pwpr_pfc_lock_unlock = &rzv2h_pwpr_pfc_lock_unlock, .pmc_writeb = &rzv2h_pmc_writeb, .pin_to_oen_bit = &rzv2h_pin_to_oen_bit, - .oen_read = &rzg2l_read_oen, - .oen_write = &rzg2l_write_oen, .hw_to_bias_param = &rzv2h_hw_to_bias_param, .bias_param_to_hw = &rzv2h_bias_param_to_hw, }; From d17b34744f5e4299109801c0a151e5dd31d76936 Mon Sep 17 00:00:00 2001 From: Thierry Bultel Date: Tue, 17 Jun 2025 17:28:09 +0100 Subject: [PATCH 00156/11391] arm64: dts: renesas: Add initial support for the Renesas RZ/T2H SoC Add the initial dtsi for the RZ/T2H SoC: - GIC - ARMv8-timer - CPG clock - SCI0 UART also add arch/arm64/boot/dts/renesas/r9a09g077m44.dtsi, that keeps all 4 CPUs enabled, for consistency with later support of -m24 and -m04 SoC revisions, that only have 2 and 1 Cortex-A55, respectively, and that will use /delete-node/ to disable the missing CPUs. Signed-off-by: Thierry Bultel Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250617162810.154332-2-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- arch/arm64/boot/dts/renesas/r9a09g077.dtsi | 124 ++++++++++++++++++ arch/arm64/boot/dts/renesas/r9a09g077m44.dtsi | 13 ++ 2 files changed, 137 insertions(+) create mode 100644 arch/arm64/boot/dts/renesas/r9a09g077.dtsi create mode 100644 arch/arm64/boot/dts/renesas/r9a09g077m44.dtsi diff --git a/arch/arm64/boot/dts/renesas/r9a09g077.dtsi b/arch/arm64/boot/dts/renesas/r9a09g077.dtsi new file mode 100644 index 000000000000..42c3b86196d6 --- /dev/null +++ b/arch/arm64/boot/dts/renesas/r9a09g077.dtsi @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* + * Device Tree Source for the RZ/T2H SoC + * + * Copyright (C) 2025 Renesas Electronics Corp. + */ + +#include +#include + +/ { + compatible = "renesas,r9a09g077"; + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "arm,cortex-a55"; + reg = <0>; + device_type = "cpu"; + next-level-cache = <&L3_CA55>; + enable-method = "psci"; + }; + + cpu1: cpu@100 { + compatible = "arm,cortex-a55"; + reg = <0x100>; + device_type = "cpu"; + next-level-cache = <&L3_CA55>; + enable-method = "psci"; + }; + + cpu2: cpu@200 { + compatible = "arm,cortex-a55"; + reg = <0x200>; + device_type = "cpu"; + next-level-cache = <&L3_CA55>; + enable-method = "psci"; + }; + + cpu3: cpu@300 { + compatible = "arm,cortex-a55"; + reg = <0x300>; + device_type = "cpu"; + next-level-cache = <&L3_CA55>; + enable-method = "psci"; + }; + + L3_CA55: cache-controller-0 { + compatible = "cache"; + cache-unified; + cache-size = <0x100000>; + cache-level = <3>; + }; + }; + + extal_clk: extal { + compatible = "fixed-clock"; + #clock-cells = <0>; + /* This value must be overridden by the board */ + clock-frequency = <0>; + }; + + psci { + compatible = "arm,psci-1.0", "arm,psci-0.2"; + method = "smc"; + }; + + soc: soc { + compatible = "simple-bus"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + sci0: serial@80005000 { + compatible = "renesas,r9a09g077-rsci"; + reg = <0 0x80005000 0 0x400>; + interrupts = , + , + , + ; + interrupt-names = "eri", "rxi", "txi", "tei"; + clocks = <&cpg CPG_MOD 8>, <&cpg CPG_CORE R9A09G077_CLK_PCLKM>; + clock-names = "operation", "bus"; + power-domains = <&cpg>; + status = "disabled"; + }; + + cpg: clock-controller@80280000 { + compatible = "renesas,r9a09g077-cpg-mssr"; + reg = <0 0x80280000 0 0x1000>, + <0 0x81280000 0 0x9000>; + clocks = <&extal_clk>; + clock-names = "extal"; + #clock-cells = <2>; + #reset-cells = <1>; + #power-domain-cells = <0>; + }; + + gic: interrupt-controller@83000000 { + compatible = "arm,gic-v3"; + reg = <0x0 0x83000000 0 0x40000>, + <0x0 0x83040000 0 0x160000>; + #interrupt-cells = <3>; + #address-cells = <0>; + interrupt-controller; + interrupts = ; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts-extended = <&gic GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>, + <&gic GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>, + <&gic GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>, + <&gic GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>, + <&gic GIC_PPI 12 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "sec-phys", "phys", "virt", "hyp-phys", "hyp-virt"; + }; +}; diff --git a/arch/arm64/boot/dts/renesas/r9a09g077m44.dtsi b/arch/arm64/boot/dts/renesas/r9a09g077m44.dtsi new file mode 100644 index 000000000000..6f4a11b39d12 --- /dev/null +++ b/arch/arm64/boot/dts/renesas/r9a09g077m44.dtsi @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* + * Device Tree Source for the RZ/T2H 4-core SoC + * + * Copyright (C) 2025 Renesas Electronics Corp. + */ + +/dts-v1/; +#include "r9a09g077.dtsi" + +/ { + compatible = "renesas,r9a09g077m44", "renesas,r9a09g077"; +}; From a38f991fa19cb0d9375a95e04ccc93e7aaed4d34 Mon Sep 17 00:00:00 2001 From: Thierry Bultel Date: Tue, 17 Jun 2025 17:28:10 +0100 Subject: [PATCH 00157/11391] arm64: dts: renesas: Add initial support for the Renesas RZ/T2H eval board Add the initial device tree for the RZ/T2H evaluation board. Signed-off-by: Thierry Bultel Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250617162810.154332-3-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- arch/arm64/boot/dts/renesas/Makefile | 2 ++ .../dts/renesas/r9a09g077m44-rzt2h-evk.dts | 31 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 arch/arm64/boot/dts/renesas/r9a09g077m44-rzt2h-evk.dts diff --git a/arch/arm64/boot/dts/renesas/Makefile b/arch/arm64/boot/dts/renesas/Makefile index 6093d5f6e548..89acad605c2d 100644 --- a/arch/arm64/boot/dts/renesas/Makefile +++ b/arch/arm64/boot/dts/renesas/Makefile @@ -180,5 +180,7 @@ r9a09g057h44-rzv2h-evk-cn15-sd-dtbs := r9a09g057h44-rzv2h-evk.dtb rzv2-evk-cn15- dtb-$(CONFIG_ARCH_R9A09G057) += r9a09g057h44-rzv2h-evk-cn15-sd.dtb dtb-$(CONFIG_ARCH_R9A09G057) += r9a09g057h48-kakip.dtb +dtb-$(CONFIG_ARCH_R9A09G077) += r9a09g077m44-rzt2h-evk.dtb + dtb-$(CONFIG_ARCH_RCAR_GEN3) += draak-ebisu-panel-aa104xd12.dtbo dtb-$(CONFIG_ARCH_RCAR_GEN3) += salvator-panel-aa104xd12.dtbo diff --git a/arch/arm64/boot/dts/renesas/r9a09g077m44-rzt2h-evk.dts b/arch/arm64/boot/dts/renesas/r9a09g077m44-rzt2h-evk.dts new file mode 100644 index 000000000000..752d4c9f2cae --- /dev/null +++ b/arch/arm64/boot/dts/renesas/r9a09g077m44-rzt2h-evk.dts @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* + * Device Tree Source for the RZ/T2H EVK board + * + * Copyright (C) 2025 Renesas Electronics Corp. + */ + +/dts-v1/; + +#include "r9a09g077m44.dtsi" + +/ { + model = "Renesas RZ/T2H EVK Board based on r9a09g077m44"; + compatible = "renesas,rzt2h-evk", "renesas,r9a09g077m44", "renesas,r9a09g077"; + + aliases { + serial0 = &sci0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; +}; + +&extal_clk { + clock-frequency = <25000000>; +}; + +&sci0 { + status = "okay"; +}; From 4b3d31f0b81fefae5874467081496467af0f05a7 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Tue, 17 Jun 2025 18:19:54 +0100 Subject: [PATCH 00158/11391] arm64: dts: renesas: Add initial SoC DTSI for the RZ/N2H SoC Add the initial SoC DTSI for the Renesas RZ/N2H ("R9A09G087") SoC, below is the list of blocks added: - EXT CLKs - 4x CA55 - SCIF - CPG - GIC - ARMv8 Timer Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250617171957.162145-2-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- arch/arm64/boot/dts/renesas/r9a09g087.dtsi | 124 +++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 arch/arm64/boot/dts/renesas/r9a09g087.dtsi diff --git a/arch/arm64/boot/dts/renesas/r9a09g087.dtsi b/arch/arm64/boot/dts/renesas/r9a09g087.dtsi new file mode 100644 index 000000000000..e57a91adcb68 --- /dev/null +++ b/arch/arm64/boot/dts/renesas/r9a09g087.dtsi @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* + * Device Tree Source for the RZ/N2H SoC + * + * Copyright (C) 2025 Renesas Electronics Corp. + */ + +#include +#include + +/ { + compatible = "renesas,r9a09g087"; + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "arm,cortex-a55"; + reg = <0>; + device_type = "cpu"; + next-level-cache = <&L3_CA55>; + enable-method = "psci"; + }; + + cpu1: cpu@100 { + compatible = "arm,cortex-a55"; + reg = <0x100>; + device_type = "cpu"; + next-level-cache = <&L3_CA55>; + enable-method = "psci"; + }; + + cpu2: cpu@200 { + compatible = "arm,cortex-a55"; + reg = <0x200>; + device_type = "cpu"; + next-level-cache = <&L3_CA55>; + enable-method = "psci"; + }; + + cpu3: cpu@300 { + compatible = "arm,cortex-a55"; + reg = <0x300>; + device_type = "cpu"; + next-level-cache = <&L3_CA55>; + enable-method = "psci"; + }; + + L3_CA55: cache-controller-0 { + compatible = "cache"; + cache-unified; + cache-size = <0x100000>; + cache-level = <3>; + }; + }; + + extal_clk: extal { + compatible = "fixed-clock"; + #clock-cells = <0>; + /* This value must be overridden by the board */ + clock-frequency = <0>; + }; + + psci { + compatible = "arm,psci-1.0", "arm,psci-0.2"; + method = "smc"; + }; + + soc: soc { + compatible = "simple-bus"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + sci0: serial@80005000 { + compatible = "renesas,r9a09g087-rsci", "renesas,r9a09g077-rsci"; + reg = <0 0x80005000 0 0x400>; + interrupts = , + , + , + ; + interrupt-names = "eri", "rxi", "txi", "tei"; + clocks = <&cpg CPG_MOD 8>, <&cpg CPG_CORE R9A09G087_CLK_PCLKM>; + clock-names = "operation", "bus"; + power-domains = <&cpg>; + status = "disabled"; + }; + + cpg: clock-controller@80280000 { + compatible = "renesas,r9a09g087-cpg-mssr"; + reg = <0 0x80280000 0 0x1000>, + <0 0x81280000 0 0x9000>; + clocks = <&extal_clk>; + clock-names = "extal"; + #clock-cells = <2>; + #reset-cells = <1>; + #power-domain-cells = <0>; + }; + + gic: interrupt-controller@83000000 { + compatible = "arm,gic-v3"; + reg = <0x0 0x83000000 0 0x40000>, + <0x0 0x83040000 0 0x160000>; + #interrupt-cells = <3>; + #address-cells = <0>; + interrupt-controller; + interrupts = ; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts-extended = <&gic GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>, + <&gic GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>, + <&gic GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>, + <&gic GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>, + <&gic GIC_PPI 12 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "sec-phys", "phys", "virt", "hyp-phys", "hyp-virt"; + }; +}; From 8989230e80113e2bd2f322fba6922f9a3252e9c0 Mon Sep 17 00:00:00 2001 From: Paul Barker Date: Tue, 17 Jun 2025 18:19:55 +0100 Subject: [PATCH 00159/11391] arm64: dts: renesas: Refactor RZ/T2H EVK device tree The RZ/T2H EVK and RZ/N2H EVK are very similar boards. As there is so much overlap between these parts, common device tree entries are moved to the new file rzt2h-n2h-evk-common.dtsi. Signed-off-by: Paul Barker Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250617171957.162145-3-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- .../dts/renesas/r9a09g077m44-rzt2h-evk.dts | 17 +------------ .../dts/renesas/rzt2h-n2h-evk-common.dtsi | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 16 deletions(-) create mode 100644 arch/arm64/boot/dts/renesas/rzt2h-n2h-evk-common.dtsi diff --git a/arch/arm64/boot/dts/renesas/r9a09g077m44-rzt2h-evk.dts b/arch/arm64/boot/dts/renesas/r9a09g077m44-rzt2h-evk.dts index 752d4c9f2cae..486584fefead 100644 --- a/arch/arm64/boot/dts/renesas/r9a09g077m44-rzt2h-evk.dts +++ b/arch/arm64/boot/dts/renesas/r9a09g077m44-rzt2h-evk.dts @@ -8,24 +8,9 @@ /dts-v1/; #include "r9a09g077m44.dtsi" +#include "rzt2h-n2h-evk-common.dtsi" / { model = "Renesas RZ/T2H EVK Board based on r9a09g077m44"; compatible = "renesas,rzt2h-evk", "renesas,r9a09g077m44", "renesas,r9a09g077"; - - aliases { - serial0 = &sci0; - }; - - chosen { - stdout-path = "serial0:115200n8"; - }; -}; - -&extal_clk { - clock-frequency = <25000000>; -}; - -&sci0 { - status = "okay"; }; diff --git a/arch/arm64/boot/dts/renesas/rzt2h-n2h-evk-common.dtsi b/arch/arm64/boot/dts/renesas/rzt2h-n2h-evk-common.dtsi new file mode 100644 index 000000000000..5f17996bcd6b --- /dev/null +++ b/arch/arm64/boot/dts/renesas/rzt2h-n2h-evk-common.dtsi @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* + * Common Device Tree Source for the RZ/T2H and RZ/N2H EVK boards. + * + * Copyright (C) 2025 Renesas Electronics Corp. + */ + +/ { + aliases { + serial0 = &sci0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; +}; + +&extal_clk { + clock-frequency = <25000000>; +}; + +&sci0 { + status = "okay"; +}; From bddf6ae4f51755b31ad85906331f4bd4ded7632c Mon Sep 17 00:00:00 2001 From: Paul Barker Date: Tue, 17 Jun 2025 18:19:56 +0100 Subject: [PATCH 00160/11391] arm64: dts: renesas: Add DTSI for R9A09G087M44 variant of RZ/N2H Add the device tree source include file for the R9A09G087M44 variant of the Renesas RZ/N2H SoC, which features a 4-core configuration. Signed-off-by: Paul Barker Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250617171957.162145-4-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- arch/arm64/boot/dts/renesas/r9a09g087m44.dtsi | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 arch/arm64/boot/dts/renesas/r9a09g087m44.dtsi diff --git a/arch/arm64/boot/dts/renesas/r9a09g087m44.dtsi b/arch/arm64/boot/dts/renesas/r9a09g087m44.dtsi new file mode 100644 index 000000000000..ef0343b53309 --- /dev/null +++ b/arch/arm64/boot/dts/renesas/r9a09g087m44.dtsi @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* + * Device Tree Source for the RZ/N2H 4-core SoC + * + * Copyright (C) 2025 Renesas Electronics Corp. + */ + +/dts-v1/; +#include "r9a09g087.dtsi" + +/ { + compatible = "renesas,r9a09g087m44", "renesas,r9a09g087"; +}; From 8d0b6ca38f942292d9c1ae557150c58eaae63052 Mon Sep 17 00:00:00 2001 From: Paul Barker Date: Tue, 17 Jun 2025 18:19:57 +0100 Subject: [PATCH 00161/11391] arm64: dts: renesas: Add initial support for the RZ/N2H EVK Add an initial device tree file for the Renesas RZ/N2H Evaluation Board (EVK). Signed-off-by: Paul Barker Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250617171957.162145-5-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- arch/arm64/boot/dts/renesas/Makefile | 2 ++ .../boot/dts/renesas/r9a09g087m44-rzn2h-evk.dts | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 arch/arm64/boot/dts/renesas/r9a09g087m44-rzn2h-evk.dts diff --git a/arch/arm64/boot/dts/renesas/Makefile b/arch/arm64/boot/dts/renesas/Makefile index 89acad605c2d..d8c923762466 100644 --- a/arch/arm64/boot/dts/renesas/Makefile +++ b/arch/arm64/boot/dts/renesas/Makefile @@ -182,5 +182,7 @@ dtb-$(CONFIG_ARCH_R9A09G057) += r9a09g057h48-kakip.dtb dtb-$(CONFIG_ARCH_R9A09G077) += r9a09g077m44-rzt2h-evk.dtb +dtb-$(CONFIG_ARCH_R9A09G087) += r9a09g087m44-rzn2h-evk.dtb + dtb-$(CONFIG_ARCH_RCAR_GEN3) += draak-ebisu-panel-aa104xd12.dtbo dtb-$(CONFIG_ARCH_RCAR_GEN3) += salvator-panel-aa104xd12.dtbo diff --git a/arch/arm64/boot/dts/renesas/r9a09g087m44-rzn2h-evk.dts b/arch/arm64/boot/dts/renesas/r9a09g087m44-rzn2h-evk.dts new file mode 100644 index 000000000000..d6ba14a26f03 --- /dev/null +++ b/arch/arm64/boot/dts/renesas/r9a09g087m44-rzn2h-evk.dts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* + * Device Tree Source for the RZ/N2H EVK board + * + * Copyright (C) 2025 Renesas Electronics Corp. + */ + +/dts-v1/; + +#include "r9a09g087m44.dtsi" +#include "rzt2h-n2h-evk-common.dtsi" + +/ { + model = "Renesas RZ/N2H EVK Board based on r9a09g087m44"; + compatible = "renesas,rzn2h-evk", "renesas,r9a09g087m44", "renesas,r9a09g087"; +}; From c494de2e00fb06d5b62708a91d7dda701abc52f4 Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Tue, 24 Jun 2025 20:23:04 +0100 Subject: [PATCH 00162/11391] arm64: dts: renesas: r9a09g057: Add RSPI nodes Add nodes for the RSPI IPs found in the Renesas RZ/V2H(P) SoC. Signed-off-by: Fabrizio Castro Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250624192304.338979-7-fabrizio.castro.jz@renesas.com Signed-off-by: Geert Uytterhoeven --- arch/arm64/boot/dts/renesas/r9a09g057.dtsi | 63 ++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/arch/arm64/boot/dts/renesas/r9a09g057.dtsi b/arch/arm64/boot/dts/renesas/r9a09g057.dtsi index 044f2a22f161..6d0c6449b9ff 100644 --- a/arch/arm64/boot/dts/renesas/r9a09g057.dtsi +++ b/arch/arm64/boot/dts/renesas/r9a09g057.dtsi @@ -607,6 +607,69 @@ scif: serial@11c01400 { status = "disabled"; }; + rspi0: spi@12800000 { + compatible = "renesas,r9a09g057-rspi"; + reg = <0x0 0x12800000 0x0 0x400>; + interrupts = , + , + , + , + ; + interrupt-names = "idle", "error", "end", "rx", "tx"; + clocks = <&cpg CPG_MOD 0x54>, + <&cpg CPG_MOD 0x55>, + <&cpg CPG_MOD 0x56>; + clock-names = "pclk", "pclk_sfr", "tclk"; + resets = <&cpg 0x7b>, <&cpg 0x7c>; + reset-names = "presetn", "tresetn"; + power-domains = <&cpg>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + rspi1: spi@12800400 { + compatible = "renesas,r9a09g057-rspi"; + reg = <0x0 0x12800400 0x0 0x400>; + interrupts = , + , + , + , + ; + interrupt-names = "idle", "error", "end", "rx", "tx"; + clocks = <&cpg CPG_MOD 0x57>, + <&cpg CPG_MOD 0x58>, + <&cpg CPG_MOD 0x59>; + clock-names = "pclk", "pclk_sfr", "tclk"; + resets = <&cpg 0x7d>, <&cpg 0x7e>; + reset-names = "presetn", "tresetn"; + power-domains = <&cpg>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + rspi2: spi@12800800 { + compatible = "renesas,r9a09g057-rspi"; + reg = <0x0 0x12800800 0x0 0x400>; + interrupts = , + , + , + , + ; + interrupt-names = "idle", "error", "end", "rx", "tx"; + clocks = <&cpg CPG_MOD 0x5a>, + <&cpg CPG_MOD 0x5b>, + <&cpg CPG_MOD 0x5c>; + clock-names = "pclk", "pclk_sfr", "tclk"; + resets = <&cpg 0x7f>, <&cpg 0x80>; + reset-names = "presetn", "tresetn"; + power-domains = <&cpg>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + i2c0: i2c@14400400 { compatible = "renesas,riic-r9a09g057"; reg = <0 0x14400400 0 0x400>; From add7b05aeeb417c86239e6731a168e6c46b83279 Mon Sep 17 00:00:00 2001 From: Qiang Yu Date: Tue, 22 Jul 2025 17:11:49 +0800 Subject: [PATCH 00163/11391] 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 00164/11391] 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 00165/11391] 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 00166/11391] 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 243167e96939630b7d0d7f61be926d327e14a017 Mon Sep 17 00:00:00 2001 From: Nick Li Date: Mon, 11 Aug 2025 18:46:06 +0800 Subject: [PATCH 00167/11391] dt-bindings: vendor-prefixes: Add Shanghai FourSemi Semiconductor Co.,Ltd Add vendor prefix for Shanghai FourSemi Semiconductor Co.,Ltd Link: https://en.foursemi.com/ Signed-off-by: Nick Li Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/EA25BCF08F8BA128+20250811104610.8993-2-nick.li@foursemi.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 77160cd47f54..a92261b10c52 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -552,6 +552,8 @@ patternProperties: description: FocalTech Systems Co.,Ltd "^forlinx,.*": description: Baoding Forlinx Embedded Technology Co., Ltd. + "^foursemi,.*": + description: Shanghai FourSemi Semiconductor Co.,Ltd. "^freebox,.*": description: Freebox SAS "^freecom,.*": From fd90680da7e2d92e50ad72dfd4ea601098ab3493 Mon Sep 17 00:00:00 2001 From: Nick Li Date: Mon, 11 Aug 2025 18:46:07 +0800 Subject: [PATCH 00168/11391] ASoC: dt-bindings: Add FS2104/5S audio amplifiers Add a DT schema for describing FourSemi FS2104/5S audio amplifiers which support both I2S and I2C interface. Signed-off-by: Nick Li Reviewed-by: Rob Herring (Arm) Link: https://patch.msgid.link/350C011186D85903+20250811104610.8993-3-nick.li@foursemi.com Signed-off-by: Mark Brown --- .../bindings/sound/foursemi,fs2105s.yaml | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/foursemi,fs2105s.yaml diff --git a/Documentation/devicetree/bindings/sound/foursemi,fs2105s.yaml b/Documentation/devicetree/bindings/sound/foursemi,fs2105s.yaml new file mode 100644 index 000000000000..4da735317e0f --- /dev/null +++ b/Documentation/devicetree/bindings/sound/foursemi,fs2105s.yaml @@ -0,0 +1,101 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/foursemi,fs2105s.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: FourSemi FS2104/5S Digital Audio Amplifier + +maintainers: + - Nick Li + +description: + The FS2104 is a 15W Inductor-Less, Stereo, Closed-Loop, + Digital Input Class-D Power Amplifier with Enhanced Signal Processing. + The FS2105S is a 30W Inductor-Less, Stereo, Closed-Loop, + Digital Input Class-D Power Amplifier with Enhanced Signal Processing. + +properties: + compatible: + oneOf: + - items: + - enum: + - foursemi,fs2104 + - const: foursemi,fs2105s + - enum: + - foursemi,fs2105s + + reg: + maxItems: 1 + + clocks: + items: + - description: The clock of I2S BCLK + + clock-names: + items: + - const: bclk + + interrupts: + maxItems: 1 + + '#sound-dai-cells': + const: 0 + + pvdd-supply: + description: + Regulator for power supply(PVDD in datasheet). + + dvdd-supply: + description: + Regulator for digital supply(DVDD in datasheet). + + reset-gpios: + maxItems: 1 + description: + It's the SDZ pin in datasheet, the pin is active low, + it will power down and reset the chip to shut down state. + + firmware-name: + maxItems: 1 + description: | + The firmware(*.bin) contains: + a. Register initialization settings + b. DSP effect parameters + c. Multi-scene sound effect configurations(optional) + It's gernerated by FourSemi's tuning tool. + +required: + - compatible + - reg + - '#sound-dai-cells' + - pvdd-supply + - dvdd-supply + - reset-gpios + - firmware-name + +allOf: + - $ref: dai-common.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + audio-codec@68 { + compatible = "foursemi,fs2105s"; + reg = <0x68>; + clocks = <&clocks 18>; + clock-names = "bclk"; + #sound-dai-cells = <0>; + pvdd-supply = <&pvdd_supply>; + dvdd-supply = <&dvdd_supply>; + reset-gpios = <&gpio 18 GPIO_ACTIVE_LOW>; + firmware-name = "fs2105s-btl-2p0-0s.bin"; + pinctrl-names = "default"; + pinctrl-0 = <&fs210x_pins_default>; + }; + }; From e0bbbcaceba1cf47751f264d0dbe36206eab0ef0 Mon Sep 17 00:00:00 2001 From: Nick Li Date: Mon, 11 Aug 2025 18:46:08 +0800 Subject: [PATCH 00169/11391] ASoC: codecs: Add library for FourSemi audio amplifiers This patch adds firmware loading and parsing support for FourSemi audio amplifiers. The library handles firmware file (*.bin) generated by the FourSemi tuning tool, which contains: - Register initialization settings - DSP effect parameters - Multi-scene sound effect switching configurations(optional) The firmware is required for proper initialization and configuration of FourSemi amplifier devices. Signed-off-by: Nick Li Link: https://patch.msgid.link/77822D0108CCC1D0+20250811104610.8993-4-nick.li@foursemi.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 3 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/fs-amp-lib.c | 265 ++++++++++++++++++++++++++++++++++ sound/soc/codecs/fs-amp-lib.h | 150 +++++++++++++++++++ 4 files changed, 420 insertions(+) create mode 100644 sound/soc/codecs/fs-amp-lib.c create mode 100644 sound/soc/codecs/fs-amp-lib.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 6d7e4725d89c..ecdc05ef3e44 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1232,6 +1232,9 @@ config SND_SOC_FRAMER To compile this driver as a module, choose M here: the module will be called snd-soc-framer. +config SND_SOC_FS_AMP_LIB + select CRC16 + tristate config SND_SOC_GTM601 tristate 'GTM601 UMTS modem audio codec' diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index a68c3d192a1b..646e017a8754 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -137,6 +137,7 @@ snd-soc-es8328-spi-y := es8328-spi.o snd-soc-es8375-y := es8375.o snd-soc-es8389-y := es8389.o snd-soc-framer-y := framer-codec.o +snd-soc-fs-amp-lib-y := fs-amp-lib.o snd-soc-gtm601-y := gtm601.o snd-soc-hdac-hdmi-y := hdac_hdmi.o snd-soc-hdac-hda-y := hdac_hda.o @@ -562,6 +563,7 @@ obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o obj-$(CONFIG_SND_SOC_ES8375) += snd-soc-es8375.o obj-$(CONFIG_SND_SOC_ES8389) += snd-soc-es8389.o obj-$(CONFIG_SND_SOC_FRAMER) += snd-soc-framer.o +obj-$(CONFIG_SND_SOC_FS_AMP_LIB)+= snd-soc-fs-amp-lib.o obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o obj-$(CONFIG_SND_SOC_HDAC_HDA) += snd-soc-hdac-hda.o diff --git a/sound/soc/codecs/fs-amp-lib.c b/sound/soc/codecs/fs-amp-lib.c new file mode 100644 index 000000000000..75d8d5082e30 --- /dev/null +++ b/sound/soc/codecs/fs-amp-lib.c @@ -0,0 +1,265 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// fs-amp-lib.c --- Common library for FourSemi Audio Amplifiers +// +// Copyright (C) 2016-2025 Shanghai FourSemi Semiconductor Co.,Ltd. + +#include +#include +#include +#include +#include + +#include "fs-amp-lib.h" + +static int fs_get_scene_count(struct fs_amp_lib *amp_lib) +{ + const struct fs_fwm_table *table; + int count; + + if (!amp_lib || !amp_lib->dev) + return -EINVAL; + + table = amp_lib->table[FS_INDEX_SCENE]; + if (!table) + return -EFAULT; + + count = table->size / sizeof(struct fs_scene_index); + if (count < 1 || count > FS_SCENE_COUNT_MAX) { + dev_err(amp_lib->dev, "Invalid scene count: %d\n", count); + return -ERANGE; + } + + return count; +} + +static void fs_get_fwm_string(struct fs_amp_lib *amp_lib, + int offset, const char **pstr) +{ + const struct fs_fwm_table *table; + + if (!amp_lib || !amp_lib->dev || !pstr) + return; + + table = amp_lib->table[FS_INDEX_STRING]; + if (table && offset > 0 && offset < table->size + sizeof(*table)) + *pstr = (char *)table + offset; + else + *pstr = NULL; +} + +static void fs_get_scene_reg(struct fs_amp_lib *amp_lib, + int offset, struct fs_amp_scene *scene) +{ + const struct fs_fwm_table *table; + + if (!amp_lib || !amp_lib->dev || !scene) + return; + + table = amp_lib->table[FS_INDEX_REG]; + if (table && offset > 0 && offset < table->size + sizeof(*table)) + scene->reg = (struct fs_reg_table *)((char *)table + offset); + else + scene->reg = NULL; +} + +static void fs_get_scene_model(struct fs_amp_lib *amp_lib, + int offset, struct fs_amp_scene *scene) +{ + const struct fs_fwm_table *table; + const char *ptr; + + if (!amp_lib || !amp_lib->dev || !scene) + return; + + table = amp_lib->table[FS_INDEX_MODEL]; + ptr = (char *)table; + if (table && offset > 0 && offset < table->size + sizeof(*table)) + scene->model = (struct fs_file_table *)(ptr + offset); + else + scene->model = NULL; +} + +static void fs_get_scene_effect(struct fs_amp_lib *amp_lib, + int offset, struct fs_amp_scene *scene) +{ + const struct fs_fwm_table *table; + const char *ptr; + + if (!amp_lib || !amp_lib->dev || !scene) + return; + + table = amp_lib->table[FS_INDEX_EFFECT]; + ptr = (char *)table; + if (table && offset > 0 && offset < table->size + sizeof(*table)) + scene->effect = (struct fs_file_table *)(ptr + offset); + else + scene->effect = NULL; +} + +static int fs_parse_scene_tables(struct fs_amp_lib *amp_lib) +{ + const struct fs_scene_index *scene_index; + const struct fs_fwm_table *table; + struct fs_amp_scene *scene; + int idx, count; + + if (!amp_lib || !amp_lib->dev) + return -EINVAL; + + count = fs_get_scene_count(amp_lib); + if (count <= 0) + return -EFAULT; + + scene = devm_kzalloc(amp_lib->dev, count * sizeof(*scene), GFP_KERNEL); + if (!scene) + return -ENOMEM; + + amp_lib->scene_count = count; + amp_lib->scene = scene; + + table = amp_lib->table[FS_INDEX_SCENE]; + scene_index = (struct fs_scene_index *)table->buf; + + for (idx = 0; idx < count; idx++) { + fs_get_fwm_string(amp_lib, scene_index->name, &scene->name); + if (!scene->name) + scene->name = devm_kasprintf(amp_lib->dev, + GFP_KERNEL, "S%d", idx); + dev_dbg(amp_lib->dev, "scene.%d name: %s\n", idx, scene->name); + fs_get_scene_reg(amp_lib, scene_index->reg, scene); + fs_get_scene_model(amp_lib, scene_index->model, scene); + fs_get_scene_effect(amp_lib, scene_index->effect, scene); + scene++; + scene_index++; + } + + return 0; +} + +static int fs_parse_all_tables(struct fs_amp_lib *amp_lib) +{ + const struct fs_fwm_table *table; + const struct fs_fwm_index *index; + const char *ptr; + int idx, count; + int ret; + + if (!amp_lib || !amp_lib->dev || !amp_lib->hdr) + return -EINVAL; + + /* Parse all fwm tables */ + table = (struct fs_fwm_table *)amp_lib->hdr->params; + index = (struct fs_fwm_index *)table->buf; + count = table->size / sizeof(*index); + + for (idx = 0; idx < count; idx++, index++) { + if (index->type >= FS_INDEX_MAX) + return -ERANGE; + ptr = (char *)table + (int)index->offset; + amp_lib->table[index->type] = (struct fs_fwm_table *)ptr; + } + + /* Parse all scene tables */ + ret = fs_parse_scene_tables(amp_lib); + if (ret) + dev_err(amp_lib->dev, "Failed to parse scene: %d\n", ret); + + return ret; +} + +static int fs_verify_firmware(struct fs_amp_lib *amp_lib) +{ + const struct fs_fwm_header *hdr; + int crcsum; + + if (!amp_lib || !amp_lib->dev || !amp_lib->hdr) + return -EINVAL; + + hdr = amp_lib->hdr; + + /* Verify the crcsum code */ + crcsum = crc16(0x0000, (const char *)&hdr->crc_size, hdr->crc_size); + if (crcsum != hdr->crc16) { + dev_err(amp_lib->dev, "Failed to checksum: %x-%x\n", + crcsum, hdr->crc16); + return -EFAULT; + } + + /* Verify the devid(chip_type) */ + if (amp_lib->devid != LO_U16(hdr->chip_type)) { + dev_err(amp_lib->dev, "DEVID dismatch: %04X#%04X\n", + amp_lib->devid, hdr->chip_type); + return -EINVAL; + } + + return 0; +} + +static void fs_print_firmware_info(struct fs_amp_lib *amp_lib) +{ + const struct fs_fwm_header *hdr; + const char *pro_name = NULL; + const char *dev_name = NULL; + + if (!amp_lib || !amp_lib->dev || !amp_lib->hdr) + return; + + hdr = amp_lib->hdr; + + fs_get_fwm_string(amp_lib, hdr->project, &pro_name); + fs_get_fwm_string(amp_lib, hdr->device, &dev_name); + + dev_info(amp_lib->dev, "Project: %s Device: %s\n", + pro_name ? pro_name : "null", + dev_name ? dev_name : "null"); + + dev_info(amp_lib->dev, "Date: %04d%02d%02d-%02d%02d\n", + hdr->date.year, hdr->date.month, hdr->date.day, + hdr->date.hour, hdr->date.minute); +} + +int fs_amp_load_firmware(struct fs_amp_lib *amp_lib, const char *name) +{ + const struct firmware *cont; + struct fs_fwm_header *hdr; + int ret; + + if (!amp_lib || !amp_lib->dev || !name) + return -EINVAL; + + ret = request_firmware(&cont, name, amp_lib->dev); + if (ret) { + dev_err(amp_lib->dev, "Failed to request %s: %d\n", name, ret); + return ret; + } + + dev_info(amp_lib->dev, "Loading %s - size: %zu\n", name, cont->size); + + hdr = devm_kmemdup(amp_lib->dev, cont->data, cont->size, GFP_KERNEL); + release_firmware(cont); + if (!hdr) + return -ENOMEM; + + amp_lib->hdr = hdr; + ret = fs_verify_firmware(amp_lib); + if (ret) { + amp_lib->hdr = NULL; + return ret; + } + + ret = fs_parse_all_tables(amp_lib); + if (ret) { + amp_lib->hdr = NULL; + return ret; + } + + fs_print_firmware_info(amp_lib); + + return 0; +} +EXPORT_SYMBOL_GPL(fs_amp_load_firmware); + +MODULE_AUTHOR("Nick Li "); +MODULE_DESCRIPTION("FourSemi audio amplifier library"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/fs-amp-lib.h b/sound/soc/codecs/fs-amp-lib.h new file mode 100644 index 000000000000..4a77c7b383cd --- /dev/null +++ b/sound/soc/codecs/fs-amp-lib.h @@ -0,0 +1,150 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * fs-amp-lib.h --- Common library for FourSemi Audio Amplifiers + * + * Copyright (C) 2016-2025 Shanghai FourSemi Semiconductor Co.,Ltd. + */ + +#ifndef __FS_AMP_LIB_H__ +#define __FS_AMP_LIB_H__ + +#define HI_U16(a) (((a) >> 8) & 0xFF) +#define LO_U16(a) ((a) & 0xFF) +#define FS_TABLE_NAME_LEN (4) +#define FS_SCENE_COUNT_MAX (16) +#define FS_CMD_DELAY_MS_MAX (100) /* 100ms */ + +#define FS_CMD_DELAY (0xFF) +#define FS_CMD_BURST (0xFE) +#define FS_CMD_UPDATE (0xFD) + +#define FS_SOC_ENUM_EXT(xname, xhandler_info, xhandler_get, xhandler_put) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = xhandler_info, \ + .get = xhandler_get, .put = xhandler_put \ +} + +enum fs_index_type { + FS_INDEX_INFO = 0, + FS_INDEX_STCOEF, + FS_INDEX_SCENE, + FS_INDEX_MODEL, + FS_INDEX_REG, + FS_INDEX_EFFECT, + FS_INDEX_STRING, + FS_INDEX_WOOFER, + FS_INDEX_MAX, +}; + +#pragma pack(push, 1) + +struct fs_reg_val { + u8 reg; + u16 val; +}; + +struct fs_reg_bits { + u8 cmd; /* FS_CMD_UPDATE */ + u8 reg; + u16 val; + u16 mask; +}; + +struct fs_cmd_pkg { + union { + u8 cmd; + struct fs_reg_val regv; + struct fs_reg_bits regb; + }; +}; + +struct fs_fwm_index { + /* Index type */ + u16 type; + /* Offset address starting from the end of header */ + u16 offset; +}; + +struct fs_fwm_table { + char name[FS_TABLE_NAME_LEN]; + u16 size; /* size of buf */ + u8 buf[]; +}; + +struct fs_scene_index { + /* Offset address(scene name) in string table */ + u16 name; + /* Offset address(scene reg) in register table */ + u16 reg; + /* Offset address(scene model) in model table */ + u16 model; + /* Offset address(scene effect) in effect table */ + u16 effect; +}; + +struct fs_reg_table { + u16 size; /* size of buf */ + u8 buf[]; +}; + +struct fs_file_table { + u16 name; + u16 size; /* size of buf */ + u8 buf[]; +}; + +struct fs_fwm_date { + u32 year:12; + u32 month:4; + u32 day:5; + u32 hour:5; + u32 minute:6; +}; + +struct fs_fwm_header { + u16 version; + u16 project; /* Offset address(project name) in string table */ + u16 device; /* Offset address(device name) in string table */ + struct fs_fwm_date date; + u16 crc16; + u16 crc_size; /* Starting position for CRC checking */ + u16 chip_type; + u16 addr; /* 7-bit i2c address */ + u16 spkid; + u16 rsvd[6]; + u8 params[]; +}; + +#pragma pack(pop) + +struct fs_i2s_srate { + u32 srate; /* Sample rate */ + u16 i2ssr; /* Value of Bit field[I2SSR] */ +}; + +struct fs_pll_div { + unsigned int bclk; /* Rate of bit clock */ + u16 pll1; + u16 pll2; + u16 pll3; +}; + +struct fs_amp_scene { + const char *name; + const struct fs_reg_table *reg; + const struct fs_file_table *model; + const struct fs_file_table *effect; +}; + +struct fs_amp_lib { + const struct fs_fwm_header *hdr; + const struct fs_fwm_table *table[FS_INDEX_MAX]; + struct fs_amp_scene *scene; + struct device *dev; + int scene_count; + u16 devid; +}; + +int fs_amp_load_firmware(struct fs_amp_lib *amp_lib, const char *name); + +#endif // __FS_AMP_LIB_H__ From 75611770177965ae902c87c96eace07542beff07 Mon Sep 17 00:00:00 2001 From: Nick Li Date: Mon, 11 Aug 2025 18:46:09 +0800 Subject: [PATCH 00170/11391] ASoC: codecs: Add FourSemi FS2104/5S audio amplifier driver The FS2104/5S are FourSemi digital audio amplifiers with I2C control. They are Inductor-Less, Stereo, Closed-Loop, Digital Input Class-D Power Amplifiers with Enhanced Signal Processing. Signed-off-by: Nick Li Link: https://patch.msgid.link/75A0F7CC495E9662+20250811104610.8993-5-nick.li@foursemi.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 13 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/fs210x.c | 1583 +++++++++++++++++++++++++++++++++++++ sound/soc/codecs/fs210x.h | 75 ++ 4 files changed, 1673 insertions(+) create mode 100644 sound/soc/codecs/fs210x.c create mode 100644 sound/soc/codecs/fs210x.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index ecdc05ef3e44..787cc23e8511 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -125,6 +125,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_ES7134 imply SND_SOC_ES7241 imply SND_SOC_FRAMER + imply SND_SOC_FS210X imply SND_SOC_GTM601 imply SND_SOC_HDAC_HDMI imply SND_SOC_HDAC_HDA @@ -1236,6 +1237,18 @@ config SND_SOC_FS_AMP_LIB select CRC16 tristate +config SND_SOC_FS210X + tristate 'FourSemi FS2104/5S digital audio amplifier' + depends on I2C + select GPIOLIB + select REGMAP_I2C + select SND_SOC_FS_AMP_LIB + help + Enable support for FourSemi FS2104/5S digital audio amplifier. + The FS2104/5S are Inductor-Less, Stereo, Closed-Loop, + Digital Input Class-D Power Amplifiers with Enhanced Signal Processing. + The amplifiers support I2C and I2S/TDM. + config SND_SOC_GTM601 tristate 'GTM601 UMTS modem audio codec' diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 646e017a8754..3f97afaaaed8 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -138,6 +138,7 @@ snd-soc-es8375-y := es8375.o snd-soc-es8389-y := es8389.o snd-soc-framer-y := framer-codec.o snd-soc-fs-amp-lib-y := fs-amp-lib.o +snd-soc-fs210x-y := fs210x.o snd-soc-gtm601-y := gtm601.o snd-soc-hdac-hdmi-y := hdac_hdmi.o snd-soc-hdac-hda-y := hdac_hda.o @@ -564,6 +565,7 @@ obj-$(CONFIG_SND_SOC_ES8375) += snd-soc-es8375.o obj-$(CONFIG_SND_SOC_ES8389) += snd-soc-es8389.o obj-$(CONFIG_SND_SOC_FRAMER) += snd-soc-framer.o obj-$(CONFIG_SND_SOC_FS_AMP_LIB)+= snd-soc-fs-amp-lib.o +obj-$(CONFIG_SND_SOC_FS210X) += snd-soc-fs210x.o obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o obj-$(CONFIG_SND_SOC_HDAC_HDA) += snd-soc-hdac-hda.o diff --git a/sound/soc/codecs/fs210x.c b/sound/soc/codecs/fs210x.c new file mode 100644 index 000000000000..b4f51ee7235a --- /dev/null +++ b/sound/soc/codecs/fs210x.c @@ -0,0 +1,1583 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// fs210x.c -- Driver for the FS2104/5S Audio Amplifier +// +// Copyright (C) 2016-2025 Shanghai FourSemi Semiconductor Co.,Ltd. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fs210x.h" +#include "fs-amp-lib.h" + +#define FS210X_DEFAULT_FWM_NAME "fs210x_fwm.bin" +#define FS210X_DEFAULT_DAI_NAME "fs210x-aif" +#define FS2105S_DEVICE_ID 0x20 /* FS2105S */ +#define FS210X_DEVICE_ID 0x45 /* FS2104 */ +#define FS210X_REG_MAX 0xF8 +#define FS210X_INIT_SCENE 0 +#define FS210X_DEFAULT_SCENE 1 +#define FS210X_START_DELAY_MS 5 +#define FS210X_FAULT_CHECK_INTERVAL_MS 2000 +#define FS2105S_RATES (SNDRV_PCM_RATE_32000 | \ + SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_88200 | \ + SNDRV_PCM_RATE_96000) +#define FS210X_RATES (SNDRV_PCM_RATE_16000 | FS2105S_RATES) +#define FS210X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S24_3LE | \ + SNDRV_PCM_FMTBIT_S32_LE) +#define FS210X_NUM_SUPPLIES ARRAY_SIZE(fs210x_supply_names) + +static const char *const fs210x_supply_names[] = { + "pvdd", + "dvdd", +}; + +struct fs210x_platform_data { + const char *fwm_name; +}; + +struct fs210x_priv { + struct i2c_client *i2c; + struct device *dev; + struct regmap *regmap; + struct fs210x_platform_data pdata; + struct regulator_bulk_data supplies[FS210X_NUM_SUPPLIES]; + struct gpio_desc *gpio_sdz; + struct delayed_work start_work; + struct delayed_work fault_check_work; + struct fs_amp_lib amp_lib; + const struct fs_amp_scene *cur_scene; + struct clk *clk_bclk; + /* + * @lock: Mutex ensuring exclusive access for critical device operations + * + * This lock serializes access between the following actions: + * - Device initialization procedures(probe) + * - Enable/disable device(DAPM event) + * - Suspend/resume device(PM) + * - Runtime scene switching(control) + * - Scheduling/execution of delayed works items(delayed works) + */ + struct mutex lock; + unsigned int check_interval_ms; + unsigned int bclk; + unsigned int srate; + int scene_id; + u16 devid; + bool is_inited; + bool is_suspended; + bool is_bclk_on; + bool is_playing; +}; + +static const unsigned int fs2105s_rates[] = { + 32000, 44100, 48000, 88200, 96000 +}; + +static const struct snd_pcm_hw_constraint_list fs2105s_constraints = { + .count = ARRAY_SIZE(fs2105s_rates), + .list = fs2105s_rates, +}; + +static const unsigned int fs210x_rates[] = { + 16000, 32000, 44100, 48000, 88200, 96000 +}; + +static const struct snd_pcm_hw_constraint_list fs210x_constraints = { + .count = ARRAY_SIZE(fs210x_rates), + .list = fs210x_rates, +}; + +static const struct fs_pll_div fs210x_pll_div[] = { + /* bclk, pll1, pll2, pll3 */ + { 512000, 0x006C, 0x0120, 0x0001 }, + { 768000, 0x016C, 0x00C0, 0x0001 }, + { 1024000, 0x016C, 0x0090, 0x0001 }, + { 1536000, 0x016C, 0x0060, 0x0001 }, + { 2048000, 0x016C, 0x0090, 0x0002 }, + { 2304000, 0x016C, 0x0080, 0x0002 }, + { 3072000, 0x016C, 0x0090, 0x0003 }, + { 4096000, 0x016C, 0x0090, 0x0004 }, + { 4608000, 0x016C, 0x0080, 0x0004 }, + { 6144000, 0x016C, 0x0090, 0x0006 }, + { 8192000, 0x016C, 0x0090, 0x0008 }, + { 9216000, 0x016C, 0x0090, 0x0009 }, + { 12288000, 0x016C, 0x0090, 0x000C }, + { 16384000, 0x016C, 0x0090, 0x0010 }, + { 18432000, 0x016C, 0x0090, 0x0012 }, + { 24576000, 0x016C, 0x0090, 0x0018 }, + { 1411200, 0x016C, 0x0060, 0x0001 }, + { 2116800, 0x016C, 0x0080, 0x0002 }, + { 2822400, 0x016C, 0x0090, 0x0003 }, + { 4233600, 0x016C, 0x0080, 0x0004 }, + { 5644800, 0x016C, 0x0090, 0x0006 }, + { 8467200, 0x016C, 0x0090, 0x0009 }, + { 11289600, 0x016C, 0x0090, 0x000C }, + { 16934400, 0x016C, 0x0090, 0x0012 }, + { 22579200, 0x016C, 0x0090, 0x0018 }, + { 2000000, 0x017C, 0x0093, 0x0002 }, +}; + +static int fs210x_bclk_set(struct fs210x_priv *fs210x, bool on) +{ + int ret = 0; + + if (!fs210x || !fs210x->dev) + return -EINVAL; + + if ((fs210x->is_bclk_on ^ on) == 0) + return 0; + + if (on) { + clk_set_rate(fs210x->clk_bclk, fs210x->bclk); + ret = clk_prepare_enable(fs210x->clk_bclk); + fs210x->is_bclk_on = true; + fsleep(2000); /* >= 2ms */ + } else { + clk_disable_unprepare(fs210x->clk_bclk); + fs210x->is_bclk_on = false; + } + + return ret; +} + +static int fs210x_reg_write(struct fs210x_priv *fs210x, + u8 reg, u16 val) +{ + int ret; + + ret = regmap_write(fs210x->regmap, reg, val); + if (ret) { + dev_err(fs210x->dev, "Failed to write %02Xh: %d\n", reg, ret); + return ret; + } + + return 0; +} + +static int fs210x_reg_read(struct fs210x_priv *fs210x, + u8 reg, u16 *pval) +{ + unsigned int val; + int ret; + + ret = regmap_read(fs210x->regmap, reg, &val); + if (ret) { + dev_err(fs210x->dev, "Failed to read %02Xh: %d\n", reg, ret); + return ret; + } + + *pval = (u16)val; + + return 0; +} + +static int fs210x_reg_update_bits(struct fs210x_priv *fs210x, + u8 reg, u16 mask, u16 val) +{ + int ret; + + ret = regmap_update_bits(fs210x->regmap, reg, mask, val); + if (ret) { + dev_err(fs210x->dev, "Failed to update %02Xh: %d\n", reg, ret); + return ret; + } + + return 0; +} + +static int fs210x_reg_bulk_write(struct fs210x_priv *fs210x, + u8 reg, const void *val, u32 size) +{ + int ret; + + ret = regmap_bulk_write(fs210x->regmap, reg, val, size / 2); + if (ret) { + dev_err(fs210x->dev, "Failed to bulk write %02Xh: %d\n", + reg, ret); + return ret; + } + + return 0; +} + +static inline int fs210x_write_reg_val(struct fs210x_priv *fs210x, + const struct fs_reg_val *regv) +{ + return fs210x_reg_write(fs210x, regv->reg, regv->val); +} + +static inline int fs210x_write_reg_bits(struct fs210x_priv *fs210x, + const struct fs_reg_bits *regu) +{ + return fs210x_reg_update_bits(fs210x, + regu->reg, + regu->mask, + regu->val); +} + +static inline int fs210x_set_cmd_pkg(struct fs210x_priv *fs210x, + const struct fs_cmd_pkg *pkg, + unsigned int *offset) +{ + int delay_us; + + if (pkg->cmd >= 0x00 && pkg->cmd <= FS210X_REG_MAX) { + *offset = sizeof(pkg->regv); + return fs210x_write_reg_val(fs210x, &pkg->regv); + } else if (pkg->cmd == FS_CMD_UPDATE) { + *offset = sizeof(pkg->regb); + return fs210x_write_reg_bits(fs210x, &pkg->regb); + } else if (pkg->cmd == FS_CMD_DELAY) { + if (pkg->regv.val > FS_CMD_DELAY_MS_MAX) + return -EOPNOTSUPP; + delay_us = pkg->regv.val * 1000; /* ms -> us */ + fsleep(delay_us); + *offset = sizeof(pkg->regv); + return 0; + } + + dev_err(fs210x->dev, "Invalid pkg cmd: %d\n", pkg->cmd); + + return -EOPNOTSUPP; +} + +static int fs210x_reg_write_table(struct fs210x_priv *fs210x, + const struct fs_reg_table *reg) +{ + const struct fs_cmd_pkg *pkg; + unsigned int index, offset; + int ret; + + if (!fs210x || !fs210x->dev) + return -EINVAL; + + if (!reg || reg->size == 0) + return -EFAULT; + + for (index = 0; index < reg->size; index += offset) { + pkg = (struct fs_cmd_pkg *)(reg->buf + index); + ret = fs210x_set_cmd_pkg(fs210x, pkg, &offset); + if (ret) { + dev_err(fs210x->dev, "Failed to set cmd pkg: %02X-%d\n", + pkg->cmd, ret); + return ret; + } + } + + if (index != reg->size) { + dev_err(fs210x->dev, "Invalid reg table size: %d-%d\n", + index, reg->size); + return -EFAULT; + } + + return 0; +} + +static int fs210x_dev_play(struct fs210x_priv *fs210x) +{ + int ret; + + if (!fs210x->is_inited) + return -EFAULT; + + if (fs210x->is_playing) + return 0; + + ret = fs210x_reg_write(fs210x, FS210X_11H_SYSCTRL, + FS210X_11H_DPS_PLAY); + if (!ret) + fs210x->is_playing = true; + + fsleep(10000); /* >= 10ms */ + + return ret; +} + +static int fs210x_dev_stop(struct fs210x_priv *fs210x) +{ + int ret; + + if (!fs210x->is_inited) + return -EFAULT; + + if (!fs210x->is_playing) + return 0; + + ret = fs210x_reg_write(fs210x, FS210X_11H_SYSCTRL, + FS210X_11H_DPS_PWDN); + fs210x->is_playing = false; + + fsleep(30000); /* >= 30ms */ + + return ret; +} + +static int fs210x_set_reg_table(struct fs210x_priv *fs210x, + const struct fs_amp_scene *scene) +{ + const struct fs_amp_scene *cur_scene; + const struct fs_reg_table *reg; + + if (!fs210x || !fs210x->dev || !scene) + return -EINVAL; + + cur_scene = fs210x->cur_scene; + if (!scene->reg || cur_scene == scene) { + dev_dbg(fs210x->dev, "Skip writing reg table\n"); + return 0; + } + + reg = scene->reg; + dev_dbg(fs210x->dev, "reg table size: %d\n", reg->size); + + return fs210x_reg_write_table(fs210x, reg); +} + +static int fs210x_set_woofer_table(struct fs210x_priv *fs210x) +{ + const struct fs_file_table *woofer; + const struct fs_fwm_table *table; + int ret; + + if (!fs210x || !fs210x->dev) + return -EINVAL; + + /* NOTE: fs2105s has woofer ram only */ + if (fs210x->devid != FS2105S_DEVICE_ID) + return 0; + + table = fs210x->amp_lib.table[FS_INDEX_WOOFER]; + if (!table) { + dev_dbg(fs210x->dev, "Skip writing woofer table\n"); + return 0; + } + + woofer = (struct fs_file_table *)table->buf; + dev_dbg(fs210x->dev, "woofer table size: %d\n", woofer->size); + /* Unit of woofer data is u32(4 bytes) */ + if (woofer->size == 0 || (woofer->size & 0x3)) { + dev_err(fs210x->dev, "Invalid woofer size: %d\n", + woofer->size); + return -EINVAL; + } + + ret = fs210x_reg_write(fs210x, FS210X_46H_DACEQA, + FS2105S_46H_CAM_BURST_W); + ret |= fs210x_reg_bulk_write(fs210x, FS210X_42H_DACEQWL, + woofer->buf, woofer->size); + + return ret; +} + +static int fs210x_set_effect_table(struct fs210x_priv *fs210x, + const struct fs_amp_scene *scene) +{ + const struct fs_amp_scene *cur_scene; + const struct fs_file_table *effect; + int half_size; + int ret; + + if (!fs210x || !fs210x->dev || !scene) + return -EINVAL; + + cur_scene = fs210x->cur_scene; + if (!scene->effect || cur_scene == scene) { + dev_dbg(fs210x->dev, "Skip writing effect table\n"); + return 0; + } + + effect = scene->effect; + dev_dbg(fs210x->dev, "effect table size: %d\n", effect->size); + + /* Unit of effect data is u32(4 bytes), 2 channels */ + if (effect->size == 0 || (effect->size & 0x7)) { + dev_err(fs210x->dev, "Invalid effect size: %d\n", + effect->size); + return -EINVAL; + } + + half_size = effect->size / 2; + + /* Left channel */ + ret = fs210x_reg_write(fs210x, FS210X_46H_DACEQA, + FS210X_46H_CAM_BURST_L); + ret |= fs210x_reg_bulk_write(fs210x, FS210X_42H_DACEQWL, + effect->buf, half_size); + if (ret) + return ret; + + /* Right channel */ + ret = fs210x_reg_write(fs210x, FS210X_46H_DACEQA, + FS210X_46H_CAM_BURST_R); + ret |= fs210x_reg_bulk_write(fs210x, FS210X_42H_DACEQWL, + effect->buf + half_size, half_size); + + return ret; +} + +static int fs210x_access_dsp_ram(struct fs210x_priv *fs210x, bool enable) +{ + int ret; + + if (!fs210x || !fs210x->dev) + return -EINVAL; + + if (enable) { + ret = fs210x_reg_write(fs210x, FS210X_11H_SYSCTRL, + FS210X_11H_DPS_HIZ); + ret |= fs210x_reg_write(fs210x, FS210X_0BH_ACCKEY, + FS210X_0BH_ACCKEY_ON); + } else { + ret = fs210x_reg_write(fs210x, FS210X_0BH_ACCKEY, + FS210X_0BH_ACCKEY_OFF); + ret |= fs210x_reg_write(fs210x, FS210X_11H_SYSCTRL, + FS210X_11H_DPS_PWDN); + } + + fsleep(10000); /* >= 10ms */ + + return ret; +} + +static int fs210x_write_dsp_effect(struct fs210x_priv *fs210x, + const struct fs_amp_scene *scene, + int scene_id) +{ + int ret; + + if (!fs210x || !scene) + return -EINVAL; + + ret = fs210x_access_dsp_ram(fs210x, true); + if (ret) { + dev_err(fs210x->dev, "Failed to access dsp: %d\n", ret); + goto tag_exit; + } + + ret = fs210x_set_effect_table(fs210x, scene); + if (ret) { + dev_err(fs210x->dev, "Failed to set effect: %d\n", ret); + goto tag_exit; + } + + if (scene_id == FS210X_INIT_SCENE) + ret = fs210x_set_woofer_table(fs210x); + +tag_exit: + fs210x_reg_write(fs210x, FS210X_46H_DACEQA, + FS210X_46H_CAM_CLEAR); + fs210x_access_dsp_ram(fs210x, false); + + return ret; +} + +static int fs210x_check_scene(struct fs210x_priv *fs210x, + int scene_id, bool *skip_set) +{ + struct fs_amp_lib *amp_lib; + + if (!fs210x || !skip_set) + return -EINVAL; + + amp_lib = &fs210x->amp_lib; + if (amp_lib->scene_count == 0 || !amp_lib->scene) { + dev_err(fs210x->dev, "There's no scene data\n"); + return -EINVAL; + } + + if (scene_id < 0 || scene_id >= amp_lib->scene_count) { + dev_err(fs210x->dev, "Invalid scene_id: %d\n", scene_id); + return -EINVAL; + } + + if (fs210x->scene_id == scene_id) { + dev_dbg(fs210x->dev, "Skip to set same scene\n"); + return 0; + } + + *skip_set = false; + + return 0; +} + +static int fs210x_set_scene(struct fs210x_priv *fs210x, int scene_id) +{ + const struct fs_amp_scene *scene; + bool skip_set = true; + bool is_playing; + int ret; + + if (!fs210x || !fs210x->dev) + return -EINVAL; + + ret = fs210x_check_scene(fs210x, scene_id, &skip_set); + if (ret || skip_set) + return ret; + + scene = fs210x->amp_lib.scene + scene_id; + dev_info(fs210x->dev, "Switch scene.%d: %s\n", + scene_id, scene->name); + + is_playing = fs210x->is_playing; + if (is_playing) + fs210x_dev_stop(fs210x); + + ret = fs210x_set_reg_table(fs210x, scene); + if (ret) { + dev_err(fs210x->dev, "Failed to set reg: %d\n", ret); + return ret; + } + + ret = fs210x_write_dsp_effect(fs210x, scene, scene_id); + if (ret) { + dev_err(fs210x->dev, "Failed to write ram: %d\n", ret); + return ret; + } + + fs210x->cur_scene = scene; + fs210x->scene_id = scene_id; + + if (is_playing) + fs210x_dev_play(fs210x); + + return 0; +} + +static int fs210x_init_chip(struct fs210x_priv *fs210x) +{ + int scene_id; + int ret; + + regcache_cache_bypass(fs210x->regmap, true); + + if (!fs210x->gpio_sdz) { + /* Gpio is not found, i2c reset */ + ret = fs210x_reg_write(fs210x, FS210X_10H_PWRCTRL, + FS210X_10H_I2C_RESET); + if (ret) + goto tag_power_down; + } else { + /* gpio reset, deactivate */ + gpiod_set_value_cansleep(fs210x->gpio_sdz, 0); + } + + fsleep(10000); /* >= 10ms */ + + /* Backup scene id */ + scene_id = fs210x->scene_id; + fs210x->scene_id = -1; + + /* Init registers/RAM by init scene */ + ret = fs210x_set_scene(fs210x, FS210X_INIT_SCENE); + if (ret) + goto tag_power_down; + + /* + * If the firmware has effect scene(s), + * we load effect scene by default scene or scene_id + */ + if (fs210x->amp_lib.scene_count > 1) { + if (scene_id < FS210X_DEFAULT_SCENE) + scene_id = FS210X_DEFAULT_SCENE; + ret = fs210x_set_scene(fs210x, scene_id); + if (ret) + goto tag_power_down; + } + +tag_power_down: + /* Power down the device */ + ret |= fs210x_reg_write(fs210x, FS210X_11H_SYSCTRL, + FS210X_11H_DPS_PWDN); + fsleep(10000); /* >= 10ms */ + + regcache_cache_bypass(fs210x->regmap, false); + if (!ret) { + regcache_mark_dirty(fs210x->regmap); + regcache_sync(fs210x->regmap); + fs210x->is_inited = true; + } + + return ret; +} + +static int fs210x_set_i2s_params(struct fs210x_priv *fs210x) +{ + const struct fs_i2s_srate params[] = { + { 16000, 0x3 }, + { 32000, 0x7 }, + { 44100, 0x8 }, + { 48000, 0x9 }, + { 88200, 0xA }, + { 96000, 0xB }, + }; + u16 val; + int i, ret; + + for (i = 0; i < ARRAY_SIZE(params); i++) { + if (params[i].srate != fs210x->srate) + continue; + val = params[i].i2ssr << FS210X_17H_I2SSR_SHIFT; + ret = fs210x_reg_update_bits(fs210x, + FS210X_17H_I2SCTRL, + FS210X_17H_I2SSR_MASK, + val); + return ret; + } + + dev_err(fs210x->dev, "Invalid sample rate: %d\n", fs210x->srate); + + return -EINVAL; +} + +static int fs210x_get_pll_div(struct fs210x_priv *fs210x, + const struct fs_pll_div **pll_div) +{ + int i; + + if (!fs210x || !pll_div) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(fs210x_pll_div); i++) { + if (fs210x_pll_div[i].bclk != fs210x->bclk) + continue; + *pll_div = fs210x_pll_div + i; + return 0; + } + + dev_err(fs210x->dev, "No PLL table for bclk: %d\n", fs210x->bclk); + + return -EFAULT; +} + +static int fs210x_set_hw_params(struct fs210x_priv *fs210x) +{ + const struct fs_pll_div *pll_div; + int ret; + + ret = fs210x_set_i2s_params(fs210x); + if (ret) { + dev_err(fs210x->dev, "Failed to set i2s params: %d\n", ret); + return ret; + } + + /* Set pll params */ + ret = fs210x_get_pll_div(fs210x, &pll_div); + if (ret) + return ret; + + ret = fs210x_reg_write(fs210x, FS210X_A1H_PLLCTRL1, pll_div->pll1); + ret |= fs210x_reg_write(fs210x, FS210X_A2H_PLLCTRL2, pll_div->pll2); + ret |= fs210x_reg_write(fs210x, FS210X_A3H_PLLCTRL3, pll_div->pll3); + + return ret; +} + +static int fs210x_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + const struct snd_pcm_hw_constraint_list *list; + struct fs210x_priv *fs210x; + int ret; + + fs210x = snd_soc_component_get_drvdata(dai->component); + if (!fs210x) { + pr_err("dai_startup: fs210x is null\n"); + return -EINVAL; + } + + if (!substream->runtime) + return 0; + + ret = snd_pcm_hw_constraint_mask64(substream->runtime, + SNDRV_PCM_HW_PARAM_FORMAT, + FS210X_FORMATS); + if (ret < 0) { + dev_err(fs210x->dev, + "Failed to set hw param format: %d\n", ret); + return ret; + } + + if (fs210x->devid == FS2105S_DEVICE_ID) + list = &fs2105s_constraints; + else + list = &fs210x_constraints; + + ret = snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + list); + if (ret < 0) { + dev_err(fs210x->dev, + "Failed to set hw param rate: %d\n", ret); + return ret; + } + + return 0; +} + +static int fs210x_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct fs210x_priv *fs210x; + + fs210x = snd_soc_component_get_drvdata(dai->component); + + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: + /* Only supports consumer mode */ + break; + default: + dev_err(fs210x->dev, "Only supports consumer mode\n"); + return -EINVAL; + } + + return 0; +} + +static int fs210x_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct fs210x_priv *fs210x; + int chn_num; + int ret; + + if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) + return 0; + + fs210x = snd_soc_component_get_drvdata(dai->component); + + fs210x->srate = params_rate(params); + fs210x->bclk = snd_soc_params_to_bclk(params); + chn_num = params_channels(params); + if (chn_num == 1) /* mono */ + fs210x->bclk *= 2; /* I2S bus has 2 channels */ + + /* The FS2105S can't support 16kHz sample rate. */ + if (fs210x->devid == FS2105S_DEVICE_ID && fs210x->srate == 16000) + return -EOPNOTSUPP; + + mutex_lock(&fs210x->lock); + ret = fs210x_set_hw_params(fs210x); + mutex_unlock(&fs210x->lock); + if (ret) + dev_err(fs210x->dev, "Failed to set hw params: %d\n", ret); + + return ret; +} + +static int fs210x_dai_mute(struct snd_soc_dai *dai, int mute, int stream) +{ + struct fs210x_priv *fs210x; + unsigned long delay; + + if (stream != SNDRV_PCM_STREAM_PLAYBACK) + return 0; + + fs210x = snd_soc_component_get_drvdata(dai->component); + + mutex_lock(&fs210x->lock); + + if (!fs210x->is_inited || fs210x->is_suspended) { + mutex_unlock(&fs210x->lock); + return 0; + } + + mutex_unlock(&fs210x->lock); + + if (mute) { + cancel_delayed_work_sync(&fs210x->fault_check_work); + cancel_delayed_work_sync(&fs210x->start_work); + } else { + delay = msecs_to_jiffies(fs210x->check_interval_ms); + schedule_delayed_work(&fs210x->fault_check_work, delay); + } + + return 0; +} + +static int fs210x_dai_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct fs210x_priv *fs210x; + + fs210x = snd_soc_component_get_drvdata(dai->component); + + mutex_lock(&fs210x->lock); + + if (!fs210x->is_inited || fs210x->is_suspended || fs210x->is_playing) { + mutex_unlock(&fs210x->lock); + return 0; + } + + mutex_unlock(&fs210x->lock); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + /* + * According to the power up/down sequence of FS210x, + * it requests the I2S clock has been present + * and stable(>= 2ms) before playing. + */ + schedule_delayed_work(&fs210x->start_work, + msecs_to_jiffies(FS210X_START_DELAY_MS)); + break; + + default: + break; + } + + return 0; +} + +static void fs210x_start_work(struct work_struct *work) +{ + struct fs210x_priv *fs210x; + int ret; + + fs210x = container_of(work, struct fs210x_priv, start_work.work); + + mutex_lock(&fs210x->lock); + + ret = fs210x_dev_play(fs210x); + if (ret) + dev_err(fs210x->dev, "Failed to start playing: %d\n", ret); + + mutex_unlock(&fs210x->lock); +} + +static void fs210x_fault_check_work(struct work_struct *work) +{ + struct fs210x_priv *fs210x; + u16 status; + int ret; + + fs210x = container_of(work, struct fs210x_priv, fault_check_work.work); + + mutex_lock(&fs210x->lock); + + if (!fs210x->is_inited || fs210x->is_suspended || !fs210x->is_playing) { + mutex_unlock(&fs210x->lock); + return; + } + + ret = fs210x_reg_read(fs210x, FS210X_05H_ANASTAT, &status); + mutex_unlock(&fs210x->lock); + if (ret) + return; + + if (!(status & FS210X_05H_PVDD_MASK)) + dev_err(fs210x->dev, "PVDD fault\n"); + if (status & FS210X_05H_OCDL_MASK) + dev_err(fs210x->dev, "OC detected\n"); + if (status & FS210X_05H_UVDL_MASK) + dev_err(fs210x->dev, "UV detected\n"); + if (status & FS210X_05H_OVDL_MASK) + dev_err(fs210x->dev, "OV detected\n"); + if (status & FS210X_05H_OTPDL_MASK) + dev_err(fs210x->dev, "OT detected\n"); + if (status & FS210X_05H_OCRDL_MASK) + dev_err(fs210x->dev, "OCR detected\n"); + if (status & FS210X_05H_OCLDL_MASK) + dev_err(fs210x->dev, "OCL detected\n"); + if (status & FS210X_05H_DCRDL_MASK) + dev_err(fs210x->dev, "DCR detected\n"); + if (status & FS210X_05H_DCLDL_MASK) + dev_err(fs210x->dev, "DCL detected\n"); + if (status & FS210X_05H_SRDL_MASK) + dev_err(fs210x->dev, "SR detected\n"); + if (status & FS210X_05H_OTWDL_MASK) + dev_err(fs210x->dev, "OTW detected\n"); + if (!(status & FS210X_05H_AMPS_MASK)) + dev_dbg(fs210x->dev, "Amplifier unready\n"); + if (!(status & FS210X_05H_PLLS_MASK)) + dev_err(fs210x->dev, "PLL unlock\n"); + if (!(status & FS210X_05H_ANAS_MASK)) + dev_err(fs210x->dev, "Analog power fault\n"); + + schedule_delayed_work(&fs210x->fault_check_work, + msecs_to_jiffies(fs210x->check_interval_ms)); +} + +static int fs210x_get_drvdata_from_kctrl(struct snd_kcontrol *kctrl, + struct fs210x_priv **fs210x) +{ + struct snd_soc_component *cmpnt; + + if (!kctrl) { + pr_err("fs210x: kcontrol is null\n"); + return -EINVAL; + } + + cmpnt = snd_soc_kcontrol_component(kctrl); + if (!cmpnt) { + pr_err("fs210x: component is null\n"); + return -EINVAL; + } + + *fs210x = snd_soc_component_get_drvdata(cmpnt); + + return 0; +} + +static int fs210x_effect_scene_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + const struct fs_amp_scene *scene; + struct fs210x_priv *fs210x; + const char *name = "N/A"; + int idx, count; + int ret; + + ret = fs210x_get_drvdata_from_kctrl(kcontrol, &fs210x); + if (ret || !fs210x->dev) { + pr_err("scene_effect_info: fs210x is null\n"); + return -EINVAL; + } + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + + count = fs210x->amp_lib.scene_count - 1; /* Skip init scene */ + if (count < 1) { + uinfo->value.enumerated.items = 0; + return 0; + } + + uinfo->value.enumerated.items = count; + if (uinfo->value.enumerated.item >= count) + uinfo->value.enumerated.item = count - 1; + + idx = uinfo->value.enumerated.item; + scene = fs210x->amp_lib.scene + idx + 1; + if (scene->name) + name = scene->name; + + strscpy(uinfo->value.enumerated.name, name, strlen(name) + 1); + + return 0; +} + +static int fs210x_effect_scene_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct fs210x_priv *fs210x; + int index; + int ret; + + ret = fs210x_get_drvdata_from_kctrl(kcontrol, &fs210x); + if (ret || !fs210x->dev) { + pr_err("scene_effect_get: fs210x is null\n"); + return -EINVAL; + } + + /* The id of effect scene is from 1 to N. */ + if (fs210x->scene_id < 1) + return -EINVAL; + + mutex_lock(&fs210x->lock); + /* + * FS210x has scene(s) as below: + * init scene: id = 0 + * effect scene(s): id = 1~N (optional) + * effect_index = scene_id - 1 + */ + index = fs210x->scene_id - 1; + ucontrol->value.integer.value[0] = index; + mutex_unlock(&fs210x->lock); + + return 0; +} + +static int fs210x_effect_scene_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct fs210x_priv *fs210x; + int scene_id, scene_count; + bool is_changed = false; + int ret; + + ret = fs210x_get_drvdata_from_kctrl(kcontrol, &fs210x); + if (ret || !fs210x->dev) { + pr_err("scene_effect_put: fs210x is null\n"); + return -EINVAL; + } + + mutex_lock(&fs210x->lock); + + /* + * FS210x has scene(s) as below: + * init scene: id = 0 (It's set in fs210x_init_chip() only) + * effect scene(s): id = 1~N (optional) + * scene_id = effect_index + 1. + */ + scene_id = ucontrol->value.integer.value[0] + 1; + scene_count = fs210x->amp_lib.scene_count - 1; /* Skip init scene */ + if (scene_id < 1 || scene_id > scene_count) { + mutex_unlock(&fs210x->lock); + return -ERANGE; + } + + if (scene_id != fs210x->scene_id) + is_changed = true; + + if (fs210x->is_suspended) { + fs210x->scene_id = scene_id; + mutex_unlock(&fs210x->lock); + return is_changed; + } + + ret = fs210x_set_scene(fs210x, scene_id); + if (ret) + dev_err(fs210x->dev, "Failed to set scene: %d\n", ret); + + mutex_unlock(&fs210x->lock); + + if (!ret && is_changed) + return 1; + + return ret; +} + +static int fs210x_playback_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct fs210x_priv *fs210x = snd_soc_component_get_drvdata(cmpnt); + int ret = 0; + + mutex_lock(&fs210x->lock); + + if (fs210x->is_suspended) { + mutex_unlock(&fs210x->lock); + return 0; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* + * If there is no bclk for us to set the clock output, + * we will enable the device(start_work) in dai trigger. + */ + if (!fs210x->clk_bclk) + break; + fs210x_bclk_set(fs210x, true); + ret = fs210x_dev_play(fs210x); + break; + case SND_SOC_DAPM_POST_PMD: + ret = fs210x_dev_stop(fs210x); + fs210x_bclk_set(fs210x, false); + break; + default: + break; + } + + mutex_unlock(&fs210x->lock); + + return ret; +} + +static const struct snd_soc_dai_ops fs210x_dai_ops = { + .startup = fs210x_dai_startup, + .set_fmt = fs210x_dai_set_fmt, + .hw_params = fs210x_dai_hw_params, + .mute_stream = fs210x_dai_mute, + .trigger = fs210x_dai_trigger, +}; + +static const struct snd_soc_dai_driver fs210x_dai = { + .name = FS210X_DEFAULT_DAI_NAME, + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = FS210X_RATES, + .formats = FS210X_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = FS210X_RATES, + .formats = FS210X_FORMATS, + }, + .ops = &fs210x_dai_ops, + .symmetric_rate = 1, + .symmetric_sample_bits = 1, +}; + +static const DECLARE_TLV_DB_SCALE(fs2105s_vol_tlv, -9709, 19, 1); +static const DECLARE_TLV_DB_SCALE(fs210x_vol_tlv, -13357, 19, 1); + +static const struct snd_kcontrol_new fs2105s_vol_control[] = { + SOC_DOUBLE_R_TLV("PCM Playback Volume", + FS210X_39H_LVOLCTRL, FS210X_3AH_RVOLCTRL, + 7, 0x1FF, 0, fs2105s_vol_tlv), +}; + +static const struct snd_kcontrol_new fs210x_vol_control[] = { + SOC_DOUBLE_R_TLV("PCM Playback Volume", + FS210X_39H_LVOLCTRL, FS210X_3AH_RVOLCTRL, + 6, 0x2BF, 0, fs210x_vol_tlv), +}; + +static const struct snd_kcontrol_new fs210x_controls[] = { + SOC_DOUBLE("DAC Mute Switch", FS210X_30H_DACCTRL, 4, 8, 1, 0), + SOC_DOUBLE("DAC Fade Switch", FS210X_30H_DACCTRL, 5, 9, 1, 0), +}; + +static const struct snd_kcontrol_new fs210x_scene_control[] = { + FS_SOC_ENUM_EXT("Effect Scene", + fs210x_effect_scene_info, + fs210x_effect_scene_get, + fs210x_effect_scene_put), +}; + +static const struct snd_soc_dapm_widget fs210x_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN_E("AIF IN", "Playback", 0, SND_SOC_NOPM, 0, 0, + fs210x_playback_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_OUT("AIF OUT", "Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_OUTPUT("OUTL"), + SND_SOC_DAPM_OUTPUT("OUTR"), + SND_SOC_DAPM_INPUT("SDO"), +}; + +static const struct snd_soc_dapm_route fs210x_dapm_routes[] = { + { "OUTL", NULL, "AIF IN" }, + { "OUTR", NULL, "AIF IN" }, + { "AIF OUT", NULL, "SDO" }, +}; + +static int fs210x_add_mixer_controls(struct fs210x_priv *fs210x, + struct snd_soc_component *cmpnt) +{ + const struct snd_kcontrol_new *kctrl; + int count; + int ret; + + if (!fs210x || !cmpnt) + return -EINVAL; + + if (fs210x->devid == FS2105S_DEVICE_ID) { + kctrl = fs2105s_vol_control; + count = ARRAY_SIZE(fs2105s_vol_control); + } else { + kctrl = fs210x_vol_control; + count = ARRAY_SIZE(fs210x_vol_control); + } + + ret = snd_soc_add_component_controls(cmpnt, kctrl, count); + if (ret) + return ret; + + /* + * If the firmware has no scene or only init scene, + * we skip adding this mixer control. + */ + if (fs210x->amp_lib.scene_count < 2) + return 0; + + kctrl = fs210x_scene_control; + count = ARRAY_SIZE(fs210x_scene_control); + + return snd_soc_add_component_controls(cmpnt, kctrl, count); +} + +static int fs210x_probe(struct snd_soc_component *cmpnt) +{ + struct fs210x_priv *fs210x; + int ret; + + fs210x = snd_soc_component_get_drvdata(cmpnt); + if (!fs210x || !fs210x->dev) + return -EINVAL; + + fs210x->amp_lib.dev = fs210x->dev; + fs210x->amp_lib.devid = fs210x->devid; + + ret = fs_amp_load_firmware(&fs210x->amp_lib, fs210x->pdata.fwm_name); + if (ret) + return ret; + + ret = fs210x_add_mixer_controls(fs210x, cmpnt); + if (ret) + return ret; + + mutex_lock(&fs210x->lock); + ret = fs210x_init_chip(fs210x); + mutex_unlock(&fs210x->lock); + + return ret; +} + +static void fs210x_remove(struct snd_soc_component *cmpnt) +{ + struct fs210x_priv *fs210x; + + fs210x = snd_soc_component_get_drvdata(cmpnt); + if (!fs210x || !fs210x->dev) + return; + + cancel_delayed_work_sync(&fs210x->start_work); + cancel_delayed_work_sync(&fs210x->fault_check_work); +} + +#ifdef CONFIG_PM +static int fs210x_suspend(struct snd_soc_component *cmpnt) +{ + struct fs210x_priv *fs210x; + int ret; + + fs210x = snd_soc_component_get_drvdata(cmpnt); + if (!fs210x || !fs210x->dev) + return -EINVAL; + + regcache_cache_only(fs210x->regmap, true); + + mutex_lock(&fs210x->lock); + fs210x->cur_scene = NULL; + fs210x->is_inited = false; + fs210x->is_playing = false; + fs210x->is_suspended = true; + + gpiod_set_value_cansleep(fs210x->gpio_sdz, 1); /* Active */ + fsleep(30000); /* >= 30ms */ + mutex_unlock(&fs210x->lock); + + cancel_delayed_work_sync(&fs210x->start_work); + cancel_delayed_work_sync(&fs210x->fault_check_work); + + ret = regulator_bulk_disable(FS210X_NUM_SUPPLIES, fs210x->supplies); + if (ret) { + dev_err(fs210x->dev, "Failed to suspend: %d\n", ret); + return ret; + } + + return 0; +} + +static int fs210x_resume(struct snd_soc_component *cmpnt) +{ + struct fs210x_priv *fs210x; + int ret; + + fs210x = snd_soc_component_get_drvdata(cmpnt); + if (!fs210x || !fs210x->dev) + return -EINVAL; + + ret = regulator_bulk_enable(FS210X_NUM_SUPPLIES, fs210x->supplies); + if (ret) { + dev_err(fs210x->dev, "Failed to enable supplies: %d\n", ret); + return ret; + } + + mutex_lock(&fs210x->lock); + + fs210x->is_suspended = false; + ret = fs210x_init_chip(fs210x); + + mutex_unlock(&fs210x->lock); + + return ret; +} +#else +#define fs210x_suspend NULL +#define fs210x_resume NULL +#endif // CONFIG_PM + +static bool fs210x_volatile_registers(struct device *dev, unsigned int reg) +{ + switch (reg) { + case FS210X_00H_STATUS ... FS210X_0FH_I2CADDR: + case FS210X_ABH_INTSTAT: + case FS210X_ACH_INTSTATR: + return true; + default: + return false; + } +} + +static const struct snd_soc_component_driver fs210x_soc_component_dev = { + .probe = fs210x_probe, + .remove = fs210x_remove, + .suspend = fs210x_suspend, + .resume = fs210x_resume, + .controls = fs210x_controls, + .num_controls = ARRAY_SIZE(fs210x_controls), + .dapm_widgets = fs210x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(fs210x_dapm_widgets), + .dapm_routes = fs210x_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(fs210x_dapm_routes), +}; + +static const struct regmap_config fs210x_regmap = { + .reg_bits = 8, + .val_bits = 16, + .max_register = FS210X_REG_MAX, + .val_format_endian = REGMAP_ENDIAN_BIG, + .cache_type = REGCACHE_MAPLE, + .volatile_reg = fs210x_volatile_registers, +}; + +static int fs210x_detect_device(struct fs210x_priv *fs210x) +{ + u16 devid; + int ret; + + ret = fs210x_reg_read(fs210x, FS210X_03H_DEVID, &devid); + if (ret) + return ret; + + fs210x->devid = HI_U16(devid); + + switch (fs210x->devid) { + case FS210X_DEVICE_ID: + dev_info(fs210x->dev, "FS2104 detected\n"); + break; + case FS2105S_DEVICE_ID: + dev_info(fs210x->dev, "FS2105S detected\n"); + break; + default: + dev_err(fs210x->dev, "DEVID: 0x%04X dismatch\n", devid); + return -ENODEV; + } + + return 0; +} + +static int fs210x_parse_dts(struct fs210x_priv *fs210x, + struct fs210x_platform_data *pdata) +{ + struct device_node *node = fs210x->dev->of_node; + int i, ret; + + if (!node) + return 0; + + ret = of_property_read_string(node, "firmware-name", &pdata->fwm_name); + if (ret) + pdata->fwm_name = FS210X_DEFAULT_FWM_NAME; + + fs210x->gpio_sdz = devm_gpiod_get_optional(fs210x->dev, + "reset", GPIOD_OUT_HIGH); + if (IS_ERR(fs210x->gpio_sdz)) + return dev_err_probe(fs210x->dev, PTR_ERR(fs210x->gpio_sdz), + "Failed to get reset-gpios\n"); + + for (i = 0; i < FS210X_NUM_SUPPLIES; i++) + fs210x->supplies[i].supply = fs210x_supply_names[i]; + + ret = devm_regulator_bulk_get(fs210x->dev, + ARRAY_SIZE(fs210x->supplies), + fs210x->supplies); + if (ret) + return dev_err_probe(fs210x->dev, ret, + "Failed to get supplies\n"); + + return 0; +} + +static void fs210x_deinit(struct fs210x_priv *fs210x) +{ + gpiod_set_value_cansleep(fs210x->gpio_sdz, 1); /* Active */ + fsleep(10000); /* >= 10ms */ + + regulator_bulk_disable(FS210X_NUM_SUPPLIES, fs210x->supplies); +} + +static int fs210x_init(struct fs210x_priv *fs210x) +{ + int ret; + + ret = fs210x_parse_dts(fs210x, &fs210x->pdata); + if (ret) + return ret; + + fs210x->clk_bclk = devm_clk_get_optional(fs210x->dev, "bclk"); + if (IS_ERR(fs210x->clk_bclk)) + return dev_err_probe(fs210x->dev, PTR_ERR(fs210x->clk_bclk), + "Failed to get bclk\n"); + + ret = regulator_bulk_enable(FS210X_NUM_SUPPLIES, fs210x->supplies); + if (ret) + return dev_err_probe(fs210x->dev, ret, + "Failed to enable supplies\n"); + + /* Make sure the SDZ pin is pulled down enough time. */ + fsleep(10000); /* >= 10ms */ + gpiod_set_value_cansleep(fs210x->gpio_sdz, 0); /* Deactivate */ + fsleep(10000); /* >= 10ms */ + + ret = fs210x_detect_device(fs210x); + if (ret) { + fs210x_deinit(fs210x); + return ret; + } + + fs210x->scene_id = -1; /* Invalid scene */ + fs210x->cur_scene = NULL; + fs210x->is_playing = false; + fs210x->is_inited = false; + fs210x->is_suspended = false; + fs210x->check_interval_ms = FS210X_FAULT_CHECK_INTERVAL_MS; + + INIT_DELAYED_WORK(&fs210x->fault_check_work, fs210x_fault_check_work); + INIT_DELAYED_WORK(&fs210x->start_work, fs210x_start_work); + mutex_init(&fs210x->lock); + + return 0; +} + +static int fs210x_register_snd_component(struct fs210x_priv *fs210x) +{ + struct snd_soc_dai_driver *dai_drv; + static int instance_id; + int ret; + + dai_drv = devm_kmemdup(fs210x->dev, &fs210x_dai, + sizeof(fs210x_dai), GFP_KERNEL); + if (!dai_drv) + return -ENOMEM; + + dai_drv->name = devm_kasprintf(fs210x->dev, + GFP_KERNEL, "%s-%d", + dai_drv->name, instance_id); + instance_id++; + + if (fs210x->devid == FS2105S_DEVICE_ID) { + dai_drv->playback.rates = FS2105S_RATES; + dai_drv->capture.rates = FS2105S_RATES; + } + + ret = snd_soc_register_component(fs210x->dev, + &fs210x_soc_component_dev, + dai_drv, 1); + return ret; +} + +static ssize_t check_interval_ms_show(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct fs210x_priv *fs210x = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%d\n", fs210x->check_interval_ms); +} + +static ssize_t check_interval_ms_store(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct fs210x_priv *fs210x = dev_get_drvdata(dev); + int ret; + + ret = kstrtouint(buf, 10, &fs210x->check_interval_ms); + if (ret) + return -EINVAL; + + return (ssize_t)count; +} + +static DEVICE_ATTR_RW(check_interval_ms); + +static struct attribute *fs210x_attrs[] = { + &dev_attr_check_interval_ms.attr, + NULL, +}; + +static struct attribute_group fs210x_attr_group = { + .attrs = fs210x_attrs, +}; + +static int fs210x_i2c_probe(struct i2c_client *client) +{ + struct fs210x_priv *fs210x; + int ret; + + fs210x = devm_kzalloc(&client->dev, sizeof(*fs210x), GFP_KERNEL); + if (!fs210x) + return -ENOMEM; + + fs210x->i2c = client; + fs210x->dev = &client->dev; + i2c_set_clientdata(client, fs210x); + + fs210x->regmap = devm_regmap_init_i2c(client, &fs210x_regmap); + if (IS_ERR(fs210x->regmap)) + return dev_err_probe(fs210x->dev, PTR_ERR(fs210x->regmap), + "Failed to get regmap\n"); + + ret = fs210x_init(fs210x); + if (ret) + return ret; + + ret = devm_device_add_group(fs210x->dev, &fs210x_attr_group); + if (ret) { + fs210x_deinit(fs210x); + return dev_err_probe(fs210x->dev, ret, + "Failed to create sysfs group\n"); + } + + ret = fs210x_register_snd_component(fs210x); + if (ret) { + fs210x_deinit(fs210x); + return dev_err_probe(fs210x->dev, ret, + "Failed to register component\n"); + } + + return 0; +} + +static void fs210x_i2c_remove(struct i2c_client *client) +{ + struct fs210x_priv *fs210x = i2c_get_clientdata(client); + + snd_soc_unregister_component(fs210x->dev); + fs210x_deinit(fs210x); +} + +static const struct i2c_device_id fs210x_i2c_id[] = { + { "fs2104" }, + { "fs2105s" }, + {} +}; +MODULE_DEVICE_TABLE(i2c, fs210x_i2c_id); + +static const struct of_device_id fs210x_of_match[] = { + { .compatible = "foursemi,fs2105s", }, + {}, +}; +MODULE_DEVICE_TABLE(of, fs210x_of_match); + +static struct i2c_driver fs210x_i2c_driver = { + .driver = { + .name = "fs210x", + .of_match_table = fs210x_of_match, + }, + .id_table = fs210x_i2c_id, + .probe = fs210x_i2c_probe, + .remove = fs210x_i2c_remove, +}; + +module_i2c_driver(fs210x_i2c_driver); + +MODULE_AUTHOR("Nick Li "); +MODULE_DESCRIPTION("FS2104/5S Audio Amplifier Driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/fs210x.h b/sound/soc/codecs/fs210x.h new file mode 100644 index 000000000000..78e1760332ca --- /dev/null +++ b/sound/soc/codecs/fs210x.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * fs210x.h -- Driver for the FS2104/5S Audio Amplifier + * + * Copyright (C) 2016-2025 Shanghai FourSemi Semiconductor Co.,Ltd. + */ + +#ifndef __FS210X_H__ +#define __FS210X_H__ + +#define FS210X_00H_STATUS 0x00 +#define FS210X_03H_DEVID 0x03 +#define FS210X_05H_ANASTAT 0x05 +#define FS210X_06H_DIGSTAT 0x06 +#define FS210X_0BH_ACCKEY 0x0B +#define FS210X_0FH_I2CADDR 0x0F +#define FS210X_10H_PWRCTRL 0x10 +#define FS210X_11H_SYSCTRL 0x11 +#define FS210X_17H_I2SCTRL 0x17 +#define FS210X_30H_DACCTRL 0x30 +#define FS210X_39H_LVOLCTRL 0x39 +#define FS210X_3AH_RVOLCTRL 0x3A +#define FS210X_42H_DACEQWL 0x42 +#define FS210X_46H_DACEQA 0x46 +#define FS210X_A1H_PLLCTRL1 0xA1 +#define FS210X_A2H_PLLCTRL2 0xA2 +#define FS210X_A3H_PLLCTRL3 0xA3 +#define FS210X_ABH_INTSTAT 0xAB +#define FS210X_ACH_INTSTATR 0xAC + +#define FS210X_05H_PVDD_SHIFT 14 +#define FS210X_05H_PVDD_MASK BIT(14) +#define FS210X_05H_OCDL_SHIFT 13 +#define FS210X_05H_OCDL_MASK BIT(13) +#define FS210X_05H_UVDL_SHIFT 12 +#define FS210X_05H_UVDL_MASK BIT(12) +#define FS210X_05H_OVDL_SHIFT 11 +#define FS210X_05H_OVDL_MASK BIT(11) +#define FS210X_05H_OTPDL_SHIFT 10 +#define FS210X_05H_OTPDL_MASK BIT(10) +#define FS210X_05H_OCRDL_SHIFT 9 +#define FS210X_05H_OCRDL_MASK BIT(9) +#define FS210X_05H_OCLDL_SHIFT 8 +#define FS210X_05H_OCLDL_MASK BIT(8) +#define FS210X_05H_DCRDL_SHIFT 7 +#define FS210X_05H_DCRDL_MASK BIT(7) +#define FS210X_05H_DCLDL_SHIFT 6 +#define FS210X_05H_DCLDL_MASK BIT(6) +#define FS210X_05H_SRDL_SHIFT 5 +#define FS210X_05H_SRDL_MASK BIT(5) +#define FS210X_05H_OTWDL_SHIFT 4 +#define FS210X_05H_OTWDL_MASK BIT(4) +#define FS210X_05H_AMPS_SHIFT 3 +#define FS210X_05H_AMPS_MASK BIT(3) +#define FS210X_05H_PLLS_SHIFT 1 +#define FS210X_05H_PLLS_MASK BIT(1) +#define FS210X_05H_ANAS_SHIFT 0 +#define FS210X_05H_ANAS_MASK BIT(0) +#define FS210X_17H_I2SSR_SHIFT 12 +#define FS210X_17H_I2SSR_MASK GENMASK(15, 12) +#define FS210X_30H_RMUTE_SHIFT 8 +#define FS210X_30H_LMUTE_SHIFT 4 + +#define FS210X_0BH_ACCKEY_ON 0x0091 +#define FS210X_0BH_ACCKEY_OFF 0x0000 +#define FS210X_10H_I2C_RESET 0x0002 +#define FS210X_11H_DPS_HIZ 0x0100 +#define FS210X_11H_DPS_PWDN 0x0000 +#define FS210X_11H_DPS_PLAY 0x0300 +#define FS210X_46H_CAM_BURST_L 0x8000 +#define FS210X_46H_CAM_BURST_R 0x8200 +#define FS2105S_46H_CAM_BURST_W 0x8400 +#define FS210X_46H_CAM_CLEAR 0x0000 + +#endif /* __FS210X_H__ */ From 2291a2186305faaf8525d57849d8ba12ad63f5e7 Mon Sep 17 00:00:00 2001 From: Nick Li Date: Mon, 11 Aug 2025 18:46:10 +0800 Subject: [PATCH 00171/11391] MAINTAINERS: Add entry for FourSemi audio amplifiers Add entry for FourSemi maintainer and related files Signed-off-by: Nick Li Link: https://patch.msgid.link/B9209BC5189B8946+20250811104610.8993-6-nick.li@foursemi.com Signed-off-by: Mark Brown --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index fe168477caa4..dd38bd429e4f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9573,6 +9573,14 @@ F: lib/tests/memcpy_kunit.c K: \bunsafe_memcpy\b K: \b__NO_FORTIFY\b +FOURSEMI AUDIO AMPLIFIER DRIVER +M: Nick Li +L: linux-sound@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/sound/foursemi,fs2105s.yaml +F: sound/soc/codecs/fs-amp-lib.* +F: sound/soc/codecs/fs210x.* + FPGA DFL DRIVERS M: Xu Yilun R: Tom Rix From 57a75fa9d56e310e883e4377205690e88c05781b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 1 Aug 2025 16:34:45 +0300 Subject: [PATCH 00172/11391] 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 00173/11391] 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 1071d560afb4c245c2076494226df47db5a35708 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Mon, 11 Aug 2025 13:17:32 +0200 Subject: [PATCH 00174/11391] dm-stripe: fix a possible integer overflow There's a possible integer overflow in stripe_io_hints if we have too large chunk size. Test if the overflow happened, and if it did, don't set limits->io_min and limits->io_opt; Signed-off-by: Mikulas Patocka Reviewed-by: John Garry Suggested-by: Dongsheng Yang Cc: stable@vger.kernel.org --- drivers/md/dm-stripe.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c index 58902091bf79..1461dc740dae 100644 --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c @@ -456,11 +456,15 @@ static void stripe_io_hints(struct dm_target *ti, struct queue_limits *limits) { struct stripe_c *sc = ti->private; - unsigned int chunk_size = sc->chunk_size << SECTOR_SHIFT; + unsigned int io_min, io_opt; limits->chunk_sectors = sc->chunk_size; - limits->io_min = chunk_size; - limits->io_opt = chunk_size * sc->stripes; + + if (!check_shl_overflow(sc->chunk_size, SECTOR_SHIFT, &io_min) && + !check_mul_overflow(io_min, sc->stripes, &io_opt)) { + limits->io_min = io_min; + limits->io_opt = io_opt; + } } static struct target_type stripe_target = { From 1ccc2e20fe1d3b91395de8ca9ce0efe070287534 Mon Sep 17 00:00:00 2001 From: Darshan Rathod Date: Fri, 1 Aug 2025 16:17:05 +0530 Subject: [PATCH 00175/11391] 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 00176/11391] 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 15a04f94f42973d85afa2df66f1d18e0bca3385c Mon Sep 17 00:00:00 2001 From: Thiago Becker Date: Thu, 24 Jul 2025 17:35:16 -0300 Subject: [PATCH 00177/11391] locks: Remove the last reference to EXPORT_OP_ASYNC_LOCK. Commit b875bd5b381e ("exportfs: Remove EXPORT_OP_ASYNC_LOCK") removed all references to EXPORT_OP_ASYNC_LOCK, but one lasted in the comments for fs/locks.c. Remove it. Signed-off-by: Thiago Becker Link: https://lore.kernel.org/20250724203516.153616-1-tbecker@redhat.com Signed-off-by: Christian Brauner --- fs/locks.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index 559f02aa4172..04a3f0e20724 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -2328,8 +2328,8 @@ int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock *flock) * To avoid blocking kernel daemons, such as lockd, that need to acquire POSIX * locks, the ->lock() interface may return asynchronously, before the lock has * been granted or denied by the underlying filesystem, if (and only if) - * lm_grant is set. Additionally EXPORT_OP_ASYNC_LOCK in export_operations - * flags need to be set. + * lm_grant is set. Additionally FOP_ASYNC_LOCK in file_operations fop_flags + * need to be set. * * Callers expecting ->lock() to return asynchronously will only use F_SETLK, * not F_SETLKW; they will set FL_SLEEP if (and only if) the request is for a From 17e8b7e08fa8bf7a936f70444a42a88750410251 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 24 Jul 2025 09:48:54 +0200 Subject: [PATCH 00178/11391] fs: mark file_remove_privs_flags static file_remove_privs_flags is only used inside of inode.c, mark it static. Signed-off-by: Christoph Hellwig Link: https://lore.kernel.org/20250724074854.3316911-1-hch@lst.de Signed-off-by: Christian Brauner --- fs/inode.c | 3 +-- include/linux/fs.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/inode.c b/fs/inode.c index 01ebdc40021e..3cbb78412a3e 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -2189,7 +2189,7 @@ static int __remove_privs(struct mnt_idmap *idmap, return notify_change(idmap, dentry, &newattrs, NULL); } -int file_remove_privs_flags(struct file *file, unsigned int flags) +static int file_remove_privs_flags(struct file *file, unsigned int flags) { struct dentry *dentry = file_dentry(file); struct inode *inode = file_inode(file); @@ -2214,7 +2214,6 @@ int file_remove_privs_flags(struct file *file, unsigned int flags) inode_has_no_xattr(inode); return error; } -EXPORT_SYMBOL_GPL(file_remove_privs_flags); /** * file_remove_privs - remove special file privileges (suid, capabilities) diff --git a/include/linux/fs.h b/include/linux/fs.h index d7ab4f96d705..796319914b0a 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -3393,7 +3393,6 @@ static inline struct inode *new_inode_pseudo(struct super_block *sb) extern struct inode *new_inode(struct super_block *sb); extern void free_inode_nonrcu(struct inode *inode); extern int setattr_should_drop_suidgid(struct mnt_idmap *, struct inode *); -extern int file_remove_privs_flags(struct file *file, unsigned int flags); extern int file_remove_privs(struct file *); int setattr_should_drop_sgid(struct mnt_idmap *idmap, const struct inode *inode); From 4e021920812d164bb02c30cc40e08a3681b1c755 Mon Sep 17 00:00:00 2001 From: Kriish Sharma Date: Wed, 30 Jul 2025 20:18:53 +0000 Subject: [PATCH 00179/11391] fs: document 'name' parameter for name_contains_dotdot() The kernel-doc for name_contains_dotdot() was missing the @name parameter description, leading to a warning during make htmldocs. Add the missing documentation to resolve this warning. Signed-off-by: Kriish Sharma Link: https://lore.kernel.org/20250730201853.8436-1-kriish.sharma2006@gmail.com Reviewed-by: Jan Kara Signed-off-by: Christian Brauner --- include/linux/fs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/fs.h b/include/linux/fs.h index 796319914b0a..780e9c774c54 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -3281,7 +3281,7 @@ static inline bool is_dot_dotdot(const char *name, size_t len) /** * name_contains_dotdot - check if a file name contains ".." path components - * + * @name: File path string to check * Search for ".." surrounded by either '/' or start/end of string. */ static inline bool name_contains_dotdot(const char *name) From f7d812357e40ef3ce1c0dcdd929590f1dbc6c344 Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Fri, 8 Aug 2025 16:37:58 +0800 Subject: [PATCH 00180/11391] fs: fix "writen"->"written" Trivial fix to spelling mistake in comment text. Signed-off-by: Xichao Zhao Link: https://lore.kernel.org/20250808083758.229563-1-zhao.xichao@vivo.com Signed-off-by: Christian Brauner --- fs/namei.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/namei.c b/fs/namei.c index cd43ff89fbaa..138a693c2346 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -4828,7 +4828,7 @@ int vfs_link(struct dentry *old_dentry, struct mnt_idmap *idmap, return -EPERM; /* * Updating the link count will likely cause i_uid and i_gid to - * be writen back improperly if their true value is unknown to + * be written back improperly if their true value is unknown to * the vfs. */ if (HAS_UNMAPPED_ID(idmap, inode)) From 708c04a5c2b78e22f56e2350de41feba74dfccd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Tue, 5 Aug 2025 14:38:08 +0200 Subject: [PATCH 00181/11391] fs: always return zero on success from replace_fd() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit replace_fd() returns the number of the new file descriptor through the return value of do_dup2(). However its callers never care about the specific returned number. In fact the caller in receive_fd_replace() treats any non-zero return value as an error and therefore never calls __receive_sock() for most file descriptors, which is a bug. To fix the bug in receive_fd_replace() and to avoid the same issue happening in future callers, signal success through a plain zero. Suggested-by: Al Viro Link: https://lore.kernel.org/lkml/20250801220215.GS222315@ZenIV/ Fixes: 173817151b15 ("fs: Expand __receive_fd() to accept existing fd") Fixes: 42eb0d54c08a ("fs: split receive_fd_replace from __receive_fd") Cc: stable@vger.kernel.org Signed-off-by: Thomas Weißschuh Link: https://lore.kernel.org/20250805-fix-receive_fd_replace-v3-1-b72ba8b34bac@linutronix.de Signed-off-by: Christian Brauner --- fs/file.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/file.c b/fs/file.c index 6d2275c3be9c..28743b742e3c 100644 --- a/fs/file.c +++ b/fs/file.c @@ -1330,7 +1330,10 @@ int replace_fd(unsigned fd, struct file *file, unsigned flags) err = expand_files(files, fd); if (unlikely(err < 0)) goto out_unlock; - return do_dup2(files, file, fd, flags); + err = do_dup2(files, file, fd, flags); + if (err < 0) + return err; + return 0; out_unlock: spin_unlock(&files->file_lock); From 56ecfd9175b999dfc303ac6a0f9ea4bd1bee49d7 Mon Sep 17 00:00:00 2001 From: Pedro Falcato Date: Wed, 23 Jul 2025 14:21:54 +0100 Subject: [PATCH 00182/11391] fs: Remove mount_nodev mount_nodev has had no in-tree users since cc0876f817d6 ("vfs: Convert devpts to use the new mount API"). Remove it. Signed-off-by: Pedro Falcato Link: https://lore.kernel.org/20250723132156.225410-2-pfalcato@suse.de Signed-off-by: Christian Brauner --- fs/super.c | 20 -------------------- include/linux/fs.h | 3 --- 2 files changed, 23 deletions(-) diff --git a/fs/super.c b/fs/super.c index 7f876f32343a..7daa20737f2e 100644 --- a/fs/super.c +++ b/fs/super.c @@ -1773,26 +1773,6 @@ void kill_block_super(struct super_block *sb) EXPORT_SYMBOL(kill_block_super); #endif -struct dentry *mount_nodev(struct file_system_type *fs_type, - int flags, void *data, - int (*fill_super)(struct super_block *, void *, int)) -{ - int error; - struct super_block *s = sget(fs_type, NULL, set_anon_super, flags, NULL); - - if (IS_ERR(s)) - return ERR_CAST(s); - - error = fill_super(s, data, flags & SB_SILENT ? 1 : 0); - if (error) { - deactivate_locked_super(s); - return ERR_PTR(error); - } - s->s_flags |= SB_ACTIVE; - return dget(s->s_root); -} -EXPORT_SYMBOL(mount_nodev); - /** * vfs_get_tree - Get the mountable root * @fc: The superblock configuration context. diff --git a/include/linux/fs.h b/include/linux/fs.h index d7ab4f96d705..204328ed7ebb 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2716,9 +2716,6 @@ static inline bool is_mgtime(const struct inode *inode) extern struct dentry *mount_bdev(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, int (*fill_super)(struct super_block *, void *, int)); -extern struct dentry *mount_nodev(struct file_system_type *fs_type, - int flags, void *data, - int (*fill_super)(struct super_block *, void *, int)); extern struct dentry *mount_subtree(struct vfsmount *mnt, const char *path); void retire_super(struct super_block *sb); void generic_shutdown_super(struct super_block *sb); From f7d161c2804f3ad36bdc3222cb93c8fee67be98c Mon Sep 17 00:00:00 2001 From: Pedro Falcato Date: Wed, 23 Jul 2025 14:21:55 +0100 Subject: [PATCH 00183/11391] fs: Remove mount_bdev mount_bdev has no in-tree users ever since f2fs adopted the new mount API. Remove it. Signed-off-by: Pedro Falcato Link: https://lore.kernel.org/20250723132156.225410-3-pfalcato@suse.de Signed-off-by: Christian Brauner --- fs/super.c | 43 ------------------------------------------- include/linux/fs.h | 3 --- 2 files changed, 46 deletions(-) diff --git a/fs/super.c b/fs/super.c index 7daa20737f2e..a038848e8d1f 100644 --- a/fs/super.c +++ b/fs/super.c @@ -1716,49 +1716,6 @@ int get_tree_bdev(struct fs_context *fc, } EXPORT_SYMBOL(get_tree_bdev); -static int test_bdev_super(struct super_block *s, void *data) -{ - return !(s->s_iflags & SB_I_RETIRED) && s->s_dev == *(dev_t *)data; -} - -struct dentry *mount_bdev(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, - int (*fill_super)(struct super_block *, void *, int)) -{ - struct super_block *s; - int error; - dev_t dev; - - error = lookup_bdev(dev_name, &dev); - if (error) - return ERR_PTR(error); - - flags |= SB_NOSEC; - s = sget(fs_type, test_bdev_super, set_bdev_super, flags, &dev); - if (IS_ERR(s)) - return ERR_CAST(s); - - if (s->s_root) { - if ((flags ^ s->s_flags) & SB_RDONLY) { - deactivate_locked_super(s); - return ERR_PTR(-EBUSY); - } - } else { - error = setup_bdev_super(s, flags, NULL); - if (!error) - error = fill_super(s, data, flags & SB_SILENT ? 1 : 0); - if (error) { - deactivate_locked_super(s); - return ERR_PTR(error); - } - - s->s_flags |= SB_ACTIVE; - } - - return dget(s->s_root); -} -EXPORT_SYMBOL(mount_bdev); - void kill_block_super(struct super_block *sb) { struct block_device *bdev = sb->s_bdev; diff --git a/include/linux/fs.h b/include/linux/fs.h index 204328ed7ebb..98afcf455b28 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2713,9 +2713,6 @@ static inline bool is_mgtime(const struct inode *inode) return inode->i_opflags & IOP_MGTIME; } -extern struct dentry *mount_bdev(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, - int (*fill_super)(struct super_block *, void *, int)); extern struct dentry *mount_subtree(struct vfsmount *mnt, const char *path); void retire_super(struct super_block *sb); void generic_shutdown_super(struct super_block *sb); From ad7fe23b4b0dc0c26187df92a5649948ef7049fa Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Wed, 6 Aug 2025 16:07:05 +1000 Subject: [PATCH 00184/11391] fscontext: add custom-prefix log helpers Sometimes, errors associated with an fscontext come from the VFS or otherwise outside of the filesystem driver itself. However, the default logging of errorfc will always prefix the message with the filesystem name. So, add some *fcp() wrappers that allow for custom prefixes to be used when emitting information to the fscontext log. Signed-off-by: Aleksa Sarai Link: https://lore.kernel.org/20250806-errorfc-mount-too-revealing-v2-1-534b9b4d45bb@cyphar.com Signed-off-by: Christian Brauner --- include/linux/fs_context.h | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/include/linux/fs_context.h b/include/linux/fs_context.h index 7773eb870039..671f031be173 100644 --- a/include/linux/fs_context.h +++ b/include/linux/fs_context.h @@ -186,10 +186,12 @@ struct fc_log { extern __attribute__((format(printf, 4, 5))) void logfc(struct fc_log *log, const char *prefix, char level, const char *fmt, ...); -#define __logfc(fc, l, fmt, ...) logfc((fc)->log.log, NULL, \ - l, fmt, ## __VA_ARGS__) -#define __plog(p, l, fmt, ...) logfc((p)->log, (p)->prefix, \ - l, fmt, ## __VA_ARGS__) +#define __logfc(fc, l, fmt, ...) \ + logfc((fc)->log.log, NULL, (l), (fmt), ## __VA_ARGS__) +#define __plogp(p, prefix, l, fmt, ...) \ + logfc((p)->log, (prefix), (l), (fmt), ## __VA_ARGS__) +#define __plog(p, l, fmt, ...) __plogp(p, (p)->prefix, l, fmt, ## __VA_ARGS__) + /** * infof - Store supplementary informational message * @fc: The context in which to log the informational message @@ -201,6 +203,8 @@ void logfc(struct fc_log *log, const char *prefix, char level, const char *fmt, #define infof(fc, fmt, ...) __logfc(fc, 'i', fmt, ## __VA_ARGS__) #define info_plog(p, fmt, ...) __plog(p, 'i', fmt, ## __VA_ARGS__) #define infofc(fc, fmt, ...) __plog((&(fc)->log), 'i', fmt, ## __VA_ARGS__) +#define infofcp(fc, prefix, fmt, ...) \ + __plogp((&(fc)->log), prefix, 'i', fmt, ## __VA_ARGS__) /** * warnf - Store supplementary warning message @@ -213,6 +217,8 @@ void logfc(struct fc_log *log, const char *prefix, char level, const char *fmt, #define warnf(fc, fmt, ...) __logfc(fc, 'w', fmt, ## __VA_ARGS__) #define warn_plog(p, fmt, ...) __plog(p, 'w', fmt, ## __VA_ARGS__) #define warnfc(fc, fmt, ...) __plog((&(fc)->log), 'w', fmt, ## __VA_ARGS__) +#define warnfcp(fc, prefix, fmt, ...) \ + __plogp((&(fc)->log), prefix, 'w', fmt, ## __VA_ARGS__) /** * errorf - Store supplementary error message @@ -225,6 +231,8 @@ void logfc(struct fc_log *log, const char *prefix, char level, const char *fmt, #define errorf(fc, fmt, ...) __logfc(fc, 'e', fmt, ## __VA_ARGS__) #define error_plog(p, fmt, ...) __plog(p, 'e', fmt, ## __VA_ARGS__) #define errorfc(fc, fmt, ...) __plog((&(fc)->log), 'e', fmt, ## __VA_ARGS__) +#define errorfcp(fc, prefix, fmt, ...) \ + __plogp((&(fc)->log), prefix, 'e', fmt, ## __VA_ARGS__) /** * invalf - Store supplementary invalid argument error message @@ -237,5 +245,7 @@ void logfc(struct fc_log *log, const char *prefix, char level, const char *fmt, #define invalf(fc, fmt, ...) (errorf(fc, fmt, ## __VA_ARGS__), -EINVAL) #define inval_plog(p, fmt, ...) (error_plog(p, fmt, ## __VA_ARGS__), -EINVAL) #define invalfc(fc, fmt, ...) (errorfc(fc, fmt, ## __VA_ARGS__), -EINVAL) +#define invalfcp(fc, prefix, fmt, ...) \ + (errorfcp(fc, prefix, fmt, ## __VA_ARGS__), -EINVAL) #endif /* _LINUX_FS_CONTEXT_H */ From 92becd1701a835d0807fa1f5c03b43762af27444 Mon Sep 17 00:00:00 2001 From: Pedro Falcato Date: Wed, 23 Jul 2025 14:21:56 +0100 Subject: [PATCH 00185/11391] docs/vfs: Remove mentions to the old mount API helpers Now that mount_bdev(), mount_nodev() and mount_single() have all been removed, remove mentions to them in vfs.rst. While we're at it, redirect people looking for mount API docs to mount_api.rst (which documents the newer API). Signed-off-by: Pedro Falcato Link: https://lore.kernel.org/20250723132156.225410-4-pfalcato@suse.de Signed-off-by: Christian Brauner --- Documentation/filesystems/vfs.rst | 27 ++------------------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/Documentation/filesystems/vfs.rst b/Documentation/filesystems/vfs.rst index 486a91633474..229eb90c96f2 100644 --- a/Documentation/filesystems/vfs.rst +++ b/Documentation/filesystems/vfs.rst @@ -209,31 +209,8 @@ method fills in is the "s_op" field. This is a pointer to a "struct super_operations" which describes the next level of the filesystem implementation. -Usually, a filesystem uses one of the generic mount() implementations -and provides a fill_super() callback instead. The generic variants are: - -``mount_bdev`` - mount a filesystem residing on a block device - -``mount_nodev`` - mount a filesystem that is not backed by a device - -``mount_single`` - mount a filesystem which shares the instance between all mounts - -A fill_super() callback implementation has the following arguments: - -``struct super_block *sb`` - the superblock structure. The callback must initialize this - properly. - -``void *data`` - arbitrary mount options, usually comes as an ASCII string (see - "Mount Options" section) - -``int silent`` - whether or not to be silent on error - +For more information on mounting (and the new mount API), see +Documentation/filesystems/mount_api.rst. The Superblock Object ===================== From 807602d8cfc8b63e2c645fbbc66c8e82479ee311 Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Wed, 6 Aug 2025 16:07:06 +1000 Subject: [PATCH 00186/11391] vfs: output mount_too_revealing() errors to fscontext It makes little sense for fsmount() to output the warning message when mount_too_revealing() is violated to kmsg. Instead, the warning should be output (with a "VFS" prefix) to the fscontext log. In addition, include the same log message for mount_too_revealing() when doing a regular mount for consistency. With the newest fsopen()-based mount(8) from util-linux, the error messages now look like # mount -t proc proc /tmp mount: /tmp: fsmount() failed: VFS: Mount too revealing. dmesg(1) may have more information after failed mount system call. which could finally result in mount_too_revealing() errors being easier for users to detect and understand. Signed-off-by: Aleksa Sarai Link: https://lore.kernel.org/20250806-errorfc-mount-too-revealing-v2-2-534b9b4d45bb@cyphar.com Signed-off-by: Christian Brauner --- fs/namespace.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/namespace.c b/fs/namespace.c index ddfd4457d338..86d12f88b688 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -3724,8 +3724,10 @@ static int do_new_mount_fc(struct fs_context *fc, struct path *mountpoint, int error; error = security_sb_kern_mount(sb); - if (!error && mount_too_revealing(sb, &mnt_flags)) + if (!error && mount_too_revealing(sb, &mnt_flags)) { + errorfcp(fc, "VFS", "Mount too revealing"); error = -EPERM; + } if (unlikely(error)) { fc_drop_locked(fc); @@ -4441,7 +4443,7 @@ SYSCALL_DEFINE3(fsmount, int, fs_fd, unsigned int, flags, ret = -EPERM; if (mount_too_revealing(fc->root->d_sb, &mnt_flags)) { - pr_warn("VFS: Mount too revealing\n"); + errorfcp(fc, "VFS", "Mount too revealing"); goto err_unlock; } From 72d271a7baa7062cb27e774ac37c5459c6d20e22 Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Thu, 7 Aug 2025 03:55:23 +1000 Subject: [PATCH 00187/11391] fscontext: do not consume log entries when returning -EMSGSIZE Userspace generally expects APIs that return -EMSGSIZE to allow for them to adjust their buffer size and retry the operation. However, the fscontext log would previously clear the message even in the -EMSGSIZE case. Given that it is very cheap for us to check whether the buffer is too small before we remove the message from the ring buffer, let's just do that instead. While we're at it, refactor some fscontext_read() into a separate helper to make the ring buffer logic a bit easier to read. Fixes: 007ec26cdc9f ("vfs: Implement logging through fs_context") Cc: David Howells Cc: stable@vger.kernel.org # v5.2+ Signed-off-by: Aleksa Sarai Link: https://lore.kernel.org/20250807-fscontext-log-cleanups-v3-1-8d91d6242dc3@cyphar.com Signed-off-by: Christian Brauner --- fs/fsopen.c | 70 +++++++++++++++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/fs/fsopen.c b/fs/fsopen.c index 1aaf4cb2afb2..f645c99204eb 100644 --- a/fs/fsopen.c +++ b/fs/fsopen.c @@ -18,50 +18,56 @@ #include "internal.h" #include "mount.h" +static inline const char *fetch_message_locked(struct fc_log *log, size_t len, + bool *need_free) +{ + const char *p; + int index; + + if (unlikely(log->head == log->tail)) + return ERR_PTR(-ENODATA); + + index = log->tail & (ARRAY_SIZE(log->buffer) - 1); + p = log->buffer[index]; + if (unlikely(strlen(p) > len)) + return ERR_PTR(-EMSGSIZE); + + log->buffer[index] = NULL; + *need_free = log->need_free & (1 << index); + log->need_free &= ~(1 << index); + log->tail++; + + return p; +} + /* * Allow the user to read back any error, warning or informational messages. + * Only one message is returned for each read(2) call. */ static ssize_t fscontext_read(struct file *file, char __user *_buf, size_t len, loff_t *pos) { struct fs_context *fc = file->private_data; - struct fc_log *log = fc->log.log; - unsigned int logsize = ARRAY_SIZE(log->buffer); - ssize_t ret; - char *p; + ssize_t err; + const char *p __free(kfree) = NULL, *message; bool need_free; - int index, n; + int n; - ret = mutex_lock_interruptible(&fc->uapi_mutex); - if (ret < 0) - return ret; - - if (log->head == log->tail) { - mutex_unlock(&fc->uapi_mutex); - return -ENODATA; - } - - index = log->tail & (logsize - 1); - p = log->buffer[index]; - need_free = log->need_free & (1 << index); - log->buffer[index] = NULL; - log->need_free &= ~(1 << index); - log->tail++; + err = mutex_lock_interruptible(&fc->uapi_mutex); + if (err < 0) + return err; + message = fetch_message_locked(fc->log.log, len, &need_free); mutex_unlock(&fc->uapi_mutex); + if (IS_ERR(message)) + return PTR_ERR(message); - ret = -EMSGSIZE; - n = strlen(p); - if (n > len) - goto err_free; - ret = -EFAULT; - if (copy_to_user(_buf, p, n) != 0) - goto err_free; - ret = n; - -err_free: if (need_free) - kfree(p); - return ret; + p = message; + + n = strlen(message); + if (copy_to_user(_buf, message, n)) + return -EFAULT; + return n; } static int fscontext_release(struct inode *inode, struct file *file) From df579e471111b9f8691d75c980f59cc085fa97a3 Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Thu, 7 Aug 2025 03:55:24 +1000 Subject: [PATCH 00188/11391] selftests/filesystems: add basic fscontext log tests Signed-off-by: Aleksa Sarai Link: https://lore.kernel.org/20250807-fscontext-log-cleanups-v3-2-8d91d6242dc3@cyphar.com Signed-off-by: Christian Brauner --- .../testing/selftests/filesystems/.gitignore | 1 + tools/testing/selftests/filesystems/Makefile | 2 +- tools/testing/selftests/filesystems/fclog.c | 130 ++++++++++++++++++ 3 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/filesystems/fclog.c diff --git a/tools/testing/selftests/filesystems/.gitignore b/tools/testing/selftests/filesystems/.gitignore index fcbdb1297e24..64ac0dfa46b7 100644 --- a/tools/testing/selftests/filesystems/.gitignore +++ b/tools/testing/selftests/filesystems/.gitignore @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only dnotify_test devpts_pts +fclog file_stressor anon_inode_test kernfs_test diff --git a/tools/testing/selftests/filesystems/Makefile b/tools/testing/selftests/filesystems/Makefile index 73d4650af1a5..85427d7f19b9 100644 --- a/tools/testing/selftests/filesystems/Makefile +++ b/tools/testing/selftests/filesystems/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 CFLAGS += $(KHDR_INCLUDES) -TEST_GEN_PROGS := devpts_pts file_stressor anon_inode_test kernfs_test +TEST_GEN_PROGS := devpts_pts file_stressor anon_inode_test kernfs_test fclog TEST_GEN_PROGS_EXTENDED := dnotify_test include ../lib.mk diff --git a/tools/testing/selftests/filesystems/fclog.c b/tools/testing/selftests/filesystems/fclog.c new file mode 100644 index 000000000000..912a8b755c3b --- /dev/null +++ b/tools/testing/selftests/filesystems/fclog.c @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Author: Aleksa Sarai + * Copyright (C) 2025 SUSE LLC. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../kselftest_harness.h" + +#define ASSERT_ERRNO(expected, _t, seen) \ + __EXPECT(expected, #expected, \ + ({__typeof__(seen) _tmp_seen = (seen); \ + _tmp_seen >= 0 ? _tmp_seen : -errno; }), #seen, _t, 1) + +#define ASSERT_ERRNO_EQ(expected, seen) \ + ASSERT_ERRNO(expected, ==, seen) + +#define ASSERT_SUCCESS(seen) \ + ASSERT_ERRNO(0, <=, seen) + +FIXTURE(ns) +{ + int host_mntns; +}; + +FIXTURE_SETUP(ns) +{ + /* Stash the old mntns. */ + self->host_mntns = open("/proc/self/ns/mnt", O_RDONLY|O_CLOEXEC); + ASSERT_SUCCESS(self->host_mntns); + + /* Create a new mount namespace and make it private. */ + ASSERT_SUCCESS(unshare(CLONE_NEWNS)); + ASSERT_SUCCESS(mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL)); +} + +FIXTURE_TEARDOWN(ns) +{ + ASSERT_SUCCESS(setns(self->host_mntns, CLONE_NEWNS)); + ASSERT_SUCCESS(close(self->host_mntns)); +} + +TEST_F(ns, fscontext_log_enodata) +{ + int fsfd = fsopen("tmpfs", FSOPEN_CLOEXEC); + ASSERT_SUCCESS(fsfd); + + /* A brand new fscontext has no log entries. */ + char buf[128] = {}; + for (int i = 0; i < 16; i++) + ASSERT_ERRNO_EQ(-ENODATA, read(fsfd, buf, sizeof(buf))); + + ASSERT_SUCCESS(close(fsfd)); +} + +TEST_F(ns, fscontext_log_errorfc) +{ + int fsfd = fsopen("tmpfs", FSOPEN_CLOEXEC); + ASSERT_SUCCESS(fsfd); + + ASSERT_ERRNO_EQ(-EINVAL, fsconfig(fsfd, FSCONFIG_SET_STRING, "invalid-arg", "123", 0)); + + char buf[128] = {}; + ASSERT_SUCCESS(read(fsfd, buf, sizeof(buf))); + EXPECT_STREQ("e tmpfs: Unknown parameter 'invalid-arg'\n", buf); + + /* The message has been consumed. */ + ASSERT_ERRNO_EQ(-ENODATA, read(fsfd, buf, sizeof(buf))); + ASSERT_SUCCESS(close(fsfd)); +} + +TEST_F(ns, fscontext_log_errorfc_after_fsmount) +{ + int fsfd = fsopen("tmpfs", FSOPEN_CLOEXEC); + ASSERT_SUCCESS(fsfd); + + ASSERT_ERRNO_EQ(-EINVAL, fsconfig(fsfd, FSCONFIG_SET_STRING, "invalid-arg", "123", 0)); + + ASSERT_SUCCESS(fsconfig(fsfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0)); + int mfd = fsmount(fsfd, FSMOUNT_CLOEXEC, MOUNT_ATTR_NOEXEC | MOUNT_ATTR_NOSUID); + ASSERT_SUCCESS(mfd); + ASSERT_SUCCESS(move_mount(mfd, "", AT_FDCWD, "/tmp", MOVE_MOUNT_F_EMPTY_PATH)); + + /* + * The fscontext log should still contain data even after + * FSCONFIG_CMD_CREATE and fsmount(). + */ + char buf[128] = {}; + ASSERT_SUCCESS(read(fsfd, buf, sizeof(buf))); + EXPECT_STREQ("e tmpfs: Unknown parameter 'invalid-arg'\n", buf); + + /* The message has been consumed. */ + ASSERT_ERRNO_EQ(-ENODATA, read(fsfd, buf, sizeof(buf))); + ASSERT_SUCCESS(close(fsfd)); +} + +TEST_F(ns, fscontext_log_emsgsize) +{ + int fsfd = fsopen("tmpfs", FSOPEN_CLOEXEC); + ASSERT_SUCCESS(fsfd); + + ASSERT_ERRNO_EQ(-EINVAL, fsconfig(fsfd, FSCONFIG_SET_STRING, "invalid-arg", "123", 0)); + + char buf[128] = {}; + /* + * Attempting to read a message with too small a buffer should not + * result in the message getting consumed. + */ + ASSERT_ERRNO_EQ(-EMSGSIZE, read(fsfd, buf, 0)); + ASSERT_ERRNO_EQ(-EMSGSIZE, read(fsfd, buf, 1)); + for (int i = 0; i < 16; i++) + ASSERT_ERRNO_EQ(-EMSGSIZE, read(fsfd, buf, 16)); + + ASSERT_SUCCESS(read(fsfd, buf, sizeof(buf))); + EXPECT_STREQ("e tmpfs: Unknown parameter 'invalid-arg'\n", buf); + + /* The message has been consumed. */ + ASSERT_ERRNO_EQ(-ENODATA, read(fsfd, buf, sizeof(buf))); + ASSERT_SUCCESS(close(fsfd)); +} + +TEST_HARNESS_MAIN From d140f3ba76ac98faad7f9b37ef5a3dcbd57f59e2 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Thu, 7 Aug 2025 09:34:09 +0200 Subject: [PATCH 00189/11391] memory: stm32_omm: Fix req2ack update test If "st,omm-req2ack-ns" property is found and its value is not 0, the current test doesn't allow to compute and set req2ack value, Fix this test. Fixes: 8181d061dcff ("memory: Add STM32 Octo Memory Manager driver") Signed-off-by: Patrice Chotard Link: https://lore.kernel.org/r/20250807-upstream_omm_fix_req2ack_test_condition-v2-1-d7df4af2b48b@foss.st.com Cc: Signed-off-by: Krzysztof Kozlowski --- drivers/memory/stm32_omm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/memory/stm32_omm.c b/drivers/memory/stm32_omm.c index bee2ecc8c2b9..5d06623f3f68 100644 --- a/drivers/memory/stm32_omm.c +++ b/drivers/memory/stm32_omm.c @@ -238,7 +238,7 @@ static int stm32_omm_configure(struct device *dev) if (mux & CR_MUXEN) { ret = of_property_read_u32(dev->of_node, "st,omm-req2ack-ns", &req2ack); - if (!ret && !req2ack) { + if (!ret && req2ack) { req2ack = DIV_ROUND_UP(req2ack, NSEC_PER_SEC / clk_rate_max) - 1; if (req2ack > 256) From 6ec4b94e8e959b4201ca0bfc43fa50dc946d10cb Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 11 Aug 2025 15:00:01 +0200 Subject: [PATCH 00190/11391] gpio: TODO: remove the task for converting to the new line setters The task is complete, but this was not reflected in the TODO file. Fixes: d9d87d90cc0b10cd ("treewide: rename GPIO set callbacks back to their original names") Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/417af7e5a110c527eb759289bd5d2fd6885f4e01.1754917104.git.geert+renesas@glider.be Signed-off-by: Bartosz Golaszewski --- drivers/gpio/TODO | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/gpio/TODO b/drivers/gpio/TODO index 7a09a4f58551..b797499e627e 100644 --- a/drivers/gpio/TODO +++ b/drivers/gpio/TODO @@ -176,18 +176,6 @@ cannot be converted yet, but watch this space! ------------------------------------------------------------------------------- -Convert all GPIO chips to using the new, value returning line setters - -struct gpio_chip's set() and set_multiple() callbacks are now deprecated. They -return void and thus do not allow drivers to indicate failure to set the line -value back to the caller. - -We've now added new variants - set_rv() and set_multiple_rv() that return an -integer. Let's convert all GPIO drivers treewide to use the new callbacks, -remove the old ones and finally rename the new ones back to the old names. - -------------------------------------------------------------------------------- - Remove legacy sysfs features We have two parallel per-chip class devices and per-exported-line attribute From c6871d56b52ec177b8b8bd891fa0cbbd004b646d Mon Sep 17 00:00:00 2001 From: Chen Ni Date: Tue, 29 Jul 2025 12:00:44 +0800 Subject: [PATCH 00191/11391] regulator: tps6594-regulator: 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://patch.msgid.link/20250729040044.1851988-1-nichen@iscas.ac.cn Signed-off-by: Mark Brown --- drivers/regulator/tps6594-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/tps6594-regulator.c b/drivers/regulator/tps6594-regulator.c index ab882daec7c5..645e83462c64 100644 --- a/drivers/regulator/tps6594-regulator.c +++ b/drivers/regulator/tps6594-regulator.c @@ -647,7 +647,7 @@ static int tps6594_regulator_probe(struct platform_device *pdev) default: dev_err(tps->dev, "unknown chip_id %lu\n", tps->chip_id); return -EINVAL; - }; + } enum { MULTI_BUCK12, From c072d2b49507420edd57ba3d87690ab81ef5273a Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Fri, 25 Jul 2025 15:06:26 -0500 Subject: [PATCH 00192/11391] scripts/dtc: Update to upstream version v1.7.2-35-g52f07dcca47c This adds the following commits from upstream: 52f07dcca47c dtc: Add informative error for stray identifier 9cabae6b0351 checks: Fix detection of 'i2c-bus' node 605dc044c3fe New helper to add markers 7da5d106c740 fdtput: Fix documentation about existing nodes 53c63dd421d7 dtdiff: Use input format dtb for dtbo files 84d9dd2fcbc8 dtc: Add data_insert_data function 97011d1f4e98 meson: use override_find_program/override_dependency b841391bbd08 srcpos: Define srcpos_free e0b7749c26a9 Add alloc_marker ecb21febfdd3 meson: port python bindings to build natively via meson and meson-python 7ebfcac8520e Makefile: deprecate in favor of Meson f4c53f4ebf78 Use __ASSEMBLER__ instead of __ASSEMBLY__ 205fbef17b7b Fix some typos da85f91931e5 Remove duplicated words in documentation and comments dd1b3e532d22 meson: support building libfdt without static library 1ccd232709d4 meson: don't build test programs by default ce1d8588880a tests: When building .so from -O asm output mark as non-executable stack 915daadbb62d Start with empty __local_fixups__ and __fixups__ nodes 4ea851f5a44d Let get_subnode() not return deleted nodes 175d2a564c47 Use build_root_node() instead of open-coding it 18f4f305fdd7 build: fix -Dtools=false build 267efc7d4694 checks: Warn about missing #address-cells for interrupt parents 755db115355b libfdt: Add fdt_setprop_namelen_string() bdca8612009e libfdt: Add fdt_setprop_namelen() 0f69cedc08fc libfdt_internal: fdt_find_string_len_() 56b2b30c5bd0 libfdt: add fdt_get_property_namelen_w() 1e8c5f60e127 Add clang-format config 6f183c7d9246 checks: Relax avoid_unnecessary_addr_size check to allow child ranges properties 66c7d0e6f4f3 tests/sw_tree1.c: fix unitialized saveptr 9a969f3b70b0 pylibfdt/libfdt.i: fix backwards compatibility of return values 4292b072a23a .github/workflows: update ubuntu runner to supported version 1c745a9bd169 libfdt: Remove fdt parameter from overlay_fixup_one_phandle b3bbee6b1242 libfdt: Move the SBOM authors section d1656730abfb Add a SBOM file in CycloneDX format b75515af4576 libfdt: Remove extra semi-colons outside functions 2d10aa2afe35 Bump version to v1.7.2 48795c82bdb6 pylibfdt: Don't emit warnings from swig generate C code 838f11e830e3 fdtoverlay: provide better error message for missing `/__symbols__` d1e2384185c5 pylibfdt/libfdt.i: Use SWIG_AppendOutput 18aa49a9f68d Escape spaces in depfile with backslashes. f9968fa06921 libfdt.h: whitespace consistency fixups 9b5f65fb3d8d libfdt.h: typo and consistency fixes 99031e3a4a6e Bump version to v1.7.1 3d5e376925fd setup: Move setting of srcdir down to the bottom e277553b9880 setup: Collect top-level code together 7e5a88984081 setup: Move version and full_description into a function 78b6a85c113b Tidy up some pylint warnings 3501d373f0a2 Require Python 3 The added include of string.h in libfdt_internal.h breaks the kernel overriding libfdt_env.h with its own string functions, so it is dropped. An upstream fix is pending. Signed-off-by: Rob Herring (Arm) --- scripts/Makefile.dtbs | 1 + scripts/dtc/checks.c | 23 ++-- scripts/dtc/data.c | 47 ++++++- scripts/dtc/dtc-lexer.l | 15 +++ scripts/dtc/dtc.c | 6 +- scripts/dtc/dtc.h | 5 +- scripts/dtc/fdtoverlay.c | 8 ++ scripts/dtc/flattree.c | 2 +- scripts/dtc/libfdt/fdt.c | 8 +- scripts/dtc/libfdt/fdt.h | 4 +- scripts/dtc/libfdt/fdt_overlay.c | 8 +- scripts/dtc/libfdt/fdt_rw.c | 41 +++--- scripts/dtc/libfdt/libfdt.h | 181 +++++++++++++++++++++------ scripts/dtc/libfdt/libfdt_internal.h | 14 ++- scripts/dtc/livetree.c | 25 ++-- scripts/dtc/srcpos.c | 17 ++- scripts/dtc/srcpos.h | 1 + scripts/dtc/treesource.c | 52 +++++--- scripts/dtc/util.c | 16 +++ scripts/dtc/util.h | 5 + scripts/dtc/version_gen.h | 2 +- 21 files changed, 373 insertions(+), 108 deletions(-) diff --git a/scripts/Makefile.dtbs b/scripts/Makefile.dtbs index 8d56c0815f33..2d321b813600 100644 --- a/scripts/Makefile.dtbs +++ b/scripts/Makefile.dtbs @@ -97,6 +97,7 @@ DTC_FLAGS += -Wno-unit_address_vs_reg \ -Wno-avoid_unnecessary_addr_size \ -Wno-alias_paths \ -Wno-graph_child_address \ + -Wno-interrupt_map \ -Wno-simple_bus_reg else DTC_FLAGS += -Wunique_unit_address_if_enabled diff --git a/scripts/dtc/checks.c b/scripts/dtc/checks.c index 6e06aeab5503..7e3fed5005b3 100644 --- a/scripts/dtc/checks.c +++ b/scripts/dtc/checks.c @@ -1024,7 +1024,7 @@ static void check_i2c_bus_bridge(struct check *c, struct dt_info *dti, struct no } else if (strprefixeq(node->name, node->basenamelen, "i2c")) { struct node *child; for_each_child(node, child) { - if (strprefixeq(child->name, node->basenamelen, "i2c-bus")) + if (strprefixeq(child->name, child->basenamelen, "i2c-bus")) return; } node->bus = &i2c_bus; @@ -1217,9 +1217,7 @@ WARNING(avoid_default_addr_size, check_avoid_default_addr_size, NULL, static void check_avoid_unnecessary_addr_size(struct check *c, struct dt_info *dti, struct node *node) { - struct property *prop; struct node *child; - bool has_reg = false; if (!node->parent || node->addr_cells < 0 || node->size_cells < 0) return; @@ -1228,13 +1226,18 @@ static void check_avoid_unnecessary_addr_size(struct check *c, struct dt_info *d return; for_each_child(node, child) { - prop = get_property(child, "reg"); - if (prop) - has_reg = true; + /* + * Even if the child devices' address space is not mapped into + * the parent bus (no 'ranges' property on node), children can + * still have registers on a local bus, or map local addresses + * to another subordinate address space. The properties on the + * child nodes then make #address-cells/#size-cells necessary: + */ + if (get_property(child, "reg") || get_property(child, "ranges")) + return; } - if (!has_reg) - FAIL(c, dti, node, "unnecessary #address-cells/#size-cells without \"ranges\", \"dma-ranges\" or child \"reg\" property"); + FAIL(c, dti, node, "unnecessary #address-cells/#size-cells without \"ranges\", \"dma-ranges\" or child \"reg\" or \"ranges\" property"); } WARNING(avoid_unnecessary_addr_size, check_avoid_unnecessary_addr_size, NULL, &avoid_default_addr_size); @@ -1673,6 +1676,10 @@ static void check_interrupt_map(struct check *c, cellprop = get_property(provider_node, "#address-cells"); if (cellprop) parent_cellsize += propval_cell(cellprop); + else + FAIL_PROP(c, dti, node, irq_map_prop, + "Missing property '#address-cells' in node %s, using 0 as fallback", + provider_node->fullpath); cell += 1 + parent_cellsize; if (cell > map_cells) diff --git a/scripts/dtc/data.c b/scripts/dtc/data.c index 14734233ad8b..5b25aa060416 100644 --- a/scripts/dtc/data.c +++ b/scripts/dtc/data.c @@ -228,11 +228,7 @@ struct data data_add_marker(struct data d, enum markertype type, char *ref) { struct marker *m; - m = xmalloc(sizeof(*m)); - m->offset = d.len; - m->type = type; - m->ref = ref; - m->next = NULL; + m = alloc_marker(d.len, type, ref); return data_append_markers(d, m); } @@ -254,3 +250,44 @@ bool data_is_one_string(struct data d) return true; } + +struct data data_insert_data(struct data d, struct marker *m, struct data old) +{ + unsigned int offset = m->offset; + struct marker *next = m->next; + struct marker *marker; + struct data new_data; + char *ref; + + new_data = data_insert_at_marker(d, m, old.val, old.len); + + /* Copy all markers from old value */ + marker = old.markers; + for_each_marker(marker) { + ref = NULL; + + if (marker->ref) + ref = xstrdup(marker->ref); + + m->next = alloc_marker(marker->offset + offset, marker->type, + ref); + m = m->next; + } + m->next = next; + + return new_data; +} + +struct marker *alloc_marker(unsigned int offset, enum markertype type, + char *ref) +{ + struct marker *m; + + m = xmalloc(sizeof(*m)); + m->offset = offset; + m->type = type; + m->ref = ref; + m->next = NULL; + + return m; +} diff --git a/scripts/dtc/dtc-lexer.l b/scripts/dtc/dtc-lexer.l index de60a70b6bdb..15d585c80798 100644 --- a/scripts/dtc/dtc-lexer.l +++ b/scripts/dtc/dtc-lexer.l @@ -151,6 +151,21 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...); return DT_LABEL; } +{LABEL} { + /* Missed includes or macro definitions while + * preprocessing can lead to unexpected identifiers in + * the input. Report a slightly more informative error + * in this case */ + + lexical_error("Unexpected '%s'", yytext); + + /* Treat it as a literal which often generates further + * useful error messages */ + + yylval.integer = 0; + return DT_LITERAL; + } + ([0-9]+|0[xX][0-9a-fA-F]+)(U|L|UL|LL|ULL)? { char *e; DPRINT("Integer Literal: '%s'\n", yytext); diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c index 0655c2e2c362..b3445b7d6473 100644 --- a/scripts/dtc/dtc.c +++ b/scripts/dtc/dtc.c @@ -15,7 +15,7 @@ int quiet; /* Level of quietness */ unsigned int reservenum;/* Number of memory reservation slots */ int minsize; /* Minimum blob size */ int padsize; /* Additional padding to blob */ -int alignsize; /* Additional padding to blob accroding to the alignsize */ +int alignsize; /* Additional padding to blob according to the alignsize */ int phandle_format = PHANDLE_EPAPR; /* Use linux,phandle or phandle properties */ int generate_symbols; /* enable symbols & fixup support */ int generate_fixups; /* suppress generation of fixups on symbol support */ @@ -289,7 +289,9 @@ int main(int argc, char *argv[]) if (!depfile) die("Couldn't open dependency file %s: %s\n", depname, strerror(errno)); - fprintf(depfile, "%s:", outname); + + fprint_path_escaped(depfile, outname); + fputc(':', depfile); } if (inform == NULL) diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h index 4c4aaca1fc41..3a220b9afc99 100644 --- a/scripts/dtc/dtc.h +++ b/scripts/dtc/dtc.h @@ -38,7 +38,7 @@ extern int quiet; /* Level of quietness */ extern unsigned int reservenum; /* Number of memory reservation slots */ extern int minsize; /* Minimum blob size */ extern int padsize; /* Additional padding to blob */ -extern int alignsize; /* Additional padding to blob accroding to the alignsize */ +extern int alignsize; /* Additional padding to blob according to the alignsize */ extern int phandle_format; /* Use linux,phandle or phandle properties */ extern int generate_symbols; /* generate symbols for nodes with labels */ extern int generate_fixups; /* generate fixups */ @@ -182,7 +182,10 @@ struct data data_append_addr(struct data d, uint64_t addr); struct data data_append_byte(struct data d, uint8_t byte); struct data data_append_zeroes(struct data d, int len); struct data data_append_align(struct data d, int align); +struct data data_insert_data(struct data d, struct marker *m, struct data old); +struct marker *alloc_marker(unsigned int offset, enum markertype type, + char *ref); struct data data_add_marker(struct data d, enum markertype type, char *ref); bool data_is_one_string(struct data d); diff --git a/scripts/dtc/fdtoverlay.c b/scripts/dtc/fdtoverlay.c index 699b4f616502..ee1eb8f3ad28 100644 --- a/scripts/dtc/fdtoverlay.c +++ b/scripts/dtc/fdtoverlay.c @@ -46,6 +46,7 @@ static void *apply_one(char *base, const char *overlay, size_t *buf_len, char *tmp = NULL; char *tmpo; int ret; + bool has_symbols; /* * We take copies first, because a failed apply can trash @@ -62,6 +63,8 @@ static void *apply_one(char *base, const char *overlay, size_t *buf_len, fdt_strerror(ret)); goto fail; } + ret = fdt_path_offset(tmp, "/__symbols__"); + has_symbols = ret >= 0; memcpy(tmpo, overlay, fdt_totalsize(overlay)); @@ -74,6 +77,11 @@ static void *apply_one(char *base, const char *overlay, size_t *buf_len, if (ret) { fprintf(stderr, "\nFailed to apply '%s': %s\n", name, fdt_strerror(ret)); + if (!has_symbols) { + fprintf(stderr, + "base blob does not have a '/__symbols__' node, " + "make sure you have compiled the base blob with '-@' option\n"); + } goto fail; } diff --git a/scripts/dtc/flattree.c b/scripts/dtc/flattree.c index 1bcd8089c5b9..30e6de2044b2 100644 --- a/scripts/dtc/flattree.c +++ b/scripts/dtc/flattree.c @@ -503,7 +503,7 @@ void dt_to_asm(FILE *f, struct dt_info *dti, int version) * Reserve map entries. * Align the reserve map to a doubleword boundary. * Each entry is an (address, size) pair of u64 values. - * Always supply a zero-sized temination entry. + * Always supply a zero-sized termination entry. */ asm_emit_align(f, 8); emit_label(f, symprefix, "reserve_map"); diff --git a/scripts/dtc/libfdt/fdt.c b/scripts/dtc/libfdt/fdt.c index 20c6415b9ced..95f644c31f94 100644 --- a/scripts/dtc/libfdt/fdt.c +++ b/scripts/dtc/libfdt/fdt.c @@ -312,14 +312,14 @@ int fdt_next_subnode(const void *fdt, int offset) return offset; } -const char *fdt_find_string_(const char *strtab, int tabsize, const char *s) +const char *fdt_find_string_len_(const char *strtab, int tabsize, const char *s, + int slen) { - int len = strlen(s) + 1; - const char *last = strtab + tabsize - len; + const char *last = strtab + tabsize - (slen + 1); const char *p; for (p = strtab; p <= last; p++) - if (memcmp(p, s, len) == 0) + if (memcmp(p, s, slen) == 0 && p[slen] == '\0') return p; return NULL; } diff --git a/scripts/dtc/libfdt/fdt.h b/scripts/dtc/libfdt/fdt.h index 0c91aa7f67b5..a07abfcc7108 100644 --- a/scripts/dtc/libfdt/fdt.h +++ b/scripts/dtc/libfdt/fdt.h @@ -7,7 +7,7 @@ * Copyright 2012 Kim Phillips, Freescale Semiconductor. */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ struct fdt_header { fdt32_t magic; /* magic word FDT_MAGIC */ @@ -45,7 +45,7 @@ struct fdt_property { char data[]; }; -#endif /* !__ASSEMBLY */ +#endif /* !__ASSEMBLER__ */ #define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */ #define FDT_TAGSIZE sizeof(fdt32_t) diff --git a/scripts/dtc/libfdt/fdt_overlay.c b/scripts/dtc/libfdt/fdt_overlay.c index 28b667ffc490..e6b9eb643958 100644 --- a/scripts/dtc/libfdt/fdt_overlay.c +++ b/scripts/dtc/libfdt/fdt_overlay.c @@ -307,7 +307,6 @@ static int overlay_update_local_references(void *fdto, uint32_t delta) /** * overlay_fixup_one_phandle - Set an overlay phandle to the base one - * @fdt: Base Device Tree blob * @fdto: Device tree overlay blob * @symbols_off: Node offset of the symbols node in the base device tree * @path: Path to a node holding a phandle in the overlay @@ -328,8 +327,7 @@ static int overlay_update_local_references(void *fdto, uint32_t delta) * 0 on success * Negative error code on failure */ -static int overlay_fixup_one_phandle(void *fdt, void *fdto, - int symbols_off, +static int overlay_fixup_one_phandle(void *fdto, int symbols_off, const char *path, uint32_t path_len, const char *name, uint32_t name_len, int poffset, uint32_t phandle) @@ -351,7 +349,7 @@ static int overlay_fixup_one_phandle(void *fdt, void *fdto, name, name_len, poffset, &phandle_prop, sizeof(phandle_prop)); -}; +} /** * overlay_fixup_phandle - Set an overlay phandle to the base one @@ -443,7 +441,7 @@ static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off, if ((*endptr != '\0') || (endptr <= (sep + 1))) return -FDT_ERR_BADOVERLAY; - ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off, + ret = overlay_fixup_one_phandle(fdto, symbols_off, path, path_len, name, name_len, poffset, phandle); if (ret) diff --git a/scripts/dtc/libfdt/fdt_rw.c b/scripts/dtc/libfdt/fdt_rw.c index 3621d3651d3f..7475cafce071 100644 --- a/scripts/dtc/libfdt/fdt_rw.c +++ b/scripts/dtc/libfdt/fdt_rw.c @@ -124,31 +124,33 @@ static int fdt_splice_string_(void *fdt, int newlen) * allocated. Ignored if can_assume(NO_ROLLBACK) * @return offset of string in the string table (whether found or added) */ -static int fdt_find_add_string_(void *fdt, const char *s, int *allocated) +static int fdt_find_add_string_(void *fdt, const char *s, int slen, + int *allocated) { char *strtab = (char *)fdt + fdt_off_dt_strings(fdt); const char *p; char *new; - int len = strlen(s) + 1; int err; if (!can_assume(NO_ROLLBACK)) *allocated = 0; - p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s); + p = fdt_find_string_len_(strtab, fdt_size_dt_strings(fdt), s, slen); if (p) /* found it */ return (p - strtab); new = strtab + fdt_size_dt_strings(fdt); - err = fdt_splice_string_(fdt, len); + err = fdt_splice_string_(fdt, slen + 1); if (err) return err; if (!can_assume(NO_ROLLBACK)) *allocated = 1; - memcpy(new, s, len); + memcpy(new, s, slen); + new[slen] = '\0'; + return (new - strtab); } @@ -181,13 +183,15 @@ int fdt_del_mem_rsv(void *fdt, int n) return fdt_splice_mem_rsv_(fdt, re, 1, 0); } -static int fdt_resize_property_(void *fdt, int nodeoffset, const char *name, +static int fdt_resize_property_(void *fdt, int nodeoffset, + const char *name, int namelen, int len, struct fdt_property **prop) { int oldlen; int err; - *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); + *prop = fdt_get_property_namelen_w(fdt, nodeoffset, name, namelen, + &oldlen); if (!*prop) return oldlen; @@ -200,7 +204,7 @@ static int fdt_resize_property_(void *fdt, int nodeoffset, const char *name, } static int fdt_add_property_(void *fdt, int nodeoffset, const char *name, - int len, struct fdt_property **prop) + int namelen, int len, struct fdt_property **prop) { int proplen; int nextoffset; @@ -211,7 +215,7 @@ static int fdt_add_property_(void *fdt, int nodeoffset, const char *name, if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0) return nextoffset; - namestroff = fdt_find_add_string_(fdt, name, &allocated); + namestroff = fdt_find_add_string_(fdt, name, namelen, &allocated); if (namestroff < 0) return namestroff; @@ -255,17 +259,18 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name) return 0; } -int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name, - int len, void **prop_data) +int fdt_setprop_placeholder_namelen(void *fdt, int nodeoffset, const char *name, + int namelen, int len, void **prop_data) { struct fdt_property *prop; int err; FDT_RW_PROBE(fdt); - err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop); + err = fdt_resize_property_(fdt, nodeoffset, name, namelen, len, &prop); if (err == -FDT_ERR_NOTFOUND) - err = fdt_add_property_(fdt, nodeoffset, name, len, &prop); + err = fdt_add_property_(fdt, nodeoffset, name, namelen, len, + &prop); if (err) return err; @@ -273,13 +278,14 @@ int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name, return 0; } -int fdt_setprop(void *fdt, int nodeoffset, const char *name, - const void *val, int len) +int fdt_setprop_namelen(void *fdt, int nodeoffset, const char *name, + int namelen, const void *val, int len) { void *prop_data; int err; - err = fdt_setprop_placeholder(fdt, nodeoffset, name, len, &prop_data); + err = fdt_setprop_placeholder_namelen(fdt, nodeoffset, name, namelen, + len, &prop_data); if (err) return err; @@ -307,7 +313,8 @@ int fdt_appendprop(void *fdt, int nodeoffset, const char *name, prop->len = cpu_to_fdt32(newlen); memcpy(prop->data + oldlen, val, len); } else { - err = fdt_add_property_(fdt, nodeoffset, name, len, &prop); + err = fdt_add_property_(fdt, nodeoffset, name, strlen(name), + len, &prop); if (err) return err; memcpy(prop->data, val, len); diff --git a/scripts/dtc/libfdt/libfdt.h b/scripts/dtc/libfdt/libfdt.h index 2d409d8e829b..914bf90785ab 100644 --- a/scripts/dtc/libfdt/libfdt.h +++ b/scripts/dtc/libfdt/libfdt.h @@ -14,7 +14,7 @@ extern "C" { #endif #define FDT_FIRST_SUPPORTED_VERSION 0x02 -#define FDT_LAST_COMPATIBLE_VERSION 0x10 +#define FDT_LAST_COMPATIBLE_VERSION 0x10 #define FDT_LAST_SUPPORTED_VERSION 0x11 /* Error codes: informative error codes */ @@ -263,16 +263,16 @@ int fdt_next_subnode(const void *fdt, int offset); struct fdt_header *fdth = (struct fdt_header *)fdt; \ fdth->name = cpu_to_fdt32(val); \ } -fdt_set_hdr_(magic); -fdt_set_hdr_(totalsize); -fdt_set_hdr_(off_dt_struct); -fdt_set_hdr_(off_dt_strings); -fdt_set_hdr_(off_mem_rsvmap); -fdt_set_hdr_(version); -fdt_set_hdr_(last_comp_version); -fdt_set_hdr_(boot_cpuid_phys); -fdt_set_hdr_(size_dt_strings); -fdt_set_hdr_(size_dt_struct); +fdt_set_hdr_(magic) +fdt_set_hdr_(totalsize) +fdt_set_hdr_(off_dt_struct) +fdt_set_hdr_(off_dt_strings) +fdt_set_hdr_(off_mem_rsvmap) +fdt_set_hdr_(version) +fdt_set_hdr_(last_comp_version) +fdt_set_hdr_(boot_cpuid_phys) +fdt_set_hdr_(size_dt_strings) +fdt_set_hdr_(size_dt_struct) #undef fdt_set_hdr_ /** @@ -285,7 +285,7 @@ size_t fdt_header_size(const void *fdt); /** * fdt_header_size_ - internal function to get header size from a version number - * @version: devicetree version number + * @version: device tree version number * * Return: size of DTB header in bytes */ @@ -554,7 +554,7 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen); * -FDT_ERR_BADPATH, given path does not begin with '/' and the first * component is not a valid alias * -FDT_ERR_NOTFOUND, if the requested node does not exist - * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, @@ -599,7 +599,7 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp); * structure block offset of the property (>=0), on success * -FDT_ERR_NOTFOUND, if the requested node has no properties * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, @@ -620,7 +620,7 @@ int fdt_first_property_offset(const void *fdt, int nodeoffset); * structure block offset of the next property (>=0), on success * -FDT_ERR_NOTFOUND, if the given property is the last in its node * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_PROP tag - * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, @@ -712,6 +712,13 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt, int nodeoffset, const char *name, int namelen, int *lenp); +static inline struct fdt_property * +fdt_get_property_namelen_w(void *fdt, int nodeoffset, const char *name, + int namelen, int *lenp) +{ + return (struct fdt_property *)(uintptr_t)fdt_get_property_namelen( + fdt, nodeoffset, name, namelen, lenp); +} #endif /** @@ -764,7 +771,7 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, * to within the device blob itself, not a copy of the value). If * lenp is non-NULL, the length of the property value is also * returned, in the integer pointed to by lenp. If namep is non-NULL, - * the property's namne will also be returned in the char * pointed to + * the property's name will also be returned in the char * pointed to * by namep (this will be a pointer to within the device tree's string * block, not a new copy of the name). * @@ -772,7 +779,7 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, * pointer to the property's value * if lenp is non-NULL, *lenp contains the length of the property * value (>=0) - * if namep is non-NULL *namep contiains a pointer to the property + * if namep is non-NULL *namep contains a pointer to the property * name. * NULL, on error * if lenp is non-NULL, *lenp contains an error code (<0): @@ -866,7 +873,7 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset); /** * fdt_get_alias_namelen - get alias based on substring * @fdt: pointer to the device tree blob - * @name: name of the alias th look up + * @name: name of the alias to look up * @namelen: number of characters of name to consider * * Identical to fdt_get_alias(), but only examine the first @namelen @@ -883,7 +890,7 @@ const char *fdt_get_alias_namelen(const void *fdt, /** * fdt_get_alias - retrieve the path referenced by a given alias * @fdt: pointer to the device tree blob - * @name: name of the alias th look up + * @name: name of the alias to look up * * fdt_get_alias() retrieves the value of a given alias. That is, the * value of the property named @name in the node /aliases. @@ -1259,8 +1266,8 @@ const char *fdt_stringlist_get(const void *fdt, int nodeoffset, * * returns: * 0 <= n < FDT_MAX_NCELLS, on success - * 2, if the node has no #address-cells property - * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid + * 2, if the node has no #address-cells property + * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid * #address-cells property * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, @@ -1280,8 +1287,8 @@ int fdt_address_cells(const void *fdt, int nodeoffset); * * returns: * 0 <= n < FDT_MAX_NCELLS, on success - * 1, if the node has no #size-cells property - * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid + * 1, if the node has no #size-cells property + * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid * #size-cells property * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, @@ -1562,7 +1569,7 @@ static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) * @fdt: pointer to the device tree blob * @name: name of property to add * @len: length of property value in bytes - * @valp: returns a pointer to where where the value should be placed + * @valp: returns a pointer to where the value should be placed * * returns: * 0, on success @@ -1659,6 +1666,38 @@ int fdt_del_mem_rsv(void *fdt, int n); */ int fdt_set_name(void *fdt, int nodeoffset, const char *name); +/** + * fdt_setprop_namelen - create or change a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @namelen: length of the name + * @val: pointer to data to set the property value to + * @len: length of the property value + * + * fdt_setprop_namelen() sets the value of the named property in the given + * node to the given value and length, creating the property if it + * does not already exist. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_setprop_namelen(void *fdt, int nodeoffset, const char *name, + int namelen, const void *val, int len); + /** * fdt_setprop - create or change a property * @fdt: pointer to the device tree blob @@ -1687,18 +1726,23 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name); * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ -int fdt_setprop(void *fdt, int nodeoffset, const char *name, - const void *val, int len); +static inline int fdt_setprop(void *fdt, int nodeoffset, const char *name, + const void *val, int len) +{ + return fdt_setprop_namelen(fdt, nodeoffset, name, strlen(name), val, + len); +} /** - * fdt_setprop_placeholder - allocate space for a property + * fdt_setprop_placeholder_namelen - allocate space for a property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change + * @namelen: length of the name * @len: length of the property value * @prop_data: return pointer to property data * - * fdt_setprop_placeholer() allocates the named property in the given node. + * fdt_setprop_placeholder_namelen() allocates the named property in the given node. * If the property exists it is resized. In either case a pointer to the * property data is returned. * @@ -1718,8 +1762,44 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ -int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name, - int len, void **prop_data); +int fdt_setprop_placeholder_namelen(void *fdt, int nodeoffset, const char *name, + int namelen, int len, void **prop_data); + +/** + * fdt_setprop_placeholder - allocate space for a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @len: length of the property value + * @prop_data: return pointer to property data + * + * fdt_setprop_placeholder() allocates the named property in the given node. + * If the property exists it is resized. In either case a pointer to the + * property data is returned. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_setprop_placeholder(void *fdt, int nodeoffset, + const char *name, int len, + void **prop_data) +{ + return fdt_setprop_placeholder_namelen(fdt, nodeoffset, name, + strlen(name), len, prop_data); +} /** * fdt_setprop_u32 - set a property to a 32-bit integer @@ -1839,6 +1919,38 @@ static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, #define fdt_setprop_string(fdt, nodeoffset, name, str) \ fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) +/** + * fdt_setprop_namelen_string - set a property to a string value + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @namelen: number of characters of name to consider + * @str: string value for the property + * + * fdt_setprop_namelen_string() sets the value of the named property in the + * given node to the given string value (using the length of the + * string to determine the new length of the property), or creates a + * new property with that value if it does not already exist. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +#define fdt_setprop_namelen_string(fdt, nodeoffset, name, namelen, str) \ + fdt_setprop_namelen((fdt), (nodeoffset), (name), (namelen), (str), \ + strlen(str) + 1) /** * fdt_setprop_empty - set a property to an empty value @@ -2059,7 +2171,7 @@ int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset, * @nodeoffset: offset of the node whose property to nop * @name: name of the property to nop * - * fdt_del_property() will delete the given property. + * fdt_delprop() will delete the given property. * * This function will delete data from the blob, and will therefore * change the offsets of some existing nodes. @@ -2111,8 +2223,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, * change the offsets of some existing nodes. * * returns: - * structure block offset of the created nodeequested subnode (>=0), on - * success + * structure block offset of the created subnode (>=0), on success * -FDT_ERR_NOTFOUND, if the requested subnode does not exist * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE * tag @@ -2122,7 +2233,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, * blob to contain the new node * -FDT_ERR_NOSPACE * -FDT_ERR_BADLAYOUT - * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, @@ -2167,7 +2278,7 @@ int fdt_del_node(void *fdt, int nodeoffset); * returns: * 0, on success * -FDT_ERR_NOSPACE, there's not enough space in the base device tree - * -FDT_ERR_NOTFOUND, the overlay points to some inexistant nodes or + * -FDT_ERR_NOTFOUND, the overlay points to some nonexistent nodes or * properties in the base DT * -FDT_ERR_BADPHANDLE, * -FDT_ERR_BADOVERLAY, diff --git a/scripts/dtc/libfdt/libfdt_internal.h b/scripts/dtc/libfdt/libfdt_internal.h index 16bda1906a7b..b60b5456f596 100644 --- a/scripts/dtc/libfdt/libfdt_internal.h +++ b/scripts/dtc/libfdt/libfdt_internal.h @@ -20,7 +20,15 @@ int32_t fdt_ro_probe_(const void *fdt); int fdt_check_node_offset_(const void *fdt, int offset); int fdt_check_prop_offset_(const void *fdt, int offset); -const char *fdt_find_string_(const char *strtab, int tabsize, const char *s); + +const char *fdt_find_string_len_(const char *strtab, int tabsize, const char *s, + int s_len); +static inline const char *fdt_find_string_(const char *strtab, int tabsize, + const char *s) +{ + return fdt_find_string_len_(strtab, tabsize, s, strlen(s)); +} + int fdt_node_end_offset_(void *fdt, int nodeoffset); static inline const void *fdt_offset_ptr_(const void *fdt, int offset) @@ -47,8 +55,8 @@ static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n) } /* - * Internal helpers to access tructural elements of the device tree - * blob (rather than for exaple reading integers from within property + * Internal helpers to access structural elements of the device tree + * blob (rather than for example reading integers from within property * values). We assume that we are either given a naturally aligned * address for the platform or if we are not, we are on a platform * where unaligned memory reads will be handled in a graceful manner. diff --git a/scripts/dtc/livetree.c b/scripts/dtc/livetree.c index 49f723002f85..d51d05830b18 100644 --- a/scripts/dtc/livetree.c +++ b/scripts/dtc/livetree.c @@ -174,7 +174,7 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node) old_prop->val = new_prop->val; old_prop->deleted = 0; - free(old_prop->srcpos); + srcpos_free(old_prop->srcpos); old_prop->srcpos = new_prop->srcpos; free(new_prop); new_prop = NULL; @@ -504,7 +504,7 @@ struct node *get_subnode(struct node *node, const char *nodename) struct node *child; for_each_child(node, child) - if (streq(child->name, nodename)) + if (streq(child->name, nodename) && !child->deleted) return child; return NULL; @@ -1014,9 +1014,7 @@ static void add_local_fixup_entry(struct dt_info *dti, /* walk the path components creating nodes if they don't exist */ for (wn = lfn, i = 1; i < depth; i++, wn = nwn) { /* if no node exists, create it */ - nwn = get_subnode(wn, compp[i]); - if (!nwn) - nwn = build_and_name_child_node(wn, compp[i]); + nwn = build_root_node(wn, compp[i]); } free(compp); @@ -1058,16 +1056,29 @@ void generate_label_tree(struct dt_info *dti, const char *name, bool allocph) void generate_fixups_tree(struct dt_info *dti, const char *name) { + struct node *n = get_subnode(dti->dt, name); + + /* Start with an empty __fixups__ node to not get duplicates */ + if (n) + n->deleted = true; + if (!any_fixup_tree(dti, dti->dt)) return; - generate_fixups_tree_internal(dti, build_root_node(dti->dt, name), + generate_fixups_tree_internal(dti, + build_and_name_child_node(dti->dt, name), dti->dt); } void generate_local_fixups_tree(struct dt_info *dti, const char *name) { + struct node *n = get_subnode(dti->dt, name); + + /* Start with an empty __local_fixups__ node to not get duplicates */ + if (n) + n->deleted = true; if (!any_local_fixup_tree(dti, dti->dt)) return; - generate_local_fixups_tree_internal(dti, build_root_node(dti->dt, name), + generate_local_fixups_tree_internal(dti, + build_and_name_child_node(dti->dt, name), dti->dt); } diff --git a/scripts/dtc/srcpos.c b/scripts/dtc/srcpos.c index 8e4d18a90b47..5bb57bf6856c 100644 --- a/scripts/dtc/srcpos.c +++ b/scripts/dtc/srcpos.c @@ -160,8 +160,10 @@ FILE *srcfile_relative_open(const char *fname, char **fullnamep) strerror(errno)); } - if (depfile) - fprintf(depfile, " %s", fullname); + if (depfile) { + fputc(' ', depfile); + fprint_path_escaped(depfile, fullname); + } if (fullnamep) *fullnamep = fullname; @@ -285,6 +287,17 @@ struct srcpos *srcpos_extend(struct srcpos *pos, struct srcpos *newtail) return pos; } +void srcpos_free(struct srcpos *pos) +{ + struct srcpos *p_next; + + while (pos) { + p_next = pos->next; + free(pos); + pos = p_next; + } +} + char * srcpos_string(struct srcpos *pos) { diff --git a/scripts/dtc/srcpos.h b/scripts/dtc/srcpos.h index 4318d7ad34d9..4d60b50e3119 100644 --- a/scripts/dtc/srcpos.h +++ b/scripts/dtc/srcpos.h @@ -88,6 +88,7 @@ extern void srcpos_update(struct srcpos *pos, const char *text, int len); extern struct srcpos *srcpos_copy(struct srcpos *pos); extern struct srcpos *srcpos_extend(struct srcpos *new_srcpos, struct srcpos *old_srcpos); +extern void srcpos_free(struct srcpos *pos); extern char *srcpos_string(struct srcpos *pos); extern char *srcpos_string_first(struct srcpos *pos, int level); extern char *srcpos_string_last(struct srcpos *pos, int level); diff --git a/scripts/dtc/treesource.c b/scripts/dtc/treesource.c index ae15839ba6a5..d25f01fc6937 100644 --- a/scripts/dtc/treesource.c +++ b/scripts/dtc/treesource.c @@ -139,26 +139,48 @@ static const char *delim_end[] = { [TYPE_STRING] = "", }; +/* + * The invariants in the marker list are: + * - offsets are non-strictly monotonically increasing + * - for a single offset there is at most one type marker + * - for a single offset that has both a type marker and non-type markers, the + * type marker appears before the others. + */ +static struct marker **add_marker(struct marker **mi, + enum markertype type, unsigned int offset, char *ref) +{ + struct marker *nm; + + while (*mi && (*mi)->offset < offset) + mi = &(*mi)->next; + + if (*mi && (*mi)->offset == offset && is_type_marker((*mi)->type)) { + if (is_type_marker(type)) + return mi; + mi = &(*mi)->next; + } + + if (*mi && (*mi)->offset == offset && type == (*mi)->type) + return mi; + + nm = xmalloc(sizeof(*nm)); + nm->type = type; + nm->offset = offset; + nm->ref = ref; + nm->next = *mi; + *mi = nm; + + return &nm->next; +} + static void add_string_markers(struct property *prop) { int l, len = prop->val.len; const char *p = prop->val.val; + struct marker **mi = &prop->val.markers; - for (l = strlen(p) + 1; l < len; l += strlen(p + l) + 1) { - struct marker *m, **nextp; - - m = xmalloc(sizeof(*m)); - m->offset = l; - m->type = TYPE_STRING; - m->ref = NULL; - m->next = NULL; - - /* Find the end of the markerlist */ - nextp = &prop->val.markers; - while (*nextp) - nextp = &((*nextp)->next); - *nextp = m; - } + for (l = strlen(p) + 1; l < len; l += strlen(p + l) + 1) + mi = add_marker(mi, TYPE_STRING, l, NULL); } static enum markertype guess_value_type(struct property *prop) diff --git a/scripts/dtc/util.c b/scripts/dtc/util.c index 507f0120cd13..412592320265 100644 --- a/scripts/dtc/util.c +++ b/scripts/dtc/util.c @@ -23,6 +23,22 @@ #include "util.h" #include "version_gen.h" +void fprint_path_escaped(FILE *fp, const char *path) +{ + const char *p = path; + + while (*p) { + if (*p == ' ') { + fputc('\\', fp); + fputc(' ', fp); + } else { + fputc(*p, fp); + } + + p++; + } +} + char *xstrdup(const char *s) { int len = strlen(s) + 1; diff --git a/scripts/dtc/util.h b/scripts/dtc/util.h index b448cd79efd3..800f2e2c55b1 100644 --- a/scripts/dtc/util.h +++ b/scripts/dtc/util.h @@ -42,6 +42,11 @@ static inline void NORETURN PRINTF(1, 2) die(const char *str, ...) exit(1); } +/** + * Writes path to fp, escaping spaces with a backslash. + */ +void fprint_path_escaped(FILE *fp, const char *path); + static inline void *xmalloc(size_t len) { void *new = malloc(len); diff --git a/scripts/dtc/version_gen.h b/scripts/dtc/version_gen.h index bf81ce593685..226c48bf75dc 100644 --- a/scripts/dtc/version_gen.h +++ b/scripts/dtc/version_gen.h @@ -1 +1 @@ -#define DTC_VERSION "DTC 1.7.0-gbcd02b52" +#define DTC_VERSION "DTC 1.7.2-g52f07dcc" From f6cc4140e161831e5796f099f5abc3af953ae2b8 Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Thu, 7 Aug 2025 20:39:49 +0800 Subject: [PATCH 00193/11391] regulator: tps6524x: Remove unnecessary memset devm_kzalloc() has already been initialized to full 0 space, there is no need to use memset() to initialize again. Signed-off-by: Liao Yuanhong Link: https://patch.msgid.link/20250807123949.495193-1-liaoyuanhong@vivo.com Signed-off-by: Mark Brown --- drivers/regulator/tps6524x-regulator.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c index 3fee7e38c68b..6beb51293e8e 100644 --- a/drivers/regulator/tps6524x-regulator.c +++ b/drivers/regulator/tps6524x-regulator.c @@ -598,7 +598,6 @@ static int pmic_probe(struct spi_device *spi) spi_set_drvdata(spi, hw); - memset(hw, 0, sizeof(struct tps6524x)); hw->dev = dev; hw->spi = spi; mutex_init(&hw->lock); From bb2441402392ef1f49563be68e8f0dcb127ac965 Mon Sep 17 00:00:00 2001 From: Dzmitry Sankouski Date: Tue, 5 Aug 2025 22:40:56 +0300 Subject: [PATCH 00194/11391] regulator: add s2dos05 regulator support S2DOS05 has 1 buck and 4 LDO regulators, used for powering panel/touchscreen. Signed-off-by: Dzmitry Sankouski Link: https://patch.msgid.link/20250805-starqltechn_integration_upstream-v8-1-09d8a321fafe@gmail.com Signed-off-by: Mark Brown --- MAINTAINERS | 2 +- drivers/regulator/Kconfig | 8 ++ drivers/regulator/Makefile | 1 + drivers/regulator/s2dos05-regulator.c | 165 ++++++++++++++++++++++++++ include/linux/regulator/s2dos05.h | 73 ++++++++++++ 5 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 drivers/regulator/s2dos05-regulator.c create mode 100644 include/linux/regulator/s2dos05.h diff --git a/MAINTAINERS b/MAINTAINERS index fe168477caa4..f35f9b503956 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22387,7 +22387,7 @@ F: Documentation/devicetree/bindings/regulator/samsung,s2m*.yaml F: Documentation/devicetree/bindings/regulator/samsung,s5m*.yaml F: drivers/clk/clk-s2mps11.c F: drivers/mfd/sec*.[ch] -F: drivers/regulator/s2m*.c +F: drivers/regulator/s2*.c F: drivers/regulator/s5m*.c F: drivers/rtc/rtc-s5m.c F: include/linux/mfd/samsung/ diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index eaa6df1c9f80..2399c8a9a1c5 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -1344,6 +1344,14 @@ config REGULATOR_RTQ2208 and two ldos. It features wide output voltage range from 0.4V to 2.05V and the capability to configure the corresponding power stages. +config REGULATOR_S2DOS05 + tristate "Samsung S2DOS05 voltage regulator" + depends on MFD_SEC_CORE || COMPILE_TEST + help + This driver provides support for the voltage regulators of the S2DOS05. + The S2DOS05 is a companion power management IC for the smart phones. + The S2DOS05 has 4 LDOs and 1 BUCK outputs. + config REGULATOR_S2MPA01 tristate "Samsung S2MPA01 voltage regulator" depends on MFD_SEC_CORE || COMPILE_TEST diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index be98b29d6675..78605b0fa0b2 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -156,6 +156,7 @@ obj-$(CONFIG_REGULATOR_RTMV20) += rtmv20-regulator.o obj-$(CONFIG_REGULATOR_RTQ2134) += rtq2134-regulator.o obj-$(CONFIG_REGULATOR_RTQ6752) += rtq6752-regulator.o obj-$(CONFIG_REGULATOR_RTQ2208) += rtq2208-regulator.o +obj-$(CONFIG_REGULATOR_S2DOS05) += s2dos05-regulator.o obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o diff --git a/drivers/regulator/s2dos05-regulator.c b/drivers/regulator/s2dos05-regulator.c new file mode 100644 index 000000000000..1463585c4565 --- /dev/null +++ b/drivers/regulator/s2dos05-regulator.c @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// s2dos05.c - Regulator driver for the Samsung s2dos05 +// +// Copyright (C) 2025 Dzmitry Sankouski + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct s2dos05_data { + struct regmap *regmap; + struct device *dev; +}; + +#define _BUCK(macro) S2DOS05_BUCK##macro +#define _buck_ops(num) s2dos05_ops##num +#define _LDO(macro) S2DOS05_LDO##macro +#define _REG(ctrl) S2DOS05_REG##ctrl +#define _ldo_ops(num) s2dos05_ops##num +#define _MASK(macro) S2DOS05_ENABLE_MASK##macro +#define _TIME(macro) S2DOS05_ENABLE_TIME##macro + +#define BUCK_DESC(_name, _id, _ops, m, s, v, e, em, t, a) { \ + .name = _name, \ + .id = _id, \ + .ops = _ops, \ + .of_match = of_match_ptr(_name), \ + .of_match_full_name = true, \ + .regulators_node = of_match_ptr("regulators"), \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = m, \ + .uV_step = s, \ + .n_voltages = S2DOS05_BUCK_N_VOLTAGES, \ + .vsel_reg = v, \ + .vsel_mask = S2DOS05_BUCK_VSEL_MASK, \ + .enable_reg = e, \ + .enable_mask = em, \ + .enable_time = t, \ + .active_discharge_off = 0, \ + .active_discharge_on = S2DOS05_BUCK_FD_MASK, \ + .active_discharge_reg = a, \ + .active_discharge_mask = S2DOS05_BUCK_FD_MASK \ +} + +#define LDO_DESC(_name, _id, _ops, m, s, v, e, em, t, a) { \ + .name = _name, \ + .id = _id, \ + .ops = _ops, \ + .of_match = of_match_ptr(_name), \ + .of_match_full_name = true, \ + .regulators_node = of_match_ptr("regulators"), \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = m, \ + .uV_step = s, \ + .n_voltages = S2DOS05_LDO_N_VOLTAGES, \ + .vsel_reg = v, \ + .vsel_mask = S2DOS05_LDO_VSEL_MASK, \ + .enable_reg = e, \ + .enable_mask = em, \ + .enable_time = t, \ + .active_discharge_off = 0, \ + .active_discharge_on = S2DOS05_LDO_FD_MASK, \ + .active_discharge_reg = a, \ + .active_discharge_mask = S2DOS05_LDO_FD_MASK \ +} + +static const struct regulator_ops s2dos05_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_active_discharge = regulator_set_active_discharge_regmap, +}; + +static const struct regulator_desc regulators[S2DOS05_REGULATOR_MAX] = { + // name, id, ops, min_uv, uV_step, vsel_reg, enable_reg + LDO_DESC("ldo1", _LDO(1), &_ldo_ops(), _LDO(_MIN1), + _LDO(_STEP1), _REG(_LDO1_CFG), + _REG(_EN), _MASK(_L1), _TIME(_LDO), _REG(_LDO1_CFG)), + LDO_DESC("ldo2", _LDO(2), &_ldo_ops(), _LDO(_MIN1), + _LDO(_STEP1), _REG(_LDO2_CFG), + _REG(_EN), _MASK(_L2), _TIME(_LDO), _REG(_LDO2_CFG)), + LDO_DESC("ldo3", _LDO(3), &_ldo_ops(), _LDO(_MIN2), + _LDO(_STEP1), _REG(_LDO3_CFG), + _REG(_EN), _MASK(_L3), _TIME(_LDO), _REG(_LDO3_CFG)), + LDO_DESC("ldo4", _LDO(4), &_ldo_ops(), _LDO(_MIN2), + _LDO(_STEP1), _REG(_LDO4_CFG), + _REG(_EN), _MASK(_L4), _TIME(_LDO), _REG(_LDO4_CFG)), + BUCK_DESC("buck", _BUCK(1), &_buck_ops(), _BUCK(_MIN1), + _BUCK(_STEP1), _REG(_BUCK_VOUT), + _REG(_EN), _MASK(_B1), _TIME(_BUCK), _REG(_BUCK_CFG)), +}; + +static int s2dos05_pmic_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); + struct s2dos05_data *s2dos05; + struct regulator_config config = { }; + unsigned int rdev_num = ARRAY_SIZE(regulators); + + s2dos05 = devm_kzalloc(dev, sizeof(*s2dos05), GFP_KERNEL); + if (!s2dos05) + return -ENOMEM; + + platform_set_drvdata(pdev, s2dos05); + + s2dos05->regmap = iodev->regmap_pmic; + s2dos05->dev = dev; + if (!dev->of_node) + dev->of_node = dev->parent->of_node; + + config.dev = dev; + config.driver_data = s2dos05; + + for (int i = 0; i < rdev_num; i++) { + struct regulator_dev *regulator; + + regulator = devm_regulator_register(&pdev->dev, + ®ulators[i], &config); + if (IS_ERR(regulator)) { + return dev_err_probe(&pdev->dev, PTR_ERR(regulator), + "regulator init failed for %d\n", i); + } + } + + return 0; +} + +static const struct platform_device_id s2dos05_pmic_id[] = { + { "s2dos05-regulator" }, + { }, +}; +MODULE_DEVICE_TABLE(platform, s2dos05_pmic_id); + +static struct platform_driver s2dos05_platform_driver = { + .driver = { + .name = "s2dos05", + }, + .probe = s2dos05_pmic_probe, + .id_table = s2dos05_pmic_id, +}; +module_platform_driver(s2dos05_platform_driver); + +MODULE_AUTHOR("Dzmitry Sankouski "); +MODULE_DESCRIPTION("Samsung S2DOS05 Regulator Driver"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/regulator/s2dos05.h b/include/linux/regulator/s2dos05.h new file mode 100644 index 000000000000..2e89fcbce769 --- /dev/null +++ b/include/linux/regulator/s2dos05.h @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +// s2dos05.h +// +// Copyright (c) 2016 Samsung Electronics Co., Ltd +// http://www.samsung.com +// Copyright (C) 2024 Dzmitry Sankouski + +#ifndef __LINUX_S2DOS05_H +#define __LINUX_S2DOS05_H + +// S2DOS05 registers +// Slave Addr : 0xC0 +enum S2DOS05_reg { + S2DOS05_REG_DEV_ID, + S2DOS05_REG_TOPSYS_STAT, + S2DOS05_REG_STAT, + S2DOS05_REG_EN, + S2DOS05_REG_LDO1_CFG, + S2DOS05_REG_LDO2_CFG, + S2DOS05_REG_LDO3_CFG, + S2DOS05_REG_LDO4_CFG, + S2DOS05_REG_BUCK_CFG, + S2DOS05_REG_BUCK_VOUT, + S2DOS05_REG_IRQ_MASK = 0x0D, + S2DOS05_REG_SSD_TSD = 0x0E, + S2DOS05_REG_OCL = 0x10, + S2DOS05_REG_IRQ = 0x11 +}; + +// S2DOS05 regulator ids +enum S2DOS05_regulators { + S2DOS05_LDO1, + S2DOS05_LDO2, + S2DOS05_LDO3, + S2DOS05_LDO4, + S2DOS05_BUCK1, + S2DOS05_REG_MAX, +}; + +#define S2DOS05_IRQ_PWRMT_MASK BIT(5) +#define S2DOS05_IRQ_TSD_MASK BIT(4) +#define S2DOS05_IRQ_SSD_MASK BIT(3) +#define S2DOS05_IRQ_SCP_MASK BIT(2) +#define S2DOS05_IRQ_UVLO_MASK BIT(1) +#define S2DOS05_IRQ_OCD_MASK BIT(0) + +#define S2DOS05_BUCK_MIN1 506250 +#define S2DOS05_LDO_MIN1 1500000 +#define S2DOS05_LDO_MIN2 2700000 +#define S2DOS05_BUCK_STEP1 6250 +#define S2DOS05_LDO_STEP1 25000 +#define S2DOS05_LDO_VSEL_MASK 0x7F +#define S2DOS05_LDO_FD_MASK 0x80 +#define S2DOS05_BUCK_VSEL_MASK 0xFF +#define S2DOS05_BUCK_FD_MASK 0x08 + +#define S2DOS05_ENABLE_MASK_L1 BIT(0) +#define S2DOS05_ENABLE_MASK_L2 BIT(1) +#define S2DOS05_ENABLE_MASK_L3 BIT(2) +#define S2DOS05_ENABLE_MASK_L4 BIT(3) +#define S2DOS05_ENABLE_MASK_B1 BIT(4) + +#define S2DOS05_RAMP_DELAY 12000 + +#define S2DOS05_ENABLE_TIME_LDO 50 +#define S2DOS05_ENABLE_TIME_BUCK 350 + +#define S2DOS05_LDO_N_VOLTAGES (S2DOS05_LDO_VSEL_MASK + 1) +#define S2DOS05_BUCK_N_VOLTAGES (S2DOS05_BUCK_VSEL_MASK + 1) + +#define S2DOS05_REGULATOR_MAX (S2DOS05_REG_MAX) + +#endif // __LINUX_S2DOS05_H From a54ef14188519a0994d0264f701f5771815fa11e Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Thu, 7 Aug 2025 16:44:57 -0500 Subject: [PATCH 00195/11391] regulator: dt-bindings: Clean-up active-semi,act8945a duplication The active-semi,act8945a binding is documented in multiple places. The charger child node is documented in regulator/active-semi,act8945a.yaml and power/supply/active-semi,act8945a-charger.yaml. An old text binding is in mfd/act8945a.txt. Update the regulator/active-semi,act8945a.yaml with the additional descriptions and constraints from power/supply/active-semi,act8945a-charger.yaml, and then remove it and mfd/act8945a.txt. Signed-off-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250807214459.4173892-1-robh@kernel.org Signed-off-by: Mark Brown --- .../devicetree/bindings/mfd/act8945a.txt | 82 ------------------- .../supply/active-semi,act8945a-charger.yaml | 76 ----------------- .../regulator/active-semi,act8945a.yaml | 25 ++++-- 3 files changed, 19 insertions(+), 164 deletions(-) delete mode 100644 Documentation/devicetree/bindings/mfd/act8945a.txt delete mode 100644 Documentation/devicetree/bindings/power/supply/active-semi,act8945a-charger.yaml diff --git a/Documentation/devicetree/bindings/mfd/act8945a.txt b/Documentation/devicetree/bindings/mfd/act8945a.txt deleted file mode 100644 index 5ca75d888b4a..000000000000 --- a/Documentation/devicetree/bindings/mfd/act8945a.txt +++ /dev/null @@ -1,82 +0,0 @@ -Device-Tree bindings for Active-semi ACT8945A MFD driver - -Required properties: - - compatible: "active-semi,act8945a". - - reg: the I2C slave address for the ACT8945A chip - -The chip exposes two subdevices: - - a regulators: see ../regulator/act8945a-regulator.txt - - a charger: see ../power/act8945a-charger.txt - -Example: - pmic@5b { - compatible = "active-semi,act8945a"; - reg = <0x5b>; - - active-semi,vsel-high; - - regulators { - vdd_1v35_reg: REG_DCDC1 { - regulator-name = "VDD_1V35"; - regulator-min-microvolt = <1350000>; - regulator-max-microvolt = <1350000>; - regulator-always-on; - }; - - vdd_1v2_reg: REG_DCDC2 { - regulator-name = "VDD_1V2"; - regulator-min-microvolt = <1100000>; - regulator-max-microvolt = <1300000>; - regulator-always-on; - }; - - vdd_3v3_reg: REG_DCDC3 { - regulator-name = "VDD_3V3"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - }; - - vdd_fuse_reg: REG_LDO1 { - regulator-name = "VDD_FUSE"; - regulator-min-microvolt = <2500000>; - regulator-max-microvolt = <2500000>; - regulator-always-on; - }; - - vdd_3v3_lp_reg: REG_LDO2 { - regulator-name = "VDD_3V3_LP"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - }; - - vdd_led_reg: REG_LDO3 { - regulator-name = "VDD_LED"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - }; - - vdd_sdhc_1v8_reg: REG_LDO4 { - regulator-name = "VDD_SDHC_1V8"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-always-on; - }; - }; - - charger { - compatible = "active-semi,act8945a-charger"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_charger_chglev &pinctrl_charger_lbo &pinctrl_charger_irq>; - interrupt-parent = <&pioA>; - interrupts = <45 IRQ_TYPE_LEVEL_LOW>; - - active-semi,chglev-gpios = <&pioA 12 GPIO_ACTIVE_HIGH>; - active-semi,lbo-gpios = <&pioA 72 GPIO_ACTIVE_LOW>; - active-semi,input-voltage-threshold-microvolt = <6600>; - active-semi,precondition-timeout = <40>; - active-semi,total-timeout = <3>; - }; - }; diff --git a/Documentation/devicetree/bindings/power/supply/active-semi,act8945a-charger.yaml b/Documentation/devicetree/bindings/power/supply/active-semi,act8945a-charger.yaml deleted file mode 100644 index 5220d9cb16d8..000000000000 --- a/Documentation/devicetree/bindings/power/supply/active-semi,act8945a-charger.yaml +++ /dev/null @@ -1,76 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/power/supply/active-semi,act8945a-charger.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Active-semi ACT8945A Charger Function - -maintainers: - - Sebastian Reichel - -allOf: - - $ref: power-supply.yaml# - -properties: - compatible: - const: active-semi,act8945a-charger - - interrupts: - maxItems: 1 - - active-semi,chglev-gpios: - maxItems: 1 - description: charge current level GPIO - - active-semi,lbo-gpios: - maxItems: 1 - description: low battery voltage detect GPIO - - active-semi,input-voltage-threshold-microvolt: - description: | - Specifies the charger's input over-voltage threshold value. - Despite the name, specified values are in millivolt (mV). - Defaults to 6.6 V - enum: [ 6600, 7000, 7500, 8000 ] - - active-semi,precondition-timeout: - $ref: /schemas/types.yaml#/definitions/uint32 - description: | - Specifies the charger's PRECONDITION safety timer setting value in minutes. - If 0, it means to disable this timer. - Defaults to 40 minutes. - enum: [ 0, 40, 60, 80 ] - - active-semi,total-timeout: - $ref: /schemas/types.yaml#/definitions/uint32 - description: | - Specifies the charger's total safety timer setting value in hours; - If 0, it means to disable this timer; - Defaults to 3 hours. - enum: [ 0, 3, 4, 5 ] - -required: - - compatible - - interrupts - - active-semi,chglev-gpios - - active-semi,lbo-gpios - -additionalProperties: false - -examples: - - | - #include - #include - pmic { - charger { - compatible = "active-semi,act8945a-charger"; - interrupt-parent = <&pioA>; - interrupts = <45 IRQ_TYPE_LEVEL_LOW>; - active-semi,chglev-gpios = <&pioA 12 GPIO_ACTIVE_HIGH>; - active-semi,lbo-gpios = <&pioA 72 GPIO_ACTIVE_LOW>; - active-semi,input-voltage-threshold-microvolt = <6600>; - active-semi,precondition-timeout = <40>; - active-semi,total-timeout = <3>; - }; - }; diff --git a/Documentation/devicetree/bindings/regulator/active-semi,act8945a.yaml b/Documentation/devicetree/bindings/regulator/active-semi,act8945a.yaml index bdf3f7d34ef5..a8d579844dc7 100644 --- a/Documentation/devicetree/bindings/regulator/active-semi,act8945a.yaml +++ b/Documentation/devicetree/bindings/regulator/active-semi,act8945a.yaml @@ -91,28 +91,41 @@ properties: maxItems: 1 active-semi,chglev-gpios: - description: CGHLEV GPIO + description: charge current level GPIO maxItems: 1 active-semi,lbo-gpios: - description: LBO GPIO + description: low battery voltage detect GPIO maxItems: 1 active-semi,input-voltage-threshold-microvolt: - description: Input voltage threshold - maxItems: 1 + description: + Specifies the charger's input over-voltage threshold value. Despite + the name, specified values are in millivolt (mV). + enum: [ 6600, 7000, 7500, 8000 ] + default: 6600 active-semi,precondition-timeout: - description: Precondition timeout + description: + Specifies the charger's PRECONDITION safety timer setting value in + minutes. If 0, it means to disable this timer. + enum: [ 0, 40, 60, 80 ] + default: 40 $ref: /schemas/types.yaml#/definitions/uint32 active-semi,total-timeout: - description: Total timeout + description: + Specifies the charger's total safety timer setting value in hours; If + 0, it means to disable this timer; + enum: [ 0, 3, 4, 5 ] + default: 3 $ref: /schemas/types.yaml#/definitions/uint32 required: - compatible - interrupts + - active-semi,chglev-gpios + - active-semi,lbo-gpios additionalProperties: false From da8dd0a9378ebfec9fbc813a963203ad0cb94ce2 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Thu, 31 Jul 2025 17:12:21 -0500 Subject: [PATCH 00196/11391] MAINTAINERS: Add FSI bindings to FSI subsystem entry Maintainers of a subsystem should also be the maintainer for corresponding DT bindings. Add the FSI bindings to the FSI subsystem entry. Acked-by: Eddie James Link: https://lore.kernel.org/r/20250731-dt-fsi-cleanups-v1-4-e7b695a29fc3@kernel.org Signed-off-by: Rob Herring (Arm) --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index fe168477caa4..c2cf508e6379 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9962,6 +9962,7 @@ R: Ninad Palsule L: linux-fsi@lists.ozlabs.org S: Supported Q: http://patchwork.ozlabs.org/project/linux-fsi/list/ +F: Documentation/devicetree/bindings/fsi/ F: drivers/fsi/ F: include/linux/fsi*.h F: include/trace/events/fsi*.h From 17c66b1037aa52277d42c942db76672a1298858e Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Thu, 31 Jul 2025 17:12:22 -0500 Subject: [PATCH 00197/11391] dt-bindings: fsi: Convert fsi-master-gpio to DT schema Convert the GPIO-based FSI master binding to DT schema format. Drop the "fsi-master" compatible as it has not be used consistently and doesn't represent anything. Acked-by: Eddie James Link: https://lore.kernel.org/r/20250731-dt-fsi-cleanups-v1-5-e7b695a29fc3@kernel.org Signed-off-by: Rob Herring (Arm) --- .../bindings/fsi/fsi-master-gpio.txt | 28 --------- .../bindings/fsi/fsi-master-gpio.yaml | 63 +++++++++++++++++++ 2 files changed, 63 insertions(+), 28 deletions(-) delete mode 100644 Documentation/devicetree/bindings/fsi/fsi-master-gpio.txt create mode 100644 Documentation/devicetree/bindings/fsi/fsi-master-gpio.yaml diff --git a/Documentation/devicetree/bindings/fsi/fsi-master-gpio.txt b/Documentation/devicetree/bindings/fsi/fsi-master-gpio.txt deleted file mode 100644 index 1e442450747f..000000000000 --- a/Documentation/devicetree/bindings/fsi/fsi-master-gpio.txt +++ /dev/null @@ -1,28 +0,0 @@ -Device-tree bindings for gpio-based FSI master driver ------------------------------------------------------ - -Required properties: - - compatible = "fsi-master-gpio"; - - clock-gpios = ; : GPIO for FSI clock - - data-gpios = ; : GPIO for FSI data signal - -Optional properties: - - enable-gpios = ; : GPIO for enable signal - - trans-gpios = ; : GPIO for voltage translator enable - - mux-gpios = ; : GPIO for pin multiplexing with other - functions (eg, external FSI masters) - - no-gpio-delays; : Don't add extra delays between GPIO - accesses. This is useful when the HW - GPIO block is running at a low enough - frequency. - -Examples: - - fsi-master { - compatible = "fsi-master-gpio", "fsi-master"; - clock-gpios = <&gpio 0>; - data-gpios = <&gpio 1>; - enable-gpios = <&gpio 2>; - trans-gpios = <&gpio 3>; - mux-gpios = <&gpio 4>; - } diff --git a/Documentation/devicetree/bindings/fsi/fsi-master-gpio.yaml b/Documentation/devicetree/bindings/fsi/fsi-master-gpio.yaml new file mode 100644 index 000000000000..21bfbad595b3 --- /dev/null +++ b/Documentation/devicetree/bindings/fsi/fsi-master-gpio.yaml @@ -0,0 +1,63 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/fsi/fsi-master-gpio.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: fsi-master-gpio + +maintainers: + - Eddie James + +allOf: + - $ref: /schemas/fsi/fsi-controller.yaml + +properties: + compatible: + items: + - const: fsi-master-gpio + + clock-gpios: + description: GPIO for FSI clock + maxItems: 1 + + data-gpios: + description: GPIO for FSI data signal + maxItems: 1 + + enable-gpios: + description: GPIO for enable signal + maxItems: 1 + + trans-gpios: + description: GPIO for voltage translator enable + maxItems: 1 + + mux-gpios: + description: GPIO for pin multiplexing with other functions (eg, external + FSI masters) + maxItems: 1 + + no-gpio-delays: + description: + Don't add extra delays between GPIO accesses. This is useful when the HW + GPIO block is running at a low enough frequency. + type: boolean + +required: + - compatible + - clock-gpios + - data-gpios + +unevaluatedProperties: false + +examples: + - | + fsi-master { + compatible = "fsi-master-gpio"; + clock-gpios = <&gpio 0>; + data-gpios = <&gpio 1>; + enable-gpios = <&gpio 2>; + trans-gpios = <&gpio 3>; + mux-gpios = <&gpio 4>; + }; From a678ec17f57c97e9bdcb81f67f9af73ae72b3422 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Thu, 31 Jul 2025 17:12:23 -0500 Subject: [PATCH 00198/11391] dt-bindings: fsi: Convert aspeed,ast2400-cf-fsi-master to DT schema Convert the ASpeed Coldfire offloaded GPIO FSI master. Drop the "fsi-master" compatible as it has not be used consistently and doesn't represent anything. Acked-by: Eddie James Link: https://lore.kernel.org/r/20250731-dt-fsi-cleanups-v1-6-e7b695a29fc3@kernel.org Signed-off-by: Rob Herring (Arm) --- .../fsi/aspeed,ast2400-cf-fsi-master.yaml | 81 +++++++++++++++++++ .../bindings/fsi/fsi-master-ast-cf.txt | 36 --------- 2 files changed, 81 insertions(+), 36 deletions(-) create mode 100644 Documentation/devicetree/bindings/fsi/aspeed,ast2400-cf-fsi-master.yaml delete mode 100644 Documentation/devicetree/bindings/fsi/fsi-master-ast-cf.txt diff --git a/Documentation/devicetree/bindings/fsi/aspeed,ast2400-cf-fsi-master.yaml b/Documentation/devicetree/bindings/fsi/aspeed,ast2400-cf-fsi-master.yaml new file mode 100644 index 000000000000..690b6c936f18 --- /dev/null +++ b/Documentation/devicetree/bindings/fsi/aspeed,ast2400-cf-fsi-master.yaml @@ -0,0 +1,81 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/fsi/aspeed,ast2400-cf-fsi-master.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ASpeed ColdFire offloaded GPIO-based FSI master + +maintainers: + - Eddie James + +allOf: + - $ref: /schemas/fsi/fsi-controller.yaml# + +properties: + compatible: + enum: + - aspeed,ast2400-cf-fsi-master + - aspeed,ast2500-cf-fsi-master + + clock-gpios: + maxItems: 1 + description: GPIO for FSI clock + + data-gpios: + maxItems: 1 + description: GPIO for FSI data signal + + enable-gpios: + maxItems: 1 + description: GPIO for enable signal + + trans-gpios: + maxItems: 1 + description: GPIO for voltage translator enable + + mux-gpios: + maxItems: 1 + description: + GPIO for pin multiplexing with other functions (eg, external FSI masters) + + memory-region: + maxItems: 1 + description: + Reference to the reserved memory for the ColdFire. Must be 2M aligned on + AST2400 and 1M aligned on AST2500. + + aspeed,cvic: + description: Reference to the CVIC node. + $ref: /schemas/types.yaml#/definitions/phandle + + aspeed,sram: + description: Reference to the SRAM node. + $ref: /schemas/types.yaml#/definitions/phandle + +required: + - compatible + - clock-gpios + - data-gpios + - enable-gpios + - trans-gpios + - mux-gpios + - memory-region + - aspeed,cvic + - aspeed,sram + +unevaluatedProperties: false + +examples: + - | + fsi-master { + compatible = "aspeed,ast2500-cf-fsi-master"; + clock-gpios = <&gpio 0>; + data-gpios = <&gpio 1>; + enable-gpios = <&gpio 2>; + trans-gpios = <&gpio 3>; + mux-gpios = <&gpio 4>; + memory-region = <&coldfire_memory>; + aspeed,cvic = <&cvic>; + aspeed,sram = <&sram>; + }; diff --git a/Documentation/devicetree/bindings/fsi/fsi-master-ast-cf.txt b/Documentation/devicetree/bindings/fsi/fsi-master-ast-cf.txt deleted file mode 100644 index 3dc752db748b..000000000000 --- a/Documentation/devicetree/bindings/fsi/fsi-master-ast-cf.txt +++ /dev/null @@ -1,36 +0,0 @@ -Device-tree bindings for ColdFire offloaded gpio-based FSI master driver ------------------------------------------------------------------------- - -Required properties: - - compatible = - "aspeed,ast2400-cf-fsi-master" for an AST2400 based system - or - "aspeed,ast2500-cf-fsi-master" for an AST2500 based system - - - clock-gpios = ; : GPIO for FSI clock - - data-gpios = ; : GPIO for FSI data signal - - enable-gpios = ; : GPIO for enable signal - - trans-gpios = ; : GPIO for voltage translator enable - - mux-gpios = ; : GPIO for pin multiplexing with other - functions (eg, external FSI masters) - - memory-region = ; : Reference to the reserved memory for - the ColdFire. Must be 2M aligned on - AST2400 and 1M aligned on AST2500 - - aspeed,sram = ; : Reference to the SRAM node. - - aspeed,cvic = ; : Reference to the CVIC node. - -Examples: - - fsi-master { - compatible = "aspeed,ast2500-cf-fsi-master", "fsi-master"; - - clock-gpios = <&gpio 0>; - data-gpios = <&gpio 1>; - enable-gpios = <&gpio 2>; - trans-gpios = <&gpio 3>; - mux-gpios = <&gpio 4>; - - memory-region = <&coldfire_memory>; - aspeed,sram = <&sram>; - aspeed,cvic = <&cvic>; - } From 59304e7b80b4554fae6f1df0f518bd341a0fedc9 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 6 Aug 2025 01:03:08 +0200 Subject: [PATCH 00199/11391] dt-bindings: arm: Spell out acronym When I authored these bindings I had no idea what "AEM" stood for. Now I know: it means "Architecture Envelope Model". Detail this in the bindings. Signed-off-by: Linus Walleij Acked-by: Conor Dooley Reviewed-by: Sudeep Holla Link: https://lore.kernel.org/r/20250806-aem-dt-bind-v1-1-d14676dfb027@linaro.org Signed-off-by: Rob Herring (Arm) --- Documentation/devicetree/bindings/arm/arm,vexpress-juno.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/arm,vexpress-juno.yaml b/Documentation/devicetree/bindings/arm/arm,vexpress-juno.yaml index 8dd6b6446394..89298b39903f 100644 --- a/Documentation/devicetree/bindings/arm/arm,vexpress-juno.yaml +++ b/Documentation/devicetree/bindings/arm/arm,vexpress-juno.yaml @@ -103,8 +103,9 @@ properties: - const: arm,juno-r2 - const: arm,juno - const: arm,vexpress - - description: Arm AEMv8a Versatile Express Real-Time System Model - (VE RTSM) is a programmers view of the Versatile Express with Arm + - description: Arm AEMv8a (Architecture Envelope Model) + Versatile Express Real-Time System Model (VE RTSM) + is a programmers view of the Versatile Express with Arm v8A hardware. See ARM DUI 0575D. items: - const: arm,rtsm_ve,aemv8a From 181fe022ecf8a8e85def0e94852c631c59a8b3f6 Mon Sep 17 00:00:00 2001 From: Thomas Richard Date: Mon, 11 Aug 2025 15:25:44 +0200 Subject: [PATCH 00200/11391] gpiolib: add support to register sparse pin range Add support to register for GPIO<->pin mapping using a list of non consecutive pins. The core already supports sparse pin range (pins member of struct pinctrl_gpio_range), but it was not possible to register one. If pins is not NULL the core uses it, otherwise it assumes that a consecutive pin range was registered and it uses pin_base. The function gpiochip_add_pin_range() which allocates and fills the struct pinctrl_gpio_range was renamed to gpiochip_add_pin_range_with_pins() and the pins parameter was added. Two new functions were added, gpiochip_add_pin_range() and gpiochip_add_sparse_pin_range() to register a consecutive or sparse pins range. Both use gpiochip_add_pin_range_with_pins(). Reviewed-by: Linus Walleij Reviewed-by: Andy Shevchenko Acked-by: Linus Walleij Signed-off-by: Thomas Richard Link: https://lore.kernel.org/r/20250811-aaeon-up-board-pinctrl-support-v9-1-29f0cbbdfb30@bootlin.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 29 ++++++++++++++------- include/linux/gpio/driver.h | 51 ++++++++++++++++++++++++++++++++++--- 2 files changed, 68 insertions(+), 12 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 0d2b470a252e..98d2fa602490 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2349,11 +2349,13 @@ int gpiochip_add_pingroup_range(struct gpio_chip *gc, EXPORT_SYMBOL_GPL(gpiochip_add_pingroup_range); /** - * gpiochip_add_pin_range() - add a range for GPIO <-> pin mapping + * gpiochip_add_pin_range_with_pins() - add a range for GPIO <-> pin mapping * @gc: the gpiochip to add the range for * @pinctl_name: the dev_name() of the pin controller to map to * @gpio_offset: the start offset in the current gpio_chip number space * @pin_offset: the start offset in the pin controller number space + * @pins: the list of non consecutive pins to accumulate in this range (if not + * NULL, pin_offset is ignored by pinctrl core) * @npins: the number of pins from the offset of each pin space (GPIO and * pin controller) to accumulate in this range * @@ -2365,9 +2367,12 @@ EXPORT_SYMBOL_GPL(gpiochip_add_pingroup_range); * Returns: * 0 on success, or a negative errno on failure. */ -int gpiochip_add_pin_range(struct gpio_chip *gc, const char *pinctl_name, - unsigned int gpio_offset, unsigned int pin_offset, - unsigned int npins) +int gpiochip_add_pin_range_with_pins(struct gpio_chip *gc, + const char *pinctl_name, + unsigned int gpio_offset, + unsigned int pin_offset, + unsigned int const *pins, + unsigned int npins) { struct gpio_pin_range *pin_range; struct gpio_device *gdev = gc->gpiodev; @@ -2385,6 +2390,7 @@ int gpiochip_add_pin_range(struct gpio_chip *gc, const char *pinctl_name, pin_range->range.name = gc->label; pin_range->range.base = gdev->base + gpio_offset; pin_range->range.pin_base = pin_offset; + pin_range->range.pins = pins; pin_range->range.npins = npins; pin_range->pctldev = pinctrl_find_and_add_gpio_range(pinctl_name, &pin_range->range); @@ -2394,16 +2400,21 @@ int gpiochip_add_pin_range(struct gpio_chip *gc, const char *pinctl_name, kfree(pin_range); return ret; } - chip_dbg(gc, "created GPIO range %d->%d ==> %s PIN %d->%d\n", - gpio_offset, gpio_offset + npins - 1, - pinctl_name, - pin_offset, pin_offset + npins - 1); + if (pin_range->range.pins) + chip_dbg(gc, "created GPIO range %d->%d ==> %s %d sparse PIN range { %d, ... }", + gpio_offset, gpio_offset + npins - 1, + pinctl_name, npins, pins[0]); + else + chip_dbg(gc, "created GPIO range %d->%d ==> %s PIN %d->%d\n", + gpio_offset, gpio_offset + npins - 1, + pinctl_name, + pin_offset, pin_offset + npins - 1); list_add_tail(&pin_range->node, &gdev->pin_ranges); return 0; } -EXPORT_SYMBOL_GPL(gpiochip_add_pin_range); +EXPORT_SYMBOL_GPL(gpiochip_add_pin_range_with_pins); /** * gpiochip_remove_pin_ranges() - remove all the GPIO <-> pin mappings diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 667f8fd58a79..9fcd4a988081 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -772,16 +772,50 @@ struct gpio_pin_range { #ifdef CONFIG_PINCTRL -int gpiochip_add_pin_range(struct gpio_chip *gc, const char *pinctl_name, - unsigned int gpio_offset, unsigned int pin_offset, - unsigned int npins); +int gpiochip_add_pin_range_with_pins(struct gpio_chip *gc, + const char *pinctl_name, + unsigned int gpio_offset, + unsigned int pin_offset, + unsigned int const *pins, + unsigned int npins); int gpiochip_add_pingroup_range(struct gpio_chip *gc, struct pinctrl_dev *pctldev, unsigned int gpio_offset, const char *pin_group); void gpiochip_remove_pin_ranges(struct gpio_chip *gc); +static inline int +gpiochip_add_pin_range(struct gpio_chip *gc, + const char *pinctl_name, + unsigned int gpio_offset, + unsigned int pin_offset, + unsigned int npins) +{ + return gpiochip_add_pin_range_with_pins(gc, pinctl_name, gpio_offset, + pin_offset, NULL, npins); +} + +static inline int +gpiochip_add_sparse_pin_range(struct gpio_chip *gc, + const char *pinctl_name, + unsigned int gpio_offset, + unsigned int const *pins, + unsigned int npins) +{ + return gpiochip_add_pin_range_with_pins(gc, pinctl_name, gpio_offset, 0, + pins, npins); +} #else /* ! CONFIG_PINCTRL */ +static inline int +gpiochip_add_pin_range_with_pins(struct gpio_chip *gc, + const char *pinctl_name, + unsigned int gpio_offset, + unsigned int pin_offset, + unsigned int npins) +{ + return 0; +} + static inline int gpiochip_add_pin_range(struct gpio_chip *gc, const char *pinctl_name, unsigned int gpio_offset, unsigned int pin_offset, @@ -789,6 +823,17 @@ gpiochip_add_pin_range(struct gpio_chip *gc, const char *pinctl_name, { return 0; } + +static inline int +gpiochip_add_sparse_pin_range(struct gpio_chip *gc, + const char *pinctl_name, + unsigned int gpio_offset, + unsigned int const *pins, + unsigned int npins) +{ + return 0; +} + static inline int gpiochip_add_pingroup_range(struct gpio_chip *gc, struct pinctrl_dev *pctldev, From 871c7cd54830c0bda15513238ea9d46fc1cae991 Mon Sep 17 00:00:00 2001 From: Thomas Richard Date: Mon, 11 Aug 2025 15:25:45 +0200 Subject: [PATCH 00201/11391] gpio: aggregator: move GPIO forwarder allocation in a dedicated function Move the GPIO forwarder allocation and static initialization in a dedicated function. Reviewed-by: Andy Shevchenko Acked-by: Linus Walleij Signed-off-by: Thomas Richard Link: https://lore.kernel.org/r/20250811-aaeon-up-board-pinctrl-support-v9-2-29f0cbbdfb30@bootlin.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-aggregator.c | 50 ++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index af9d8b3a711d..75c8d0deef2f 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -475,6 +475,35 @@ static int gpiochip_fwd_setup_delay_line(struct device *dev, struct gpio_chip *c } #endif /* !CONFIG_OF_GPIO */ +static struct gpiochip_fwd * +devm_gpiochip_fwd_alloc(struct device *dev, unsigned int ngpios) +{ + struct gpiochip_fwd *fwd; + struct gpio_chip *chip; + + fwd = devm_kzalloc(dev, struct_size(fwd, tmp, fwd_tmp_size(ngpios)), GFP_KERNEL); + if (!fwd) + return ERR_PTR(-ENOMEM); + + chip = &fwd->chip; + + chip->label = dev_name(dev); + chip->parent = dev; + chip->owner = THIS_MODULE; + chip->get_direction = gpio_fwd_get_direction; + chip->direction_input = gpio_fwd_direction_input; + chip->direction_output = gpio_fwd_direction_output; + chip->get = gpio_fwd_get; + chip->get_multiple = gpio_fwd_get_multiple_locked; + chip->set = gpio_fwd_set; + chip->set_multiple = gpio_fwd_set_multiple_locked; + chip->to_irq = gpio_fwd_to_irq; + chip->base = -1; + chip->ngpio = ngpios; + + return fwd; +} + /** * gpiochip_fwd_create() - Create a new GPIO forwarder * @dev: Parent device pointer @@ -495,16 +524,14 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev, struct gpio_desc *descs[], unsigned long features) { - const char *label = dev_name(dev); struct gpiochip_fwd *fwd; struct gpio_chip *chip; unsigned int i; int error; - fwd = devm_kzalloc(dev, struct_size(fwd, tmp, fwd_tmp_size(ngpios)), - GFP_KERNEL); - if (!fwd) - return ERR_PTR(-ENOMEM); + fwd = devm_gpiochip_fwd_alloc(dev, ngpios); + if (IS_ERR(fwd)) + return fwd; chip = &fwd->chip; @@ -526,19 +553,6 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev, chip->set_config = gpio_fwd_set_config; } - chip->label = label; - chip->parent = dev; - chip->owner = THIS_MODULE; - chip->get_direction = gpio_fwd_get_direction; - chip->direction_input = gpio_fwd_direction_input; - chip->direction_output = gpio_fwd_direction_output; - chip->get = gpio_fwd_get; - chip->get_multiple = gpio_fwd_get_multiple_locked; - chip->set = gpio_fwd_set; - chip->set_multiple = gpio_fwd_set_multiple_locked; - chip->to_irq = gpio_fwd_to_irq; - chip->base = -1; - chip->ngpio = ngpios; fwd->descs = descs; if (chip->can_sleep) From c44ce91b8ada680074aa976e61fcef5633e6f086 Mon Sep 17 00:00:00 2001 From: Thomas Richard Date: Mon, 11 Aug 2025 15:25:46 +0200 Subject: [PATCH 00202/11391] gpio: aggregator: refactor the code to add GPIO desc in the forwarder Create a dedicated function to add a GPIO desc in the forwarder. Instead of saving a GPIO descs array pointer, now the GPIO descs are passed one by one to the forwarder which registers them in its own array. So after the call of gpiochip_fwd_create(), the passed array can be free. Reviewed-by: Andy Shevchenko Acked-by: Linus Walleij Signed-off-by: Thomas Richard Link: https://lore.kernel.org/r/20250811-aaeon-up-board-pinctrl-support-v9-3-29f0cbbdfb30@bootlin.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-aggregator.c | 59 +++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index 75c8d0deef2f..43e488ee8383 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -485,6 +485,10 @@ devm_gpiochip_fwd_alloc(struct device *dev, unsigned int ngpios) if (!fwd) return ERR_PTR(-ENOMEM); + fwd->descs = devm_kcalloc(dev, ngpios, sizeof(*fwd->descs), GFP_KERNEL); + if (!fwd->descs) + return ERR_PTR(-ENOMEM); + chip = &fwd->chip; chip->label = dev_name(dev); @@ -504,13 +508,43 @@ devm_gpiochip_fwd_alloc(struct device *dev, unsigned int ngpios) return fwd; } +static int gpiochip_fwd_desc_add(struct gpiochip_fwd *fwd, + struct gpio_desc *desc, + unsigned int offset) +{ + struct gpio_chip *parent = gpiod_to_chip(desc); + struct gpio_chip *chip = &fwd->chip; + + if (offset > chip->ngpio) + return -EINVAL; + + /* + * If any of the GPIO lines are sleeping, then the entire forwarder + * will be sleeping. + * If any of the chips support .set_config(), then the forwarder will + * support setting configs. + */ + if (gpiod_cansleep(desc)) + chip->can_sleep = true; + + if (parent && parent->set_config) + chip->set_config = gpio_fwd_set_config; + + fwd->descs[offset] = desc; + + dev_dbg(chip->parent, "%u => gpio %d irq %d\n", offset, + desc_to_gpio(desc), gpiod_to_irq(desc)); + + return 0; +} + /** * gpiochip_fwd_create() - Create a new GPIO forwarder * @dev: Parent device pointer * @ngpios: Number of GPIOs in the forwarder. * @descs: Array containing the GPIO descriptors to forward to. - * This array must contain @ngpios entries, and must not be deallocated - * before the forwarder has been destroyed again. + * This array must contain @ngpios entries, and can be deallocated + * as the forwarder has its own array. * @features: Bitwise ORed features as defined with FWD_FEATURE_*. * * This function creates a new gpiochip, which forwards all GPIO operations to @@ -535,26 +569,12 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev, chip = &fwd->chip; - /* - * If any of the GPIO lines are sleeping, then the entire forwarder - * will be sleeping. - * If any of the chips support .set_config(), then the forwarder will - * support setting configs. - */ for (i = 0; i < ngpios; i++) { - struct gpio_chip *parent = gpiod_to_chip(descs[i]); - - dev_dbg(dev, "%u => gpio %d irq %d\n", i, - desc_to_gpio(descs[i]), gpiod_to_irq(descs[i])); - - if (gpiod_cansleep(descs[i])) - chip->can_sleep = true; - if (parent && parent->set_config) - chip->set_config = gpio_fwd_set_config; + error = gpiochip_fwd_desc_add(fwd, descs[i], i); + if (error) + return ERR_PTR(error); } - fwd->descs = descs; - if (chip->can_sleep) mutex_init(&fwd->mlock); else @@ -1348,6 +1368,7 @@ static int gpio_aggregator_probe(struct platform_device *pdev) return PTR_ERR(fwd); platform_set_drvdata(pdev, fwd); + devm_kfree(dev, descs); return 0; } From 10d022efe2c4bb2020a07b2e4d94b658ce30aca4 Mon Sep 17 00:00:00 2001 From: Thomas Richard Date: Mon, 11 Aug 2025 15:25:47 +0200 Subject: [PATCH 00203/11391] gpio: aggregator: refactor the forwarder registration part Add a new function gpiochip_fwd_register(), which finalizes the initialization of the forwarder and registers the corresponding gpiochip. Reviewed-by: Andy Shevchenko Reviewed-by: Geert Uytterhoeven Acked-by: Linus Walleij Signed-off-by: Thomas Richard Link: https://lore.kernel.org/r/20250811-aaeon-up-board-pinctrl-support-v9-4-29f0cbbdfb30@bootlin.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-aggregator.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index 43e488ee8383..95415f928436 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -538,6 +538,18 @@ static int gpiochip_fwd_desc_add(struct gpiochip_fwd *fwd, return 0; } +static int gpiochip_fwd_register(struct gpiochip_fwd *fwd) +{ + struct gpio_chip *chip = &fwd->chip; + + if (chip->can_sleep) + mutex_init(&fwd->mlock); + else + spin_lock_init(&fwd->slock); + + return devm_gpiochip_add_data(chip->parent, chip, fwd); +} + /** * gpiochip_fwd_create() - Create a new GPIO forwarder * @dev: Parent device pointer @@ -575,18 +587,13 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev, return ERR_PTR(error); } - if (chip->can_sleep) - mutex_init(&fwd->mlock); - else - spin_lock_init(&fwd->slock); - if (features & FWD_FEATURE_DELAY) { error = gpiochip_fwd_setup_delay_line(dev, chip, fwd); if (error) return ERR_PTR(error); } - error = devm_gpiochip_add_data(dev, chip, fwd); + error = gpiochip_fwd_register(fwd); if (error) return ERR_PTR(error); From b94cf35db606453c64e5da13c56cc6f8cabc6a33 Mon Sep 17 00:00:00 2001 From: Thomas Richard Date: Mon, 11 Aug 2025 15:25:48 +0200 Subject: [PATCH 00204/11391] gpio: aggregator: update gpiochip_fwd_setup_delay_line() parameters Remove useless parameters of gpiochip_fwd_setup_delay_line(). Reviewed-by: Andy Shevchenko Reviewed-by: Geert Uytterhoeven Acked-by: Linus Walleij Signed-off-by: Thomas Richard Link: https://lore.kernel.org/r/20250811-aaeon-up-board-pinctrl-support-v9-5-29f0cbbdfb30@bootlin.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-aggregator.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index 95415f928436..cc54d19f2dd1 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -453,10 +453,11 @@ static int gpiochip_fwd_delay_of_xlate(struct gpio_chip *chip, return line; } -static int gpiochip_fwd_setup_delay_line(struct device *dev, struct gpio_chip *chip, - struct gpiochip_fwd *fwd) +static int gpiochip_fwd_setup_delay_line(struct gpiochip_fwd *fwd) { - fwd->delay_timings = devm_kcalloc(dev, chip->ngpio, + struct gpio_chip *chip = &fwd->chip; + + fwd->delay_timings = devm_kcalloc(chip->parent, chip->ngpio, sizeof(*fwd->delay_timings), GFP_KERNEL); if (!fwd->delay_timings) @@ -468,8 +469,7 @@ static int gpiochip_fwd_setup_delay_line(struct device *dev, struct gpio_chip *c return 0; } #else -static int gpiochip_fwd_setup_delay_line(struct device *dev, struct gpio_chip *chip, - struct gpiochip_fwd *fwd) +static int gpiochip_fwd_setup_delay_line(struct gpiochip_fwd *fwd) { return 0; } @@ -571,7 +571,6 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev, unsigned long features) { struct gpiochip_fwd *fwd; - struct gpio_chip *chip; unsigned int i; int error; @@ -579,8 +578,6 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev, if (IS_ERR(fwd)) return fwd; - chip = &fwd->chip; - for (i = 0; i < ngpios; i++) { error = gpiochip_fwd_desc_add(fwd, descs[i], i); if (error) @@ -588,7 +585,7 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev, } if (features & FWD_FEATURE_DELAY) { - error = gpiochip_fwd_setup_delay_line(dev, chip, fwd); + error = gpiochip_fwd_setup_delay_line(fwd); if (error) return ERR_PTR(error); } From 6e986f8852f56cf9214ea2ec02b4b432e201d02c Mon Sep 17 00:00:00 2001 From: Thomas Richard Date: Mon, 11 Aug 2025 15:25:49 +0200 Subject: [PATCH 00205/11391] gpio: aggregator: export symbols of the GPIO forwarder library Export all symbols and create header file for the GPIO forwarder library. It will be used in the next changes. Acked-by: Linus Walleij Signed-off-by: Thomas Richard Link: https://lore.kernel.org/r/20250811-aaeon-up-board-pinctrl-support-v9-6-29f0cbbdfb30@bootlin.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-aggregator.c | 202 ++++++++++++++++++++++++++++++++- include/linux/gpio/forwarder.h | 37 ++++++ 2 files changed, 233 insertions(+), 6 deletions(-) create mode 100644 include/linux/gpio/forwarder.h diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index cc54d19f2dd1..c1952b28b7b7 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,7 @@ #include #include +#include #include #include "dev-sync-probe.h" @@ -475,8 +477,180 @@ static int gpiochip_fwd_setup_delay_line(struct gpiochip_fwd *fwd) } #endif /* !CONFIG_OF_GPIO */ -static struct gpiochip_fwd * -devm_gpiochip_fwd_alloc(struct device *dev, unsigned int ngpios) +/** + * gpiochip_fwd_get_gpiochip - Get the GPIO chip for the GPIO forwarder + * @fwd: GPIO forwarder + * + * Returns: The GPIO chip for the GPIO forwarder + */ +struct gpio_chip *gpiochip_fwd_get_gpiochip(struct gpiochip_fwd *fwd) +{ + return &fwd->chip; +} +EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_get_gpiochip, "GPIO_FORWARDER"); + +/** + * gpiochip_fwd_gpio_get_direction - Return the current direction of a GPIO forwarder line + * @fwd: GPIO forwarder + * @offset: the offset of the line + * + * Returns: 0 for output, 1 for input, or an error code in case of error. + */ +int gpiochip_fwd_gpio_get_direction(struct gpiochip_fwd *fwd, unsigned int offset) +{ + struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd); + + return gpio_fwd_get_direction(gc, offset); +} +EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_get_direction, "GPIO_FORWARDER"); + +/** + * gpiochip_fwd_gpio_direction_output - Set a GPIO forwarder line direction to + * output + * @fwd: GPIO forwarder + * @offset: the offset of the line + * @value: value to set + * + * Returns: 0 on success, or negative errno on failure. + */ +int gpiochip_fwd_gpio_direction_output(struct gpiochip_fwd *fwd, unsigned int offset, + int value) +{ + struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd); + + return gpio_fwd_direction_output(gc, offset, value); +} +EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_direction_output, "GPIO_FORWARDER"); + +/** + * gpiochip_fwd_gpio_direction_input - Set a GPIO forwarder line direction to input + * @fwd: GPIO forwarder + * @offset: the offset of the line + * + * Returns: 0 on success, or negative errno on failure. + */ +int gpiochip_fwd_gpio_direction_input(struct gpiochip_fwd *fwd, unsigned int offset) +{ + struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd); + + return gpio_fwd_direction_input(gc, offset); +} +EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_direction_input, "GPIO_FORWARDER"); + +/** + * gpiochip_fwd_gpio_get - Return a GPIO forwarder line's value + * @fwd: GPIO forwarder + * @offset: the offset of the line + * + * Returns: The GPIO's logical value, i.e. taking the ACTIVE_LOW status into + * account, or negative errno on failure. + */ +int gpiochip_fwd_gpio_get(struct gpiochip_fwd *fwd, unsigned int offset) +{ + struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd); + + return gpio_fwd_get(gc, offset); +} +EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_get, "GPIO_FORWARDER"); + +/** + * gpiochip_fwd_gpio_get_multiple - Get values for multiple GPIO forwarder lines + * @fwd: GPIO forwarder + * @mask: bit mask array; one bit per line; BITS_PER_LONG bits per word defines + * which lines are to be read + * @bits: bit value array; one bit per line; BITS_PER_LONG bits per word will + * contains the read values for the lines specified by mask + * + * Returns: 0 on success, or negative errno on failure. + */ +int gpiochip_fwd_gpio_get_multiple(struct gpiochip_fwd *fwd, unsigned long *mask, + unsigned long *bits) +{ + struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd); + + return gpio_fwd_get_multiple_locked(gc, mask, bits); +} +EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_get_multiple, "GPIO_FORWARDER"); + +/** + * gpiochip_fwd_gpio_set - Assign value to a GPIO forwarder line. + * @fwd: GPIO forwarder + * @offset: the offset of the line + * @value: value to set + * + * Returns: 0 on success, or negative errno on failure. + */ +int gpiochip_fwd_gpio_set(struct gpiochip_fwd *fwd, unsigned int offset, int value) +{ + struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd); + + return gpio_fwd_set(gc, offset, value); +} +EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_set, "GPIO_FORWARDER"); + +/** + * gpiochip_fwd_gpio_set_multiple - Assign values to multiple GPIO forwarder lines + * @fwd: GPIO forwarder + * @mask: bit mask array; one bit per output; BITS_PER_LONG bits per word + * defines which outputs are to be changed + * @bits: bit value array; one bit per output; BITS_PER_LONG bits per word + * defines the values the outputs specified by mask are to be set to + * + * Returns: 0 on success, or negative errno on failure. + */ +int gpiochip_fwd_gpio_set_multiple(struct gpiochip_fwd *fwd, unsigned long *mask, + unsigned long *bits) +{ + struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd); + + return gpio_fwd_set_multiple_locked(gc, mask, bits); +} +EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_set_multiple, "GPIO_FORWARDER"); + +/** + * gpiochip_fwd_gpio_set_config - Set @config for a GPIO forwarder line + * @fwd: GPIO forwarder + * @offset: the offset of the line + * @config: Same packed config format as generic pinconf + * + * Returns: 0 on success, %-ENOTSUPP if the controller doesn't support setting + * the configuration. + */ +int gpiochip_fwd_gpio_set_config(struct gpiochip_fwd *fwd, unsigned int offset, + unsigned long config) +{ + struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd); + + return gpio_fwd_set_config(gc, offset, config); +} +EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_set_config, "GPIO_FORWARDER"); + +/** + * gpiochip_fwd_gpio_to_irq - Return the IRQ corresponding to a GPIO forwarder line + * @fwd: GPIO forwarder + * @offset: the offset of the line + * + * Returns: The Linux IRQ corresponding to the passed line, or an error code in + * case of error. + */ +int gpiochip_fwd_gpio_to_irq(struct gpiochip_fwd *fwd, unsigned int offset) +{ + struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd); + + return gpio_fwd_to_irq(gc, offset); +} +EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_to_irq, "GPIO_FORWARDER"); + +/** + * devm_gpiochip_fwd_alloc - Allocate and initialize a new GPIO forwarder + * @dev: Parent device pointer + * @ngpios: Number of GPIOs in the forwarder + * + * Returns: An opaque object pointer, or an ERR_PTR()-encoded negative error + * code on failure. + */ +struct gpiochip_fwd *devm_gpiochip_fwd_alloc(struct device *dev, + unsigned int ngpios) { struct gpiochip_fwd *fwd; struct gpio_chip *chip; @@ -507,10 +681,18 @@ devm_gpiochip_fwd_alloc(struct device *dev, unsigned int ngpios) return fwd; } +EXPORT_SYMBOL_NS_GPL(devm_gpiochip_fwd_alloc, "GPIO_FORWARDER"); -static int gpiochip_fwd_desc_add(struct gpiochip_fwd *fwd, - struct gpio_desc *desc, - unsigned int offset) +/** + * gpiochip_fwd_desc_add - Add a GPIO desc in the forwarder + * @fwd: GPIO forwarder + * @desc: GPIO descriptor to register + * @offset: offset for the GPIO in the forwarder + * + * Returns: 0 on success, or negative errno on failure. + */ +int gpiochip_fwd_desc_add(struct gpiochip_fwd *fwd, struct gpio_desc *desc, + unsigned int offset) { struct gpio_chip *parent = gpiod_to_chip(desc); struct gpio_chip *chip = &fwd->chip; @@ -537,8 +719,15 @@ static int gpiochip_fwd_desc_add(struct gpiochip_fwd *fwd, return 0; } +EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_desc_add, "GPIO_FORWARDER"); -static int gpiochip_fwd_register(struct gpiochip_fwd *fwd) +/** + * gpiochip_fwd_register - Register a GPIO forwarder + * @fwd: GPIO forwarder + * + * Returns: 0 on success, or negative errno on failure. + */ +int gpiochip_fwd_register(struct gpiochip_fwd *fwd) { struct gpio_chip *chip = &fwd->chip; @@ -549,6 +738,7 @@ static int gpiochip_fwd_register(struct gpiochip_fwd *fwd) return devm_gpiochip_add_data(chip->parent, chip, fwd); } +EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_register, "GPIO_FORWARDER"); /** * gpiochip_fwd_create() - Create a new GPIO forwarder diff --git a/include/linux/gpio/forwarder.h b/include/linux/gpio/forwarder.h new file mode 100644 index 000000000000..e21a1b7b1905 --- /dev/null +++ b/include/linux/gpio/forwarder.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LINUX_GPIO_FORWARDER_H +#define __LINUX_GPIO_FORWARDER_H + +struct gpio_desc; +struct gpio_chip; +struct gpiochip_fwd; + +struct gpiochip_fwd *devm_gpiochip_fwd_alloc(struct device *dev, + unsigned int ngpios); +int gpiochip_fwd_desc_add(struct gpiochip_fwd *fwd, + struct gpio_desc *desc, unsigned int offset); +int gpiochip_fwd_register(struct gpiochip_fwd *fwd); + +struct gpio_chip *gpiochip_fwd_get_gpiochip(struct gpiochip_fwd *fwd); + +int gpiochip_fwd_gpio_get_direction(struct gpiochip_fwd *fwd, + unsigned int offset); +int gpiochip_fwd_gpio_direction_input(struct gpiochip_fwd *fwd, + unsigned int offset); +int gpiochip_fwd_gpio_direction_output(struct gpiochip_fwd *fwd, + unsigned int offset, + int value); +int gpiochip_fwd_gpio_get(struct gpiochip_fwd *fwd, unsigned int offset); +int gpiochip_fwd_gpio_get_multiple(struct gpiochip_fwd *fwd, + unsigned long *mask, + unsigned long *bits); +int gpiochip_fwd_gpio_set(struct gpiochip_fwd *fwd, unsigned int offset, + int value); +int gpiochip_fwd_gpio_set_multiple(struct gpiochip_fwd *fwd, + unsigned long *mask, + unsigned long *bits); +int gpiochip_fwd_gpio_set_config(struct gpiochip_fwd *fwd, unsigned int offset, + unsigned long config); +int gpiochip_fwd_gpio_to_irq(struct gpiochip_fwd *fwd, unsigned int offset); + +#endif From b31c68fd851e74526ad963362ea205eb97b9a710 Mon Sep 17 00:00:00 2001 From: Thomas Richard Date: Mon, 11 Aug 2025 15:25:50 +0200 Subject: [PATCH 00206/11391] gpio: aggregator: handle runtime registration of gpio_desc in gpiochip_fwd Add request() callback to check if the GPIO descriptor was well registered in the gpiochip_fwd before using it. This is done to handle the case where GPIO descriptor is added at runtime in the forwarder. If at least one GPIO descriptor was not added before the forwarder registration, we assume the forwarder can sleep as if a GPIO is added at runtime it may sleep. Acked-by: Linus Walleij Signed-off-by: Thomas Richard Link: https://lore.kernel.org/r/20250811-aaeon-up-board-pinctrl-support-v9-7-29f0cbbdfb30@bootlin.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-aggregator.c | 63 ++++++++++++++++++++++++++++++---- include/linux/gpio/forwarder.h | 2 ++ 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index c1952b28b7b7..f0d38d76cf73 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -246,6 +246,7 @@ struct gpiochip_fwd { spinlock_t slock; /* protects tmp[] if !can_sleep */ }; struct gpiochip_fwd_timing *delay_timings; + unsigned long *valid_mask; unsigned long tmp[]; /* values and descs for multiple ops */ }; @@ -254,10 +255,24 @@ struct gpiochip_fwd { #define fwd_tmp_size(ngpios) (BITS_TO_LONGS((ngpios)) + (ngpios)) +static int gpio_fwd_request(struct gpio_chip *chip, unsigned int offset) +{ + struct gpiochip_fwd *fwd = gpiochip_get_data(chip); + + return test_bit(offset, fwd->valid_mask) ? 0 : -ENODEV; +} + static int gpio_fwd_get_direction(struct gpio_chip *chip, unsigned int offset) { struct gpiochip_fwd *fwd = gpiochip_get_data(chip); + /* + * get_direction() is called during gpiochip registration, return + * -ENODEV if there is no GPIO desc for the line. + */ + if (!test_bit(offset, fwd->valid_mask)) + return -ENODEV; + return gpiod_get_direction(fwd->descs[offset]); } @@ -489,6 +504,21 @@ struct gpio_chip *gpiochip_fwd_get_gpiochip(struct gpiochip_fwd *fwd) } EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_get_gpiochip, "GPIO_FORWARDER"); +/** + * gpiochip_fwd_gpio_request - Request a line of the GPIO forwarder + * @fwd: GPIO forwarder + * @offset: the offset of the line to request + * + * Returns: 0 on success, or negative errno on failure. + */ +int gpiochip_fwd_gpio_request(struct gpiochip_fwd *fwd, unsigned int offset) +{ + struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd); + + return gpio_fwd_request(gc, offset); +} +EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_request, "GPIO_FORWARDER"); + /** * gpiochip_fwd_gpio_get_direction - Return the current direction of a GPIO forwarder line * @fwd: GPIO forwarder @@ -663,11 +693,16 @@ struct gpiochip_fwd *devm_gpiochip_fwd_alloc(struct device *dev, if (!fwd->descs) return ERR_PTR(-ENOMEM); + fwd->valid_mask = devm_bitmap_zalloc(dev, ngpios, GFP_KERNEL); + if (!fwd->valid_mask) + return ERR_PTR(-ENOMEM); + chip = &fwd->chip; chip->label = dev_name(dev); chip->parent = dev; chip->owner = THIS_MODULE; + chip->request = gpio_fwd_request; chip->get_direction = gpio_fwd_get_direction; chip->direction_input = gpio_fwd_direction_input; chip->direction_output = gpio_fwd_direction_output; @@ -694,24 +729,21 @@ EXPORT_SYMBOL_NS_GPL(devm_gpiochip_fwd_alloc, "GPIO_FORWARDER"); int gpiochip_fwd_desc_add(struct gpiochip_fwd *fwd, struct gpio_desc *desc, unsigned int offset) { - struct gpio_chip *parent = gpiod_to_chip(desc); struct gpio_chip *chip = &fwd->chip; if (offset > chip->ngpio) return -EINVAL; + if (test_and_set_bit(offset, fwd->valid_mask)) + return -EEXIST; + /* * If any of the GPIO lines are sleeping, then the entire forwarder * will be sleeping. - * If any of the chips support .set_config(), then the forwarder will - * support setting configs. */ if (gpiod_cansleep(desc)) chip->can_sleep = true; - if (parent && parent->set_config) - chip->set_config = gpio_fwd_set_config; - fwd->descs[offset] = desc; dev_dbg(chip->parent, "%u => gpio %d irq %d\n", offset, @@ -721,6 +753,18 @@ int gpiochip_fwd_desc_add(struct gpiochip_fwd *fwd, struct gpio_desc *desc, } EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_desc_add, "GPIO_FORWARDER"); +/** + * gpiochip_fwd_desc_free - Remove a GPIO desc from the forwarder + * @fwd: GPIO forwarder + * @offset: offset of GPIO desc to remove + */ +void gpiochip_fwd_desc_free(struct gpiochip_fwd *fwd, unsigned int offset) +{ + if (test_and_clear_bit(offset, fwd->valid_mask)) + gpiod_put(fwd->descs[offset]); +} +EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_desc_free, "GPIO_FORWARDER"); + /** * gpiochip_fwd_register - Register a GPIO forwarder * @fwd: GPIO forwarder @@ -731,6 +775,13 @@ int gpiochip_fwd_register(struct gpiochip_fwd *fwd) { struct gpio_chip *chip = &fwd->chip; + /* + * Some gpio_desc were not registered. They will be registered at runtime + * but we have to suppose they can sleep. + */ + if (!bitmap_full(fwd->valid_mask, chip->ngpio)) + chip->can_sleep = true; + if (chip->can_sleep) mutex_init(&fwd->mlock); else diff --git a/include/linux/gpio/forwarder.h b/include/linux/gpio/forwarder.h index e21a1b7b1905..45e0190308f0 100644 --- a/include/linux/gpio/forwarder.h +++ b/include/linux/gpio/forwarder.h @@ -10,10 +10,12 @@ struct gpiochip_fwd *devm_gpiochip_fwd_alloc(struct device *dev, unsigned int ngpios); int gpiochip_fwd_desc_add(struct gpiochip_fwd *fwd, struct gpio_desc *desc, unsigned int offset); +void gpiochip_fwd_desc_free(struct gpiochip_fwd *fwd, unsigned int offset); int gpiochip_fwd_register(struct gpiochip_fwd *fwd); struct gpio_chip *gpiochip_fwd_get_gpiochip(struct gpiochip_fwd *fwd); +int gpiochip_fwd_gpio_request(struct gpiochip_fwd *fwd, unsigned int offset); int gpiochip_fwd_gpio_get_direction(struct gpiochip_fwd *fwd, unsigned int offset); int gpiochip_fwd_gpio_direction_input(struct gpiochip_fwd *fwd, From 60e92c1009c7c6abd4a9d0caf33a8cba5d09f67c Mon Sep 17 00:00:00 2001 From: Thomas Richard Date: Mon, 11 Aug 2025 15:25:51 +0200 Subject: [PATCH 00207/11391] gpio: aggregator: add possibility to attach data to the forwarder Add a data pointer to store private data in the forwarder. Reviewed-by: Andy Shevchenko Reviewed-by: Geert Uytterhoeven Acked-by: Linus Walleij Signed-off-by: Thomas Richard Link: https://lore.kernel.org/r/20250811-aaeon-up-board-pinctrl-support-v9-8-29f0cbbdfb30@bootlin.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-aggregator.c | 20 ++++++++++++++++++-- include/linux/gpio/forwarder.h | 4 +++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index f0d38d76cf73..fb3694d581d1 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -246,6 +246,7 @@ struct gpiochip_fwd { spinlock_t slock; /* protects tmp[] if !can_sleep */ }; struct gpiochip_fwd_timing *delay_timings; + void *data; unsigned long *valid_mask; unsigned long tmp[]; /* values and descs for multiple ops */ }; @@ -504,6 +505,18 @@ struct gpio_chip *gpiochip_fwd_get_gpiochip(struct gpiochip_fwd *fwd) } EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_get_gpiochip, "GPIO_FORWARDER"); +/** + * gpiochip_fwd_get_data - Get driver-private data for the GPIO forwarder + * @fwd: GPIO forwarder + * + * Returns: The driver-private data for the GPIO forwarder + */ +void *gpiochip_fwd_get_data(struct gpiochip_fwd *fwd) +{ + return fwd->data; +} +EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_get_data, "GPIO_FORWARDER"); + /** * gpiochip_fwd_gpio_request - Request a line of the GPIO forwarder * @fwd: GPIO forwarder @@ -768,10 +781,11 @@ EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_desc_free, "GPIO_FORWARDER"); /** * gpiochip_fwd_register - Register a GPIO forwarder * @fwd: GPIO forwarder + * @data: driver-private data associated with this forwarder * * Returns: 0 on success, or negative errno on failure. */ -int gpiochip_fwd_register(struct gpiochip_fwd *fwd) +int gpiochip_fwd_register(struct gpiochip_fwd *fwd, void *data) { struct gpio_chip *chip = &fwd->chip; @@ -787,6 +801,8 @@ int gpiochip_fwd_register(struct gpiochip_fwd *fwd) else spin_lock_init(&fwd->slock); + fwd->data = data; + return devm_gpiochip_add_data(chip->parent, chip, fwd); } EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_register, "GPIO_FORWARDER"); @@ -831,7 +847,7 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev, return ERR_PTR(error); } - error = gpiochip_fwd_register(fwd); + error = gpiochip_fwd_register(fwd, NULL); if (error) return ERR_PTR(error); diff --git a/include/linux/gpio/forwarder.h b/include/linux/gpio/forwarder.h index 45e0190308f0..ee5d8355f735 100644 --- a/include/linux/gpio/forwarder.h +++ b/include/linux/gpio/forwarder.h @@ -11,10 +11,12 @@ struct gpiochip_fwd *devm_gpiochip_fwd_alloc(struct device *dev, int gpiochip_fwd_desc_add(struct gpiochip_fwd *fwd, struct gpio_desc *desc, unsigned int offset); void gpiochip_fwd_desc_free(struct gpiochip_fwd *fwd, unsigned int offset); -int gpiochip_fwd_register(struct gpiochip_fwd *fwd); +int gpiochip_fwd_register(struct gpiochip_fwd *fwd, void *data); struct gpio_chip *gpiochip_fwd_get_gpiochip(struct gpiochip_fwd *fwd); +void *gpiochip_fwd_get_data(struct gpiochip_fwd *fwd); + int gpiochip_fwd_gpio_request(struct gpiochip_fwd *fwd, unsigned int offset); int gpiochip_fwd_gpio_get_direction(struct gpiochip_fwd *fwd, unsigned int offset); From 53ec9169db1345f04174febb90f88a871fc28d9e Mon Sep 17 00:00:00 2001 From: Thomas Richard Date: Mon, 11 Aug 2025 15:25:52 +0200 Subject: [PATCH 00208/11391] lib/string_choices: Add str_input_output() helper Add str_input_output() helper to return 'input' or 'output' string literal. Also add the inversed variant str_output_input(). Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Acked-by: Linus Walleij Signed-off-by: Thomas Richard Link: https://lore.kernel.org/r/20250811-aaeon-up-board-pinctrl-support-v9-9-29f0cbbdfb30@bootlin.com Signed-off-by: Bartosz Golaszewski --- include/linux/string_choices.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/linux/string_choices.h b/include/linux/string_choices.h index f3ba4f52ff26..a27c87c954ae 100644 --- a/include/linux/string_choices.h +++ b/include/linux/string_choices.h @@ -41,6 +41,12 @@ static inline const char *str_high_low(bool v) } #define str_low_high(v) str_high_low(!(v)) +static inline const char *str_input_output(bool v) +{ + return v ? "input" : "output"; +} +#define str_output_input(v) str_input_output(!(v)) + static inline const char *str_on_off(bool v) { return v ? "on" : "off"; From 8a5a0294f40a50e5be83e9b7ebbc15b546f64e41 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Mon, 4 Aug 2025 21:26:42 +0100 Subject: [PATCH 00209/11391] dt-bindings: clock: renesas,r9a09g077/87: Add USB_CLK clock ID Add the USB clock (USB_CLK) definition for the Renesas RZ/T2H (R9A09G077) and RZ/N2H (R9A09G087) SoCs. USB_CLK is used as the reference clock for USB PHY layer. Signed-off-by: Lad Prabhakar Acked-by: Krzysztof Kozlowski Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250804202643.3967484-2-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- include/dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h | 1 + include/dt-bindings/clock/renesas,r9a09g087-cpg-mssr.h | 1 + 2 files changed, 2 insertions(+) diff --git a/include/dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h b/include/dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h index 7ecc4f0b235a..0c2ce81a8744 100644 --- a/include/dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h +++ b/include/dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h @@ -25,5 +25,6 @@ #define R9A09G077_CLK_PCLKM 13 #define R9A09G077_CLK_PCLKL 14 #define R9A09G077_SDHI_CLKHS 15 +#define R9A09G077_USB_CLK 16 #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 925e57703925..70ee883f2386 100644 --- a/include/dt-bindings/clock/renesas,r9a09g087-cpg-mssr.h +++ b/include/dt-bindings/clock/renesas,r9a09g087-cpg-mssr.h @@ -25,5 +25,6 @@ #define R9A09G087_CLK_PCLKM 13 #define R9A09G087_CLK_PCLKL 14 #define R9A09G087_SDHI_CLKHS 15 +#define R9A09G087_USB_CLK 16 #endif /* __DT_BINDINGS_CLOCK_RENESAS_R9A09G087_CPG_H__ */ From 5293e8f2a854344ef9aba2391b44c7a437889ebb Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Fri, 8 Aug 2025 14:30:15 +0100 Subject: [PATCH 00210/11391] dt-bindings: pinctrl: renesas: Document RZ/T2H and RZ/N2H SoCs Document the pin and GPIO controller IP for the Renesas RZ/T2H (R9A09G077) and RZ/N2H (R9A09G087) SoCs, and add the shared DTSI header file used by both the bindings and the driver. The RZ/T2H SoC supports 729 pins, while RZ/N2H supports 576 pins. Both share the same controller architecture; separate compatible strings are added for each SoC to distinguish them. Co-developed-by: Thierry Bultel Signed-off-by: Thierry Bultel Signed-off-by: Lad Prabhakar Reviewed-by: "Rob Herring (Arm)" Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250808133017.2053637-2-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- .../pinctrl/renesas,r9a09g077-pinctrl.yaml | 172 ++++++++++++++++++ .../pinctrl/renesas,r9a09g077-pinctrl.h | 22 +++ 2 files changed, 194 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/renesas,r9a09g077-pinctrl.yaml create mode 100644 include/dt-bindings/pinctrl/renesas,r9a09g077-pinctrl.h diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,r9a09g077-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/renesas,r9a09g077-pinctrl.yaml new file mode 100644 index 000000000000..36d665971484 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/renesas,r9a09g077-pinctrl.yaml @@ -0,0 +1,172 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/renesas,r9a09g077-pinctrl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Renesas RZ/T2H and RZ/N2H Pin and GPIO controller + +maintainers: + - Lad Prabhakar + +description: + The Renesas RZ/T2H and RZ/N2H SoCs feature a combined Pin and GPIO controller. + Pin multiplexing and GPIO configuration are performed on a per-pin basis. + Each port supports up to 8 pins, each configurable for either GPIO (port mode) + or alternate function mode. Each pin supports function mode values ranging from + 0x0 to 0x2A, allowing selection from up to 43 different functions. + +properties: + compatible: + enum: + - renesas,r9a09g077-pinctrl # RZ/T2H + - renesas,r9a09g087-pinctrl # RZ/N2H + + reg: + minItems: 1 + items: + - description: Non-safety I/O Port base + - description: Safety I/O Port safety region base + - description: Safety I/O Port Non-safety region base + + reg-names: + minItems: 1 + items: + - const: nsr + - const: srs + - const: srn + + gpio-controller: true + + '#gpio-cells': + const: 2 + description: + The first cell contains the global GPIO port index, constructed using the + RZT2H_GPIO() helper macro from + (e.g. "RZT2H_GPIO(3, 0)" for P03_0). The second cell represents the consumer + flag. Use the macros defined in include/dt-bindings/gpio/gpio.h. + + gpio-ranges: + maxItems: 1 + + clocks: + maxItems: 1 + + power-domains: + maxItems: 1 + +definitions: + renesas-rzt2h-n2h-pins-node: + type: object + allOf: + - $ref: pincfg-node.yaml# + - $ref: pinmux-node.yaml# + properties: + pinmux: + description: + Values are constructed from I/O port number, pin number, and + alternate function configuration number using the RZT2H_PORT_PINMUX() + helper macro from . + pins: true + phandle: true + input: true + input-enable: true + output-enable: true + oneOf: + - required: [pinmux] + - required: [pins] + additionalProperties: false + +patternProperties: + # Grouping nodes: allow multiple "-pins" subnodes within a "-group" + '.*-group$': + type: object + description: + Pin controller client devices can organize pin configuration entries into + grouping nodes ending in "-group". These group nodes may contain multiple + child nodes each ending in "-pins" to configure distinct sets of pins. + additionalProperties: false + patternProperties: + '-pins$': + $ref: '#/definitions/renesas-rzt2h-n2h-pins-node' + + # Standalone "-pins" nodes under client devices or groups + '-pins$': + $ref: '#/definitions/renesas-rzt2h-n2h-pins-node' + + '-hog$': + type: object + description: GPIO hog node + properties: + gpio-hog: true + gpios: true + input: true + output-high: true + output-low: true + line-name: true + required: + - gpio-hog + - gpios + additionalProperties: false + +allOf: + - $ref: pinctrl.yaml# + +required: + - compatible + - reg + - reg-names + - gpio-controller + - '#gpio-cells' + - gpio-ranges + - clocks + - power-domains + +unevaluatedProperties: false + +examples: + - | + #include + #include + + pinctrl@802c0000 { + compatible = "renesas,r9a09g077-pinctrl"; + reg = <0x802c0000 0x2000>, + <0x812c0000 0x2000>, + <0x802b0000 0x2000>; + reg-names = "nsr", "srs", "srn"; + clocks = <&cpg CPG_CORE R9A09G077_CLK_PCLKM>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl 0 0 288>; + power-domains = <&cpg>; + + serial0-pins { + pinmux = , /* Tx */ + ; /* Rx */ + }; + + sd1-pwr-en-hog { + gpio-hog; + gpios = ; + output-high; + line-name = "sd1_pwr_en"; + }; + + i2c0-pins { + pins = "RIIC0_SDA", "RIIC0_SCL"; + input-enable; + }; + + sd0-sd-group { + ctrl-pins { + pinmux = , /* SD0_CLK */ + ; /* SD0_CMD */ + }; + + data-pins { + pinmux = , /* SD0_CLK */ + ; /* SD0_CMD */ + }; + }; + }; diff --git a/include/dt-bindings/pinctrl/renesas,r9a09g077-pinctrl.h b/include/dt-bindings/pinctrl/renesas,r9a09g077-pinctrl.h new file mode 100644 index 000000000000..f088793f23ee --- /dev/null +++ b/include/dt-bindings/pinctrl/renesas,r9a09g077-pinctrl.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * This header provides constants for Renesas RZ/T2H family pinctrl bindings. + * + * Copyright (C) 2025 Renesas Electronics Corp. + */ + +#ifndef __DT_BINDINGS_PINCTRL_RENESAS_R9A09G077_PINCTRL_H__ +#define __DT_BINDINGS_PINCTRL_RENESAS_R9A09G077_PINCTRL_H__ + +#define RZT2H_PINS_PER_PORT 8 + +/* + * Create the pin index from its bank and position numbers and store in + * the upper 16 bits the alternate function identifier + */ +#define RZT2H_PORT_PINMUX(b, p, f) ((b) * RZT2H_PINS_PER_PORT + (p) | ((f) << 16)) + +/* Convert a port and pin label to its global pin index */ +#define RZT2H_GPIO(port, pin) ((port) * RZT2H_PINS_PER_PORT + (pin)) + +#endif /* __DT_BINDINGS_PINCTRL_RENESAS_R9A09G077_PINCTRL_H__ */ From ecb0605364465c051ff4744f3a848ef084b44769 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Mon, 11 Aug 2025 15:50:28 +0900 Subject: [PATCH 00211/11391] vfs: show filesystem name at dump_inode() Commit 8b17e540969a ("vfs: add initial support for CONFIG_DEBUG_VFS") added dump_inode(), but dump_inode() currently reports only raw pointer address. Comment says that adding a proper inode dumping routine is a TODO. However, syzkaller concurrently tests multiple filesystems, and several filesystems started calling dump_inode() due to hitting VFS_BUG_ON_INODE() added by commit af153bb63a33 ("vfs: catch invalid modes in may_open()") before a proper inode dumping routine is implemented. Show filesystem name at dump_inode() so that we can find which filesystem has passed an invalid mode to may_open() from syzkaller's crash reports. Link: https://syzkaller.appspot.com/bug?extid=895c23f6917da440ed0d Signed-off-by: Tetsuo Handa Link: https://lore.kernel.org/ceaf4021-65cc-422e-9d0e-6afa18dd8276@I-love.SAKURA.ne.jp Signed-off-by: Christian Brauner --- fs/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/inode.c b/fs/inode.c index 3cbb78412a3e..cc0f717a140d 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -2913,7 +2913,7 @@ EXPORT_SYMBOL(mode_strip_sgid); */ void dump_inode(struct inode *inode, const char *reason) { - pr_warn("%s encountered for inode %px", reason, inode); + pr_warn("%s encountered for inode %px (%s)\n", reason, inode, inode->i_sb->s_type->name); } EXPORT_SYMBOL(dump_inode); From 1e5f0fb41fccf5ecbb5506551790335c9578e320 Mon Sep 17 00:00:00 2001 From: Askar Safin Date: Mon, 11 Aug 2025 04:52:23 +0000 Subject: [PATCH 00212/11391] vfs: fs/namespace.c: remove ms_flags argument from do_remount ...because it is not used Signed-off-by: Askar Safin Link: https://lore.kernel.org/20250811045444.1813009-1-safinaskar@zohomail.com Reviewed-by: Aleksa Sarai Signed-off-by: Christian Brauner --- fs/namespace.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/namespace.c b/fs/namespace.c index 86d12f88b688..9f732e03c2e5 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -3279,7 +3279,7 @@ static int do_reconfigure_mnt(struct path *path, unsigned int mnt_flags) * If you've mounted a non-root directory somewhere and want to do remount * on it - tough luck. */ -static int do_remount(struct path *path, int ms_flags, int sb_flags, +static int do_remount(struct path *path, int sb_flags, int mnt_flags, void *data) { int err; @@ -4111,7 +4111,7 @@ int path_mount(const char *dev_name, struct path *path, if ((flags & (MS_REMOUNT | MS_BIND)) == (MS_REMOUNT | MS_BIND)) return do_reconfigure_mnt(path, mnt_flags); if (flags & MS_REMOUNT) - return do_remount(path, flags, sb_flags, mnt_flags, data_page); + return do_remount(path, sb_flags, mnt_flags, data_page); if (flags & MS_BIND) return do_loopback(path, dev_name, flags & MS_REC); if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) From 3fe8685424e3a351b151f37e71f0e5f2f3e3fe79 Mon Sep 17 00:00:00 2001 From: Thierry Bultel Date: Thu, 15 May 2025 16:18:25 +0200 Subject: [PATCH 00213/11391] arm64: defconfig: Enable Renesas RZ/T2H serial SCI Selects RZ/T2H (aka r9a09g077) SCI (serial) specific code, as used on the RZ/T2H and RZ/N2H EVKs. Reviewed-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Signed-off-by: Thierry Bultel Link: https://lore.kernel.org/20250515141828.43444-11-thierry.bultel.yh@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- arch/arm64/configs/defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 58f87d09366c..999dbc8c445f 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -499,6 +499,7 @@ CONFIG_SERIAL_TEGRA_TCU=y CONFIG_SERIAL_IMX=y CONFIG_SERIAL_IMX_CONSOLE=y CONFIG_SERIAL_SH_SCI=y +CONFIG_SERIAL_RSCI=y CONFIG_SERIAL_MSM=y CONFIG_SERIAL_MSM_CONSOLE=y CONFIG_SERIAL_QCOM_GENI=y From abd7c0293816a5fa5766710d2e7b576384fdec4d Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Tue, 24 Jun 2025 20:23:03 +0100 Subject: [PATCH 00214/11391] arm64: defconfig: Enable the RZ/V2H(P) RSPI driver Enable the Renesas RZ/V2H(P) RSPI driver for the benefit of RZ/V2H(P) based platforms. Signed-off-by: Fabrizio Castro Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250624192304.338979-6-fabrizio.castro.jz@renesas.com Signed-off-by: Geert Uytterhoeven --- arch/arm64/configs/defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 999dbc8c445f..54c3304c7587 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -580,6 +580,7 @@ CONFIG_SPI_ROCKCHIP=y CONFIG_SPI_ROCKCHIP_SFC=m CONFIG_SPI_RPCIF=m CONFIG_SPI_RSPI=m +CONFIG_SPI_RZV2H_RSPI=m CONFIG_SPI_RZV2M_CSI=m CONFIG_SPI_QCOM_QSPI=m CONFIG_SPI_QUP=y From ad38ea266b8dc6e15e0d2a14a9d8543345fdba44 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 31 Jul 2025 10:37:45 +0200 Subject: [PATCH 00215/11391] ARM: shmobile: rcar-gen2: Use SZ_256K definition Use SZ_256K instead of calculating the same value. Signed-off-by: Geert Uytterhoeven Reviewed-by: Wolfram Sang Link: https://lore.kernel.org/c54097a263eb3e451e5e223609a3630d4409dcdd.1753951039.git.geert+renesas@glider.be --- arch/arm/mach-shmobile/pm-rcar-gen2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-shmobile/pm-rcar-gen2.c b/arch/arm/mach-shmobile/pm-rcar-gen2.c index 907a4f8c5aed..46654d196f8d 100644 --- a/arch/arm/mach-shmobile/pm-rcar-gen2.c +++ b/arch/arm/mach-shmobile/pm-rcar-gen2.c @@ -81,7 +81,7 @@ void __init rcar_gen2_pm_init(void) map: /* RAM for jump stub, because BAR requires 256KB aligned address */ - if (res.start & (256 * 1024 - 1) || + if (res.start & (SZ_256K - 1) || resource_size(&res) < shmobile_boot_size) { pr_err("Invalid smp-sram region\n"); return; From 33450878adfc9d6bfd9cd2da2135b7fd33f2a4fe Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 11 Aug 2025 14:25:17 +0200 Subject: [PATCH 00216/11391] arm64: dts: qcom: sm8550: Flatten the USB nodes Transition the USB controllers found in the SM8550 SoC to the newly introduced, flattened representation of the Qualcomm USB block. The reg and interrupts properties from the usb child node are merged with their counterpart in the outer node, remaining properties and child nodes are simply moved. Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20250811-topic-sm8x50-usb-flatten-v2-1-0bbb3ac292e4@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8550.dtsi | 84 ++++++++++++++-------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi index a4ca06679c2f..38d139d1dd4a 100644 --- a/arch/arm64/boot/dts/qcom/sm8550.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi @@ -4084,12 +4084,11 @@ usb_dp_qmpphy_dp_in: endpoint { }; }; - usb_1: usb@a6f8800 { - compatible = "qcom,sm8550-dwc3", "qcom,dwc3"; - reg = <0x0 0x0a6f8800 0x0 0x400>; - #address-cells = <2>; - #size-cells = <2>; - ranges; + usb_1: usb@a600000 { + compatible = "qcom,sm8550-dwc3", "qcom,snps-dwc3"; + reg = <0x0 0x0a600000 0x0 0xfc100>; + #address-cells = <1>; + #size-cells = <0>; clocks = <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, <&gcc GCC_USB30_PRIM_MASTER_CLK>, @@ -4108,12 +4107,14 @@ usb_1: usb@a6f8800 { <&gcc GCC_USB30_PRIM_MASTER_CLK>; assigned-clock-rates = <19200000>, <200000000>; - interrupts-extended = <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>, + interrupts-extended = <&intc GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>, + <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>, <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, <&pdc 14 IRQ_TYPE_EDGE_BOTH>, <&pdc 15 IRQ_TYPE_EDGE_BOTH>, <&pdc 17 IRQ_TYPE_LEVEL_HIGH>; - interrupt-names = "pwr_event", + interrupt-names = "dwc_usb3", + "pwr_event", "hs_phy_irq", "dp_hs_phy_irq", "dm_hs_phy_irq", @@ -4130,47 +4131,46 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, &config_noc SLAVE_USB3_0 QCOM_ICC_TAG_ACTIVE_ONLY>; interconnect-names = "usb-ddr", "apps-usb"; + iommus = <&apps_smmu 0x40 0x0>; + + phys = <&usb_1_hsphy>, + <&usb_dp_qmpphy QMP_USB43DP_USB3_PHY>; + phy-names = "usb2-phy", "usb3-phy"; + + snps,hird-threshold = /bits/ 8 <0x0>; + snps,usb2-gadget-lpm-disable; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; + snps,dis-u1-entry-quirk; + snps,dis-u2-entry-quirk; + snps,is-utmi-l1-suspend; + snps,usb3_lpm_capable; + snps,usb2-lpm-disable; + snps,has-lpm-erratum; + tx-fifo-resize; + + dma-coherent; + + usb-role-switch; + status = "disabled"; - usb_1_dwc3: usb@a600000 { - compatible = "snps,dwc3"; - reg = <0x0 0x0a600000 0x0 0xcd00>; - interrupts = ; - iommus = <&apps_smmu 0x40 0x0>; - phys = <&usb_1_hsphy>, - <&usb_dp_qmpphy QMP_USB43DP_USB3_PHY>; - phy-names = "usb2-phy", "usb3-phy"; - snps,hird-threshold = /bits/ 8 <0x0>; - snps,usb2-gadget-lpm-disable; - snps,dis_u2_susphy_quirk; - snps,dis_enblslpm_quirk; - snps,dis-u1-entry-quirk; - snps,dis-u2-entry-quirk; - snps,is-utmi-l1-suspend; - snps,usb3_lpm_capable; - snps,usb2-lpm-disable; - snps,has-lpm-erratum; - tx-fifo-resize; - dma-coherent; - usb-role-switch; + ports { + #address-cells = <1>; + #size-cells = <0>; - ports { - #address-cells = <1>; - #size-cells = <0>; + port@0 { + reg = <0>; - port@0 { - reg = <0>; - - usb_1_dwc3_hs: endpoint { - }; + usb_1_dwc3_hs: endpoint { }; + }; - port@1 { - reg = <1>; + port@1 { + reg = <1>; - usb_1_dwc3_ss: endpoint { - remote-endpoint = <&usb_dp_qmpphy_usb_ss_in>; - }; + usb_1_dwc3_ss: endpoint { + remote-endpoint = <&usb_dp_qmpphy_usb_ss_in>; }; }; }; From 77e1f16b930221b427ec24c634703388a64175af Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 11 Aug 2025 14:25:18 +0200 Subject: [PATCH 00217/11391] arm64: dts: qcom: sm8650: Flatten the USB nodes Transition the USB controllers found in the SM8650 SoC to the newly introduced, flattened representation of the Qualcomm USB block. The reg and interrupts properties from the usb child node are merged with their counterpart in the outer node, remaining properties and child nodes are simply moved. Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20250811-topic-sm8x50-usb-flatten-v2-2-0bbb3ac292e4@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8650-hdk.dts | 6 +- arch/arm64/boot/dts/qcom/sm8650-mtp.dts | 6 +- arch/arm64/boot/dts/qcom/sm8650-qrd.dts | 6 +- arch/arm64/boot/dts/qcom/sm8650.dtsi | 88 ++++++++++++------------- 4 files changed, 47 insertions(+), 59 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8650-hdk.dts b/arch/arm64/boot/dts/qcom/sm8650-hdk.dts index 259649d7dcd7..a00da76a6062 100644 --- a/arch/arm64/boot/dts/qcom/sm8650-hdk.dts +++ b/arch/arm64/boot/dts/qcom/sm8650-hdk.dts @@ -1310,12 +1310,10 @@ &ufs_mem_phy { */ &usb_1 { - status = "okay"; -}; - -&usb_1_dwc3 { dr_mode = "otg"; usb-role-switch; + + status = "okay"; }; &usb_1_dwc3_hs { diff --git a/arch/arm64/boot/dts/qcom/sm8650-mtp.dts b/arch/arm64/boot/dts/qcom/sm8650-mtp.dts index 8a957adbfb38..c67bbace2743 100644 --- a/arch/arm64/boot/dts/qcom/sm8650-mtp.dts +++ b/arch/arm64/boot/dts/qcom/sm8650-mtp.dts @@ -857,12 +857,10 @@ &ufs_mem_phy { */ &usb_1 { - status = "okay"; -}; - -&usb_1_dwc3 { dr_mode = "otg"; usb-role-switch; + + status = "okay"; }; &usb_1_dwc3_hs { diff --git a/arch/arm64/boot/dts/qcom/sm8650-qrd.dts b/arch/arm64/boot/dts/qcom/sm8650-qrd.dts index 7552d5d3fb40..081b7e40f574 100644 --- a/arch/arm64/boot/dts/qcom/sm8650-qrd.dts +++ b/arch/arm64/boot/dts/qcom/sm8650-qrd.dts @@ -1293,12 +1293,10 @@ &ufs_mem_phy { */ &usb_1 { - status = "okay"; -}; - -&usb_1_dwc3 { dr_mode = "otg"; usb-role-switch; + + status = "okay"; }; &usb_1_dwc3_hs { diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi index e14d3d778b71..bcafd9cf3eae 100644 --- a/arch/arm64/boot/dts/qcom/sm8650.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi @@ -5651,16 +5651,18 @@ usb_dp_qmpphy_dp_in: endpoint { }; }; - usb_1: usb@a6f8800 { - compatible = "qcom,sm8650-dwc3", "qcom,dwc3"; - reg = <0 0x0a6f8800 0 0x400>; + usb_1: usb@a600000 { + compatible = "qcom,sm8650-dwc3", "qcom,snps-dwc3"; + reg = <0 0x0a600000 0 0xfc100>; - interrupts-extended = <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH 0>, + interrupts-extended = <&intc GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH 0>, + <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH 0>, <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH 0>, <&pdc 14 IRQ_TYPE_EDGE_RISING>, <&pdc 15 IRQ_TYPE_EDGE_RISING>, <&pdc 17 IRQ_TYPE_LEVEL_HIGH>; - interrupt-names = "pwr_event", + interrupt-names = "dwc_usb3", + "pwr_event", "hs_phy_irq", "dp_hs_phy_irq", "dm_hs_phy_irq", @@ -5685,6 +5687,11 @@ usb_1: usb@a6f8800 { resets = <&gcc GCC_USB30_PRIM_BCR>; + phys = <&usb_1_hsphy>, + <&usb_dp_qmpphy QMP_USB43DP_USB3_PHY>; + phy-names = "usb2-phy", + "usb3-phy"; + interconnects = <&aggre1_noc MASTER_USB3_0 QCOM_ICC_TAG_ALWAYS &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY @@ -5692,59 +5699,46 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, interconnect-names = "usb-ddr", "apps-usb"; + iommus = <&apps_smmu 0x40 0>; + power-domains = <&gcc USB30_PRIM_GDSC>; required-opps = <&rpmhpd_opp_nom>; - #address-cells = <2>; - #size-cells = <2>; - ranges; + snps,hird-threshold = /bits/ 8 <0x0>; + snps,usb2-gadget-lpm-disable; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; + snps,dis-u1-entry-quirk; + snps,dis-u2-entry-quirk; + snps,is-utmi-l1-suspend; + snps,usb3_lpm_capable; + snps,usb2-lpm-disable; + snps,has-lpm-erratum; + tx-fifo-resize; + + dma-coherent; + + #address-cells = <1>; + #size-cells = <0>; status = "disabled"; - usb_1_dwc3: usb@a600000 { - compatible = "snps,dwc3"; - reg = <0 0x0a600000 0 0xcd00>; + ports { + #address-cells = <1>; + #size-cells = <0>; - interrupts = ; + port@0 { + reg = <0>; - iommus = <&apps_smmu 0x40 0>; - - phys = <&usb_1_hsphy>, - <&usb_dp_qmpphy QMP_USB43DP_USB3_PHY>; - phy-names = "usb2-phy", - "usb3-phy"; - - snps,hird-threshold = /bits/ 8 <0x0>; - snps,usb2-gadget-lpm-disable; - snps,dis_u2_susphy_quirk; - snps,dis_enblslpm_quirk; - snps,dis-u1-entry-quirk; - snps,dis-u2-entry-quirk; - snps,is-utmi-l1-suspend; - snps,usb3_lpm_capable; - snps,usb2-lpm-disable; - snps,has-lpm-erratum; - tx-fifo-resize; - - dma-coherent; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - - usb_1_dwc3_hs: endpoint { - }; + usb_1_dwc3_hs: endpoint { }; + }; - port@1 { - reg = <1>; + port@1 { + reg = <1>; - usb_1_dwc3_ss: endpoint { - remote-endpoint = <&usb_dp_qmpphy_usb_ss_in>; - }; + usb_1_dwc3_ss: endpoint { + remote-endpoint = <&usb_dp_qmpphy_usb_ss_in>; }; }; }; From c17ccefb611fdb346eef9be6bfbd0bfd04afa204 Mon Sep 17 00:00:00 2001 From: Sricharan Ramabadhran Date: Mon, 11 Aug 2025 14:39:51 +0530 Subject: [PATCH 00218/11391] dt-bindings: clock: ipq5424-apss-clk: Add ipq5424 apss clock controller The CPU core in ipq5424 is clocked by a huayra PLL with RCG support. The RCG and PLL have a separate register space from the GCC. Also the L3 cache has a separate pll and needs to be scaled along with the CPU. Co-developed-by: Md Sadre Alam Signed-off-by: Md Sadre Alam Signed-off-by: Sricharan Ramabadhran [ Added interconnect related changes ] Reviewed-by: Krzysztof Kozlowski Signed-off-by: Varadarajan Narayanan Link: https://lore.kernel.org/r/20250811090954.2854440-2-quic_varada@quicinc.com Signed-off-by: Bjorn Andersson --- .../bindings/clock/qcom,ipq5424-apss-clk.yaml | 55 +++++++++++++++++++ include/dt-bindings/clock/qcom,apss-ipq.h | 6 ++ .../dt-bindings/interconnect/qcom,ipq5424.h | 3 + 3 files changed, 64 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,ipq5424-apss-clk.yaml diff --git a/Documentation/devicetree/bindings/clock/qcom,ipq5424-apss-clk.yaml b/Documentation/devicetree/bindings/clock/qcom,ipq5424-apss-clk.yaml new file mode 100644 index 000000000000..def739fa0a8c --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,ipq5424-apss-clk.yaml @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,ipq5424-apss-clk.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm APSS IPQ5424 Clock Controller + +maintainers: + - Varadarajan Narayanan + +description: + The CPU core in ipq5424 is clocked by a huayra PLL with RCG support. + The RCG and PLL have a separate register space from the GCC. + +properties: + compatible: + enum: + - qcom,ipq5424-apss-clk + + reg: + maxItems: 1 + + clocks: + items: + - description: Reference to the XO clock. + - description: Reference to the GPLL0 clock. + + '#clock-cells': + const: 1 + + '#interconnect-cells': + const: 1 + +required: + - compatible + - reg + - clocks + - '#clock-cells' + - '#interconnect-cells' + +additionalProperties: false + +examples: + - | + #include + + apss_clk: clock-controller@fa80000 { + compatible = "qcom,ipq5424-apss-clk"; + reg = <0x0fa80000 0x20000>; + clocks = <&xo_board>, + <&gcc GPLL0>; + #clock-cells = <1>; + #interconnect-cells = <1>; + }; diff --git a/include/dt-bindings/clock/qcom,apss-ipq.h b/include/dt-bindings/clock/qcom,apss-ipq.h index 77b6e05492e2..0bb41e5efdef 100644 --- a/include/dt-bindings/clock/qcom,apss-ipq.h +++ b/include/dt-bindings/clock/qcom,apss-ipq.h @@ -8,5 +8,11 @@ #define APCS_ALIAS0_CLK_SRC 0 #define APCS_ALIAS0_CORE_CLK 1 +#define APSS_PLL_EARLY 2 +#define APSS_SILVER_CLK_SRC 3 +#define APSS_SILVER_CORE_CLK 4 +#define L3_PLL 5 +#define L3_CLK_SRC 6 +#define L3_CORE_CLK 7 #endif diff --git a/include/dt-bindings/interconnect/qcom,ipq5424.h b/include/dt-bindings/interconnect/qcom,ipq5424.h index a770356112ee..afd7e0683a24 100644 --- a/include/dt-bindings/interconnect/qcom,ipq5424.h +++ b/include/dt-bindings/interconnect/qcom,ipq5424.h @@ -21,4 +21,7 @@ #define MASTER_CNOC_USB 16 #define SLAVE_CNOC_USB 17 +#define MASTER_CPU 0 +#define SLAVE_L3 1 + #endif /* INTERCONNECT_QCOM_IPQ5424_H */ From 5bf83c54bab5eb15a2749c6c52b6f96d425490bc Mon Sep 17 00:00:00 2001 From: Sricharan Ramabadhran Date: Mon, 11 Aug 2025 14:39:52 +0530 Subject: [PATCH 00219/11391] 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 121fcf3c871181edce0708a49d2397cedd6ad21f Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Thu, 7 Aug 2025 18:14:51 +0530 Subject: [PATCH 00220/11391] firmware: qcom: scm: preserve assign_mem() error return value When qcom_scm_assign_mem() fails, the error value is currently being overwritten after it is logged, resulting in the loss of the original error code. Fix this by retaining and returning the original error value as intended. Signed-off-by: Mukesh Ojha Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250807124451.2623019-1-mukesh.ojha@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/firmware/qcom/qcom_scm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index 26cd0458aacd..5243d5abbbe9 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -1119,7 +1119,7 @@ int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz, if (ret) { dev_err(__scm->dev, "Assign memory protection call failed %d\n", ret); - return -EINVAL; + return ret; } *srcvm = next_vm; From aaf5aae37aec74e2dd888d871e258c16f37df041 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Thu, 7 Aug 2025 13:13:09 +0530 Subject: [PATCH 00221/11391] soc: qcom: mdt_loader: Remove unused parameter commit f4e526ff7e38e ("soc: qcom: mdt_loader: Extract PAS operations") move pas specific code from __qcom_mdt_load() to a separate function qcom_mdt_pas_init() after which the pas_init variable became unused in __qcom_mdt_load(). Remove pas_init argument from __qcom_mdt_load(). Reviewed-by: Konrad Dybcio Signed-off-by: Mukesh Ojha Link: https://lore.kernel.org/r/20250807074311.2381713-1-mukesh.ojha@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/mdt_loader.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index 0ca268bdf1f8..dfd15d189087 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -333,7 +333,7 @@ static bool qcom_mdt_bins_are_split(const struct firmware *fw, const char *fw_na static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, const char *fw_name, int pas_id, void *mem_region, phys_addr_t mem_phys, size_t mem_size, - phys_addr_t *reloc_base, bool pas_init) + phys_addr_t *reloc_base) { const struct elf32_phdr *phdrs; const struct elf32_phdr *phdr; @@ -459,7 +459,7 @@ int qcom_mdt_load(struct device *dev, const struct firmware *fw, return ret; return __qcom_mdt_load(dev, fw, firmware, pas_id, mem_region, mem_phys, - mem_size, reloc_base, true); + mem_size, reloc_base); } EXPORT_SYMBOL_GPL(qcom_mdt_load); @@ -482,7 +482,7 @@ int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw, size_t mem_size, phys_addr_t *reloc_base) { return __qcom_mdt_load(dev, fw, firmware, pas_id, mem_region, mem_phys, - mem_size, reloc_base, false); + mem_size, reloc_base); } EXPORT_SYMBOL_GPL(qcom_mdt_load_no_init); From 0daf35da397b083ea0ea5407196bb6bd210530ec Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Thu, 7 Aug 2025 13:13:10 +0530 Subject: [PATCH 00222/11391] soc: qcom: mdt_loader: Remove pas id parameter pas id is not used in qcom_mdt_load_no_init() and it should not be used as it is non-PAS specific function and has no relation to PAS specific mechanism. Reviewed-by: Dikshita Agarwal Acked-by: Jeff Johnson # drivers/net/wireless/ath/ath12k/ahb.c Signed-off-by: Mukesh Ojha Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250807074311.2381713-2-mukesh.ojha@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/media/platform/qcom/venus/firmware.c | 4 ++-- drivers/net/wireless/ath/ath12k/ahb.c | 2 +- drivers/remoteproc/qcom_q6v5_adsp.c | 2 +- drivers/remoteproc/qcom_q6v5_pas.c | 7 +++---- drivers/remoteproc/qcom_q6v5_wcss.c | 2 +- drivers/soc/qcom/mdt_loader.c | 10 ++++------ include/linux/soc/qcom/mdt_loader.h | 7 +++---- 7 files changed, 15 insertions(+), 19 deletions(-) diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c index 66a18830e66d..862d0718f694 100644 --- a/drivers/media/platform/qcom/venus/firmware.c +++ b/drivers/media/platform/qcom/venus/firmware.c @@ -136,8 +136,8 @@ static int venus_load_fw(struct venus_core *core, const char *fwname, ret = qcom_mdt_load(dev, mdt, fwname, VENUS_PAS_ID, mem_va, *mem_phys, *mem_size, NULL); else - ret = qcom_mdt_load_no_init(dev, mdt, fwname, VENUS_PAS_ID, - mem_va, *mem_phys, *mem_size, NULL); + ret = qcom_mdt_load_no_init(dev, mdt, fwname, mem_va, + *mem_phys, *mem_size, NULL); memunmap(mem_va); err_release_fw: diff --git a/drivers/net/wireless/ath/ath12k/ahb.c b/drivers/net/wireless/ath/ath12k/ahb.c index 3b983f4e3268..b30527c402f6 100644 --- a/drivers/net/wireless/ath/ath12k/ahb.c +++ b/drivers/net/wireless/ath/ath12k/ahb.c @@ -414,7 +414,7 @@ static int ath12k_ahb_power_up(struct ath12k_base *ab) goto err_fw2; } - ret = qcom_mdt_load_no_init(dev, fw2, fw2_name, pasid, mem_region, mem_phys, + ret = qcom_mdt_load_no_init(dev, fw2, fw2_name, mem_region, mem_phys, mem_size, &mem_phys); if (ret) { ath12k_err(ab, "Failed to load MDT segments: %d\n", ret); diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c index 94af77baa7a1..e98b7e03162c 100644 --- a/drivers/remoteproc/qcom_q6v5_adsp.c +++ b/drivers/remoteproc/qcom_q6v5_adsp.c @@ -317,7 +317,7 @@ static int adsp_load(struct rproc *rproc, const struct firmware *fw) struct qcom_adsp *adsp = rproc->priv; int ret; - ret = qcom_mdt_load_no_init(adsp->dev, fw, rproc->firmware, 0, + ret = qcom_mdt_load_no_init(adsp->dev, fw, rproc->firmware, adsp->mem_region, adsp->mem_phys, adsp->mem_size, &adsp->mem_reloc); if (ret) diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 02e29171cbbe..55a7da801183 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -242,9 +242,8 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw) goto release_dtb_firmware; ret = qcom_mdt_load_no_init(pas->dev, pas->dtb_firmware, pas->dtb_firmware_name, - pas->dtb_pas_id, pas->dtb_mem_region, - pas->dtb_mem_phys, pas->dtb_mem_size, - &pas->dtb_mem_reloc); + pas->dtb_mem_region, pas->dtb_mem_phys, + pas->dtb_mem_size, &pas->dtb_mem_reloc); if (ret) goto release_dtb_metadata; } @@ -307,7 +306,7 @@ static int qcom_pas_start(struct rproc *rproc) if (ret) goto disable_px_supply; - ret = qcom_mdt_load_no_init(pas->dev, pas->firmware, rproc->firmware, pas->pas_id, + ret = qcom_mdt_load_no_init(pas->dev, pas->firmware, rproc->firmware, pas->mem_region, pas->mem_phys, pas->mem_size, &pas->mem_reloc); if (ret) diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c index 93648734a2f2..07c88623f597 100644 --- a/drivers/remoteproc/qcom_q6v5_wcss.c +++ b/drivers/remoteproc/qcom_q6v5_wcss.c @@ -757,7 +757,7 @@ static int q6v5_wcss_load(struct rproc *rproc, const struct firmware *fw) int ret; ret = qcom_mdt_load_no_init(wcss->dev, fw, rproc->firmware, - 0, wcss->mem_region, wcss->mem_phys, + wcss->mem_region, wcss->mem_phys, wcss->mem_size, &wcss->mem_reloc); if (ret) return ret; diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index dfd15d189087..74c415774657 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -331,7 +331,7 @@ static bool qcom_mdt_bins_are_split(const struct firmware *fw, const char *fw_na } static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, - const char *fw_name, int pas_id, void *mem_region, + const char *fw_name, void *mem_region, phys_addr_t mem_phys, size_t mem_size, phys_addr_t *reloc_base) { @@ -458,7 +458,7 @@ int qcom_mdt_load(struct device *dev, const struct firmware *fw, if (ret) return ret; - return __qcom_mdt_load(dev, fw, firmware, pas_id, mem_region, mem_phys, + return __qcom_mdt_load(dev, fw, firmware, mem_region, mem_phys, mem_size, reloc_base); } EXPORT_SYMBOL_GPL(qcom_mdt_load); @@ -468,7 +468,6 @@ EXPORT_SYMBOL_GPL(qcom_mdt_load); * @dev: device handle to associate resources with * @fw: firmware object for the mdt file * @firmware: name of the firmware, for construction of segment file names - * @pas_id: PAS identifier * @mem_region: allocated memory region to load firmware into * @mem_phys: physical address of allocated memory region * @mem_size: size of the allocated memory region @@ -477,11 +476,10 @@ EXPORT_SYMBOL_GPL(qcom_mdt_load); * Returns 0 on success, negative errno otherwise. */ int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw, - const char *firmware, int pas_id, - void *mem_region, phys_addr_t mem_phys, + const char *firmware, void *mem_region, phys_addr_t mem_phys, size_t mem_size, phys_addr_t *reloc_base) { - return __qcom_mdt_load(dev, fw, firmware, pas_id, mem_region, mem_phys, + return __qcom_mdt_load(dev, fw, firmware, mem_region, mem_phys, mem_size, reloc_base); } EXPORT_SYMBOL_GPL(qcom_mdt_load_no_init); diff --git a/include/linux/soc/qcom/mdt_loader.h b/include/linux/soc/qcom/mdt_loader.h index 9e8e60421192..8ea8230579a2 100644 --- a/include/linux/soc/qcom/mdt_loader.h +++ b/include/linux/soc/qcom/mdt_loader.h @@ -24,7 +24,7 @@ int qcom_mdt_load(struct device *dev, const struct firmware *fw, phys_addr_t *reloc_base); int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw, - const char *fw_name, int pas_id, void *mem_region, + const char *fw_name, void *mem_region, phys_addr_t mem_phys, size_t mem_size, phys_addr_t *reloc_base); void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len, @@ -54,9 +54,8 @@ static inline int qcom_mdt_load(struct device *dev, const struct firmware *fw, static inline int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw, - const char *fw_name, int pas_id, - void *mem_region, phys_addr_t mem_phys, - size_t mem_size, + const char *fw_name, void *mem_region, + phys_addr_t mem_phys, size_t mem_size, phys_addr_t *reloc_base) { return -ENODEV; From 3bf7097bfdd4cf43874d7d41689957bc0d581d47 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Thu, 7 Aug 2025 13:13:11 +0530 Subject: [PATCH 00223/11391] soc: qcom: mdt_loader: Remove unused parameter fw_name in qcom_mdt_bins_are_split() seems unused now, it may have used in the past for logging it but due to code refactor this parameter is unused now. Signed-off-by: Mukesh Ojha Reviewed-by: Jeff Johnson Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250807074311.2381713-3-mukesh.ojha@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/mdt_loader.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index 74c415774657..7522223835f5 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -302,7 +302,7 @@ int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, } EXPORT_SYMBOL_GPL(qcom_mdt_pas_init); -static bool qcom_mdt_bins_are_split(const struct firmware *fw, const char *fw_name) +static bool qcom_mdt_bins_are_split(const struct firmware *fw) { const struct elf32_phdr *phdrs; const struct elf32_hdr *ehdr; @@ -353,7 +353,7 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, if (!mdt_header_valid(fw)) return -EINVAL; - is_split = qcom_mdt_bins_are_split(fw, fw_name); + is_split = qcom_mdt_bins_are_split(fw); ehdr = (struct elf32_hdr *)fw->data; phdrs = (struct elf32_phdr *)(fw->data + ehdr->e_phoff); From c5055d0c8eddfb89ed895ae0642e2a2a0804143d Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Wed, 16 Jul 2025 14:27:30 -0700 Subject: [PATCH 00224/11391] audit: fix indentation in audit_log_exit() Fix two indentation errors in audit_log_exit(). Signed-off-by: Casey Schaufler [PM: subject tweak] Signed-off-by: Paul Moore --- kernel/auditsc.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/kernel/auditsc.c b/kernel/auditsc.c index eb98cd6fe91f..1c29541c8fb6 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -1778,15 +1778,16 @@ static void audit_log_exit(void) axs->target_sessionid[i], &axs->target_ref[i], axs->target_comm[i])) - call_panic = 1; + call_panic = 1; } if (context->target_pid && audit_log_pid_context(context, context->target_pid, context->target_auid, context->target_uid, context->target_sessionid, - &context->target_ref, context->target_comm)) - call_panic = 1; + &context->target_ref, + context->target_comm)) + call_panic = 1; if (context->pwd.dentry && context->pwd.mnt) { ab = audit_log_start(context, GFP_KERNEL, AUDIT_CWD); From d8c09d7b55da39a10c8fd7f2b3a3f88f5f55764c Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Fri, 18 Jul 2025 22:37:34 +0200 Subject: [PATCH 00225/11391] audit: Replace deprecated strcpy() with strscpy() strcpy() is deprecated; use strscpy() instead. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Signed-off-by: Paul Moore --- kernel/audit_tree.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c index b0eae2a3c895..1605df0a171e 100644 --- a/kernel/audit_tree.c +++ b/kernel/audit_tree.c @@ -93,8 +93,10 @@ static struct kmem_cache *audit_tree_mark_cachep __ro_after_init; static struct audit_tree *alloc_tree(const char *s) { struct audit_tree *tree; + size_t sz; - tree = kmalloc(struct_size(tree, pathname, strlen(s) + 1), GFP_KERNEL); + sz = strlen(s) + 1; + tree = kmalloc(struct_size(tree, pathname, sz), GFP_KERNEL); if (tree) { refcount_set(&tree->count, 1); tree->goner = 0; @@ -103,7 +105,7 @@ static struct audit_tree *alloc_tree(const char *s) INIT_LIST_HEAD(&tree->list); INIT_LIST_HEAD(&tree->same_root); tree->root = NULL; - strcpy(tree->pathname, s); + strscpy(tree->pathname, s, sz); } return tree; } From df1145b56c6f92696acec7730694a19fb4c8a174 Mon Sep 17 00:00:00 2001 From: Kieran Moy Date: Sat, 5 Jul 2025 15:48:10 +0800 Subject: [PATCH 00226/11391] audit: fix typo in auditfilter.c comment Correct the misspelling of "searching" (was "serarching") in the function documentation for audit_update_lsm_rules. Found via code inspection, no functional impact. Signed-off-by: Kieran Moy Signed-off-by: Paul Moore --- kernel/auditfilter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index e3f42018ed46..4ed0e10e20b5 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -1440,7 +1440,7 @@ static int update_lsm_rule(struct audit_krule *r) } /* This function will re-initialize the lsm_rule field of all applicable rules. - * It will traverse the filter lists serarching for rules that contain LSM + * It will traverse the filter lists searching for rules that contain LSM * specific filter fields. When such a rule is found, it is copied, the * LSM field is re-initialized, and the old rule is replaced with the * updated rule. */ From ce8370e2e62a903e18be7dd0e0be2eee079501e1 Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Wed, 6 Aug 2025 17:04:07 -0400 Subject: [PATCH 00227/11391] audit: record fanotify event regardless of presence of rules When no audit rules are in place, fanotify event results are unconditionally dropped due to an explicit check for the existence of any audit rules. Given this is a report from another security sub-system, allow it to be recorded regardless of the existence of any audit rules. To test, install and run the fapolicyd daemon with default config. Then as an unprivileged user, create and run a very simple binary that should be denied. Then check for an event with ausearch -m FANOTIFY -ts recent Link: https://issues.redhat.com/browse/RHEL-9065 Signed-off-by: Richard Guy Briggs Signed-off-by: Paul Moore --- include/linux/audit.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/audit.h b/include/linux/audit.h index a394614ccd0b..e3f06eba9c6e 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -527,7 +527,7 @@ static inline void audit_log_kern_module(const char *name) static inline void audit_fanotify(u32 response, struct fanotify_response_info_audit_rule *friar) { - if (!audit_dummy_context()) + if (audit_enabled) __audit_fanotify(response, friar); } From 5f9383bd4168eaf88a673d3eac5d8935a2202846 Mon Sep 17 00:00:00 2001 From: Yue Haibing Date: Wed, 23 Jul 2025 20:23:04 +0800 Subject: [PATCH 00228/11391] selinux: Remove unused function selinux_policycap_netif_wildcard() This is unused since commit a3d3043ef24a ("selinux: get netif_wildcard policycap from policy instead of cache"). Signed-off-by: Yue Haibing Acked-by: Stephen Smalley Signed-off-by: Paul Moore --- security/selinux/include/security.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 8201e6a3ac0f..7f19972f7922 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -203,12 +203,6 @@ static inline bool selinux_policycap_netlink_xperm(void) selinux_state.policycap[POLICYDB_CAP_NETLINK_XPERM]); } -static inline bool selinux_policycap_netif_wildcard(void) -{ - return READ_ONCE( - selinux_state.policycap[POLICYDB_CAP_NETIF_WILDCARD]); -} - struct selinux_policy_convert_data; struct selinux_load_state { From d4e8dc8e8b34771b0a3d474d243bcfcbddef8612 Mon Sep 17 00:00:00 2001 From: Tianjia Zhang Date: Tue, 29 Jul 2025 17:10:44 +0800 Subject: [PATCH 00229/11391] selinux: use a consistent method to get full socket from skb In order to maintain code consistency and readability, skb_to_full_sk() is used to get full socket from skb. Signed-off-by: Tianjia Zhang Acked-by: Stephen Smalley Signed-off-by: Paul Moore --- security/selinux/hooks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index c95a5874bf7d..e474cd7398ef 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -5885,7 +5885,7 @@ static unsigned int selinux_ip_output(void *priv, struct sk_buff *skb, /* we do this in the LOCAL_OUT path and not the POST_ROUTING path * because we want to make sure we apply the necessary labeling * before IPsec is applied so we can leverage AH protection */ - sk = sk_to_full_sk(skb->sk); + sk = skb_to_full_sk(skb); if (sk) { struct sk_security_struct *sksec; From fbec18dc9940a89e094bae890b8dc0af00ddc4ff Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sun, 10 Aug 2025 16:38:50 +0200 Subject: [PATCH 00230/11391] spi: spi-qpic-snand: remove unused 'dev' member of struct 'qpic_ecc' The 'dev' member of the 'qpic_ecc' structure is never used in the code so remove that. No functional changes. Signed-off-by: Gabor Juhos Reviewed-by: Konrad Dybcio Link: https://patch.msgid.link/20250810-qpic-snand-qpic_ecc-cleanup-v1-1-33a6b2bcbc67@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-qpic-snand.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c index 0ceaad7dba3c..53fe248a4b9a 100644 --- a/drivers/spi/spi-qpic-snand.c +++ b/drivers/spi/spi-qpic-snand.c @@ -78,7 +78,6 @@ struct qcom_ecc_stats { }; struct qpic_ecc { - struct device *dev; int ecc_bytes_hw; int spare_bytes; int bbm_size; From 6b7e2aa50bdaf88cd4c2a5e2059a7bf32d85a8b1 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sun, 10 Aug 2025 16:38:51 +0200 Subject: [PATCH 00231/11391] spi: spi-qpic-snand: remove 'clr*status' members of struct 'qpic_ecc' In the qcom_spi_ecc_init_ctx_pipelined() function, the 'clrflashstatus' and the 'clrreadstatus' members of the ECC context gets initialized with constant values. Then these values are used by several functions to set the corresponding members in the register cache. Because the values are never modified, change the code to set the those directly in the register cache by the qcom_spi_ecc_init_ctx_pipelined() function, and remove the repetitive code from the other functions to reduce code duplication. Also, remove the respective members from the 'qpic_ecc' structure as those became unused due to the change. No functional changes intended. Signed-off-by: Gabor Juhos Link: https://patch.msgid.link/20250810-qpic-snand-qpic_ecc-cleanup-v1-2-33a6b2bcbc67@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-qpic-snand.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c index 53fe248a4b9a..22fb59dbe2a0 100644 --- a/drivers/spi/spi-qpic-snand.c +++ b/drivers/spi/spi-qpic-snand.c @@ -94,8 +94,6 @@ struct qpic_ecc { u32 cfg1_raw; u32 ecc_buf_cfg; u32 ecc_bch_cfg; - u32 clrflashstatus; - u32 clrreadstatus; bool bch_enabled; }; @@ -381,12 +379,12 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) FIELD_PREP(ECC_PARITY_SIZE_BYTES_BCH_MASK, ecc_cfg->ecc_bytes_hw); ecc_cfg->ecc_buf_cfg = FIELD_PREP(NUM_STEPS_MASK, 0x203); - ecc_cfg->clrflashstatus = FS_READY_BSY_N; - ecc_cfg->clrreadstatus = 0xc0; conf->step_size = ecc_cfg->step_size; conf->strength = ecc_cfg->strength; + snandc->regs->clrflashstatus = cpu_to_le32(FS_READY_BSY_N); + snandc->regs->clrreadstatus = cpu_to_le32(0xc0); snandc->regs->erased_cw_detect_cfg_clr = cpu_to_le32(CLR_ERASED_PAGE_DET); snandc->regs->erased_cw_detect_cfg_set = cpu_to_le32(SET_ERASED_PAGE_DET); @@ -598,8 +596,6 @@ static int qcom_spi_read_last_cw(struct qcom_nand_controller *snandc, snandc->regs->cfg0 = cpu_to_le32(cfg0); snandc->regs->cfg1 = cpu_to_le32(cfg1); snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg); - snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus); - snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus); snandc->regs->exec = cpu_to_le32(1); qcom_spi_set_read_loc(snandc, num_cw - 1, 0, 0, ecc_cfg->cw_size, 1); @@ -733,8 +729,6 @@ static int qcom_spi_read_cw_raw(struct qcom_nand_controller *snandc, u8 *data_bu snandc->regs->cfg0 = cpu_to_le32(cfg0); snandc->regs->cfg1 = cpu_to_le32(cfg1); snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg); - snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus); - snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus); snandc->regs->exec = cpu_to_le32(1); qcom_spi_set_read_loc(snandc, raw_cw, 0, 0, ecc_cfg->cw_size, 1); @@ -849,8 +843,6 @@ static int qcom_spi_read_page_ecc(struct qcom_nand_controller *snandc, snandc->regs->cfg0 = cpu_to_le32(cfg0); snandc->regs->cfg1 = cpu_to_le32(cfg1); snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg); - snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus); - snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus); snandc->regs->exec = cpu_to_le32(1); qcom_spi_set_read_loc(snandc, 0, 0, 0, ecc_cfg->cw_data, 1); @@ -942,8 +934,6 @@ static int qcom_spi_read_page_oob(struct qcom_nand_controller *snandc, snandc->regs->cfg0 = cpu_to_le32(cfg0); snandc->regs->cfg1 = cpu_to_le32(cfg1); snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg); - snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus); - snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus); snandc->regs->exec = cpu_to_le32(1); qcom_spi_set_read_loc(snandc, 0, 0, 0, ecc_cfg->cw_data, 1); @@ -1063,8 +1053,6 @@ static int qcom_spi_program_raw(struct qcom_nand_controller *snandc, snandc->regs->cfg0 = cpu_to_le32(cfg0); snandc->regs->cfg1 = cpu_to_le32(cfg1); snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg); - snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus); - snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus); snandc->regs->exec = cpu_to_le32(1); qcom_spi_config_page_write(snandc); From 60a63913fd69bae76a3420c97ef40e865792a5b8 Mon Sep 17 00:00:00 2001 From: Yijie Yang Date: Mon, 4 Aug 2025 09:37:05 +0800 Subject: [PATCH 00232/11391] firmware: qcom: scm: Allow QSEECOM on HAMOA-IOT-EVK Add the Hamoa-IoT-EVK board to the list to enable access to EFI variables. Signed-off-by: Yijie Yang Link: https://lore.kernel.org/r/20250804-hamoa_initial-v4-2-19edbb28677b@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/firmware/qcom/qcom_scm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index 5243d5abbbe9..edeae6cdcf31 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -2006,6 +2006,7 @@ static const struct of_device_id qcom_scm_qseecom_allowlist[] __maybe_unused = { { .compatible = "microsoft,blackrock" }, { .compatible = "microsoft,romulus13", }, { .compatible = "microsoft,romulus15", }, + { .compatible = "qcom,hamoa-iot-evk" }, { .compatible = "qcom,sc8180x-primus" }, { .compatible = "qcom,x1e001de-devkit" }, { .compatible = "qcom,x1e80100-crd" }, From 6ef38b0c16c20701fb8a06d2d2114080fbc785ad Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Sat, 2 Aug 2025 13:44:44 +0200 Subject: [PATCH 00233/11391] 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 00234/11391] 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 6656ae4df1a6ad6dfb5c4ce4c76136a42abb9bf4 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 7 Aug 2025 15:16:28 -0600 Subject: [PATCH 00235/11391] docs: kdoc: consolidate the stripping of private struct/union members There were two locations duplicating the logic of stripping private members and associated comments; coalesce them into one, and add some comments describing what's going on. Output change: we now no longer add extraneous white space around macro definitions. Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250807211639.47286-2-corbet@lwn.net --- scripts/lib/kdoc/kdoc_parser.py | 40 ++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py index c3fe4bd5eab4..93fcd8807aa8 100644 --- a/scripts/lib/kdoc/kdoc_parser.py +++ b/scripts/lib/kdoc/kdoc_parser.py @@ -81,6 +81,21 @@ multi_space = KernRe(r'\s\s+') def trim_whitespace(s): return multi_space.sub(' ', s.strip()) +# +# Remove struct/enum members that have been marked "private". +# +def trim_private_members(text): + # + # First look for a "public:" block that ends a private region, then + # handle the "private until the end" case. + # + text = KernRe(r'/\*\s*private:.*?/\*\s*public:.*?\*/', flags=re.S).sub('', text) + text = KernRe(r'/\*\s*private:.*', flags=re.S).sub('', text) + # + # We needed the comments to do the above, but now we can take them out. + # + return KernRe(r'\s*/\*.*?\*/\s*', flags=re.S).sub('', text).strip() + class state: """ State machine enums @@ -568,12 +583,6 @@ class KernelDoc: args_pattern = r'([^,)]+)' sub_prefixes = [ - (KernRe(r'\/\*\s*private:.*?\/\*\s*public:.*?\*\/', re.S | re.I), ''), - (KernRe(r'\/\*\s*private:.*', re.S | re.I), ''), - - # Strip comments - (KernRe(r'\/\*.*?\*\/', re.S), ''), - # Strip attributes (attribute, ' '), (KernRe(r'\s*__aligned\s*\([^;]*\)', re.S), ' '), @@ -648,6 +657,7 @@ class KernelDoc: (re.compile(r'\bSTRUCT_GROUP\('), r'\1'), ] + members = trim_private_members(members) for search, sub in sub_prefixes: members = search.sub(sub, members) @@ -797,24 +807,18 @@ class KernelDoc: """ Stores an enum inside self.entries array. """ - - # Ignore members marked private - proto = KernRe(r'\/\*\s*private:.*?\/\*\s*public:.*?\*\/', flags=re.S).sub('', proto) - proto = KernRe(r'\/\*\s*private:.*}', flags=re.S).sub('}', proto) - - # Strip comments - proto = KernRe(r'\/\*.*?\*\/', flags=re.S).sub('', proto) - - # Strip #define macros inside enums + # + # Strip preprocessor directives. Note that this depends on the + # trailing semicolon we added in process_proto_type(). + # proto = KernRe(r'#\s*((define|ifdef|if)\s+|endif)[^;]*;', flags=re.S).sub('', proto) - # # Parse out the name and members of the enum. Typedef form first. # r = KernRe(r'typedef\s+enum\s*\{(.*)\}\s*(\w*)\s*;') if r.search(proto): declaration_name = r.group(2) - members = r.group(1).rstrip() + members = trim_private_members(r.group(1)) # # Failing that, look for a straight enum # @@ -822,7 +826,7 @@ class KernelDoc: r = KernRe(r'enum\s+(\w*)\s*\{(.*)\}') if r.match(proto): declaration_name = r.group(1) - members = r.group(2).rstrip() + members = trim_private_members(r.group(2)) # # OK, this isn't going to work. # From 259feba4dde78f165b03e231ea9985dfe600c202 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 7 Aug 2025 15:16:29 -0600 Subject: [PATCH 00236/11391] docs: kdoc: Move a regex line in dump_struct() The complex struct_members regex was defined far from its use; bring the two together. Remove some extraneous backslashes while making the move. Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250807211639.47286-3-corbet@lwn.net --- scripts/lib/kdoc/kdoc_parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py index 93fcd8807aa8..aa6d11bf29b1 100644 --- a/scripts/lib/kdoc/kdoc_parser.py +++ b/scripts/lib/kdoc/kdoc_parser.py @@ -551,7 +551,6 @@ class KernelDoc: ] definition_body = r'\{(.*)\}\s*' + "(?:" + '|'.join(qualifiers) + ")?" - struct_members = KernRe(type_pattern + r'([^\{\};]+)(\{)([^\{\}]*)(\})([^\{\}\;]*)(\;)') # Extract struct/union definition members = None @@ -683,6 +682,7 @@ class KernelDoc: # So, we need to have an extra loop on Python to override such # re limitation. + struct_members = KernRe(type_pattern + r'([^\{\};]+)(\{)([^\{\}]*)(\})([^\{\};]*)(;)') while True: tuples = struct_members.findall(members) if not tuples: From 5fd513f01169ae93d202b8c30f0837096664e7d7 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 7 Aug 2025 15:16:30 -0600 Subject: [PATCH 00237/11391] docs: kdoc: backslashectomy in kdoc_parser A lot of the regular expressions in this file have extraneous backslashes that may have been needed in Perl, but aren't helpful here. Take them out to reduce slightly the visual noise. Escaping of (){}[] has been left in place, even when unnecessary, for visual clarity. Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250807211639.47286-4-corbet@lwn.net --- scripts/lib/kdoc/kdoc_parser.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py index aa6d11bf29b1..14ded23f11e0 100644 --- a/scripts/lib/kdoc/kdoc_parser.py +++ b/scripts/lib/kdoc/kdoc_parser.py @@ -46,7 +46,7 @@ doc_decl = doc_com + KernRe(r'(\w+)', cache=False) known_section_names = 'description|context|returns?|notes?|examples?' known_sections = KernRe(known_section_names, flags = re.I) doc_sect = doc_com + \ - KernRe(r'\s*(\@[.\w]+|\@\.\.\.|' + known_section_names + r')\s*:([^:].*)?$', + KernRe(r'\s*(@[.\w]+|@\.\.\.|' + known_section_names + r')\s*:([^:].*)?$', flags=re.I, cache=False) doc_content = doc_com_body + KernRe(r'(.*)', cache=False) @@ -60,7 +60,7 @@ attribute = KernRe(r"__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)", export_symbol = KernRe(r'^\s*EXPORT_SYMBOL(_GPL)?\s*\(\s*(\w+)\s*\)\s*', cache=False) export_symbol_ns = KernRe(r'^\s*EXPORT_SYMBOL_NS(_GPL)?\s*\(\s*(\w+)\s*,\s*"\S+"\)\s*', cache=False) -type_param = KernRe(r"\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)", cache=False) +type_param = KernRe(r"@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)", cache=False) # # Tests for the beginning of a kerneldoc block in its various forms. @@ -405,7 +405,7 @@ class KernelDoc: for arg in args.split(splitter): # Strip comments - arg = KernRe(r'\/\*.*\*\/').sub('', arg) + arg = KernRe(r'/\*.*\*/').sub('', arg) # Ignore argument attributes arg = KernRe(r'\sPOS0?\s').sub(' ', arg) @@ -428,7 +428,7 @@ class KernelDoc: arg = arg.replace('#', ',') - r = KernRe(r'[^\(]+\(\*?\s*([\w\[\]\.]*)\s*\)') + r = KernRe(r'[^\(]+\(\*?\s*([\w\[\].]*)\s*\)') if r.match(arg): param = r.group(1) else: @@ -443,7 +443,7 @@ class KernelDoc: # Array-of-pointers arg = arg.replace('#', ',') - r = KernRe(r'[^\(]+\(\s*\*\s*([\w\[\]\.]*?)\s*(\s*\[\s*[\w]+\s*\]\s*)*\)') + r = KernRe(r'[^\(]+\(\s*\*\s*([\w\[\].]*?)\s*(\s*\[\s*[\w]+\s*\]\s*)*\)') if r.match(arg): param = r.group(1) else: @@ -709,7 +709,7 @@ class KernelDoc: if not arg: continue - r = KernRe(r'^([^\(]+\(\*?\s*)([\w\.]*)(\s*\).*)') + r = KernRe(r'^([^\(]+\(\*?\s*)([\w.]*)(\s*\).*)') if r.match(arg): # Pointer-to-function dtype = r.group(1) @@ -1044,7 +1044,7 @@ class KernelDoc: Stores a typedef inside self.entries array. """ - typedef_type = r'((?:\s+[\w\*]+\b){0,7}\s+(?:\w+\b|\*+))\s*' + typedef_type = r'((?:\s+[\w*]+\b){0,7}\s+(?:\w+\b|\*+))\s*' typedef_ident = r'\*?\s*(\w\S+)\s*' typedef_args = r'\s*\((.*)\);' @@ -1265,7 +1265,7 @@ class KernelDoc: self.dump_section() # Look for doc_com + + doc_end: - r = KernRe(r'\s*\*\s*[a-zA-Z_0-9:\.]+\*/') + r = KernRe(r'\s*\*\s*[a-zA-Z_0-9:.]+\*/') if r.match(line): self.emit_msg(ln, f"suspicious ending line: {line}") @@ -1476,7 +1476,7 @@ class KernelDoc: """Ancillary routine to process a function prototype""" # strip C99-style comments to end of line - line = KernRe(r"\/\/.*$", re.S).sub('', line) + line = KernRe(r"//.*$", re.S).sub('', line) # # Soak up the line's worth of prototype text, stopping at { or ; if present. # From 64cf83bcd3217a9583caeb404ff136366a46705c Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 7 Aug 2025 15:16:31 -0600 Subject: [PATCH 00238/11391] docs: kdoc: move the prefix transforms out of dump_struct() dump_struct is one of the longest functions in the kdoc_parser class, making it hard to read and reason about. Move the definition of the prefix transformations out of the function, join them with the definition of "attribute" (which was defined at the top of the file but only used here), and reformat the code slightly for shorter line widths. Just code movement in the end. Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250807211639.47286-5-corbet@lwn.net --- scripts/lib/kdoc/kdoc_parser.py | 179 +++++++++++++++++--------------- 1 file changed, 96 insertions(+), 83 deletions(-) diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py index 14ded23f11e0..3d007d200da6 100644 --- a/scripts/lib/kdoc/kdoc_parser.py +++ b/scripts/lib/kdoc/kdoc_parser.py @@ -54,8 +54,6 @@ doc_inline_start = KernRe(r'^\s*/\*\*\s*$', cache=False) doc_inline_sect = KernRe(r'\s*\*\s*(@\s*[\w][\w\.]*\s*):(.*)', cache=False) doc_inline_end = KernRe(r'^\s*\*/\s*$', cache=False) doc_inline_oneline = KernRe(r'^\s*/\*\*\s*(@[\w\s]+):\s*(.*)\s*\*/\s*$', cache=False) -attribute = KernRe(r"__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)", - flags=re.I | re.S, cache=False) export_symbol = KernRe(r'^\s*EXPORT_SYMBOL(_GPL)?\s*\(\s*(\w+)\s*\)\s*', cache=False) export_symbol_ns = KernRe(r'^\s*EXPORT_SYMBOL_NS(_GPL)?\s*\(\s*(\w+)\s*,\s*"\S+"\)\s*', cache=False) @@ -74,6 +72,97 @@ doc_begin_func = KernRe(str(doc_com) + # initial " * ' r'(?:[-:].*)?$', # description (not captured) cache = False) +# +# Here begins a long set of transformations to turn structure member prefixes +# and macro invocations into something we can parse and generate kdoc for. +# +struct_attribute = KernRe(r"__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)", + flags=re.I | re.S, cache=False) +struct_args_pattern = r'([^,)]+)' + +struct_prefixes = [ + # Strip attributes + (struct_attribute, ' '), + (KernRe(r'\s*__aligned\s*\([^;]*\)', re.S), ' '), + (KernRe(r'\s*__counted_by\s*\([^;]*\)', re.S), ' '), + (KernRe(r'\s*__counted_by_(le|be)\s*\([^;]*\)', re.S), ' '), + (KernRe(r'\s*__packed\s*', re.S), ' '), + (KernRe(r'\s*CRYPTO_MINALIGN_ATTR', re.S), ' '), + (KernRe(r'\s*____cacheline_aligned_in_smp', re.S), ' '), + (KernRe(r'\s*____cacheline_aligned', re.S), ' '), + # + # Unwrap struct_group macros based on this definition: + # __struct_group(TAG, NAME, ATTRS, MEMBERS...) + # which has variants like: struct_group(NAME, MEMBERS...) + # Only MEMBERS arguments require documentation. + # + # Parsing them happens on two steps: + # + # 1. drop struct group arguments that aren't at MEMBERS, + # storing them as STRUCT_GROUP(MEMBERS) + # + # 2. remove STRUCT_GROUP() ancillary macro. + # + # The original logic used to remove STRUCT_GROUP() using an + # advanced regex: + # + # \bSTRUCT_GROUP(\(((?:(?>[^)(]+)|(?1))*)\))[^;]*; + # + # with two patterns that are incompatible with + # Python re module, as it has: + # + # - a recursive pattern: (?1) + # - an atomic grouping: (?>...) + # + # I tried a simpler version: but it didn't work either: + # \bSTRUCT_GROUP\(([^\)]+)\)[^;]*; + # + # As it doesn't properly match the end parenthesis on some cases. + # + # So, a better solution was crafted: there's now a NestedMatch + # class that ensures that delimiters after a search are properly + # matched. So, the implementation to drop STRUCT_GROUP() will be + # handled in separate. + # + (KernRe(r'\bstruct_group\s*\(([^,]*,)', re.S), r'STRUCT_GROUP('), + (KernRe(r'\bstruct_group_attr\s*\(([^,]*,){2}', re.S), r'STRUCT_GROUP('), + (KernRe(r'\bstruct_group_tagged\s*\(([^,]*),([^,]*),', re.S), r'struct \1 \2; STRUCT_GROUP('), + (KernRe(r'\b__struct_group\s*\(([^,]*,){3}', re.S), r'STRUCT_GROUP('), + # + # Replace macros + # + # TODO: use NestedMatch for FOO($1, $2, ...) matches + # + # it is better to also move those to the NestedMatch logic, + # to ensure that parenthesis will be properly matched. + # + (KernRe(r'__ETHTOOL_DECLARE_LINK_MODE_MASK\s*\(([^\)]+)\)', re.S), + r'DECLARE_BITMAP(\1, __ETHTOOL_LINK_MODE_MASK_NBITS)'), + (KernRe(r'DECLARE_PHY_INTERFACE_MASK\s*\(([^\)]+)\)', re.S), + r'DECLARE_BITMAP(\1, PHY_INTERFACE_MODE_MAX)'), + (KernRe(r'DECLARE_BITMAP\s*\(' + struct_args_pattern + r',\s*' + struct_args_pattern + r'\)', + re.S), r'unsigned long \1[BITS_TO_LONGS(\2)]'), + (KernRe(r'DECLARE_HASHTABLE\s*\(' + struct_args_pattern + r',\s*' + struct_args_pattern + r'\)', + re.S), r'unsigned long \1[1 << ((\2) - 1)]'), + (KernRe(r'DECLARE_KFIFO\s*\(' + struct_args_pattern + r',\s*' + struct_args_pattern + + r',\s*' + struct_args_pattern + r'\)', re.S), r'\2 *\1'), + (KernRe(r'DECLARE_KFIFO_PTR\s*\(' + struct_args_pattern + r',\s*' + + struct_args_pattern + r'\)', re.S), r'\2 *\1'), + (KernRe(r'(?:__)?DECLARE_FLEX_ARRAY\s*\(' + struct_args_pattern + r',\s*' + + struct_args_pattern + r'\)', re.S), r'\1 \2[]'), + (KernRe(r'DEFINE_DMA_UNMAP_ADDR\s*\(' + struct_args_pattern + r'\)', re.S), r'dma_addr_t \1'), + (KernRe(r'DEFINE_DMA_UNMAP_LEN\s*\(' + struct_args_pattern + r'\)', re.S), r'__u32 \1'), +] +# +# Regexes here are guaranteed to have the end limiter matching +# the start delimiter. Yet, right now, only one replace group +# is allowed. +# +struct_nested_prefixes = [ + (re.compile(r'\bSTRUCT_GROUP\('), r'\1'), +] + + # # A little helper to get rid of excess white space # @@ -578,91 +667,15 @@ class KernelDoc: self.emit_msg(ln, f"expecting prototype for {decl_type} {self.entry.identifier}. Prototype was for {decl_type} {declaration_name} instead\n") return - - args_pattern = r'([^,)]+)' - - sub_prefixes = [ - # Strip attributes - (attribute, ' '), - (KernRe(r'\s*__aligned\s*\([^;]*\)', re.S), ' '), - (KernRe(r'\s*__counted_by\s*\([^;]*\)', re.S), ' '), - (KernRe(r'\s*__counted_by_(le|be)\s*\([^;]*\)', re.S), ' '), - (KernRe(r'\s*__packed\s*', re.S), ' '), - (KernRe(r'\s*CRYPTO_MINALIGN_ATTR', re.S), ' '), - (KernRe(r'\s*____cacheline_aligned_in_smp', re.S), ' '), - (KernRe(r'\s*____cacheline_aligned', re.S), ' '), - - # Unwrap struct_group macros based on this definition: - # __struct_group(TAG, NAME, ATTRS, MEMBERS...) - # which has variants like: struct_group(NAME, MEMBERS...) - # Only MEMBERS arguments require documentation. - # - # Parsing them happens on two steps: - # - # 1. drop struct group arguments that aren't at MEMBERS, - # storing them as STRUCT_GROUP(MEMBERS) - # - # 2. remove STRUCT_GROUP() ancillary macro. - # - # The original logic used to remove STRUCT_GROUP() using an - # advanced regex: - # - # \bSTRUCT_GROUP(\(((?:(?>[^)(]+)|(?1))*)\))[^;]*; - # - # with two patterns that are incompatible with - # Python re module, as it has: - # - # - a recursive pattern: (?1) - # - an atomic grouping: (?>...) - # - # I tried a simpler version: but it didn't work either: - # \bSTRUCT_GROUP\(([^\)]+)\)[^;]*; - # - # As it doesn't properly match the end parenthesis on some cases. - # - # So, a better solution was crafted: there's now a NestedMatch - # class that ensures that delimiters after a search are properly - # matched. So, the implementation to drop STRUCT_GROUP() will be - # handled in separate. - - (KernRe(r'\bstruct_group\s*\(([^,]*,)', re.S), r'STRUCT_GROUP('), - (KernRe(r'\bstruct_group_attr\s*\(([^,]*,){2}', re.S), r'STRUCT_GROUP('), - (KernRe(r'\bstruct_group_tagged\s*\(([^,]*),([^,]*),', re.S), r'struct \1 \2; STRUCT_GROUP('), - (KernRe(r'\b__struct_group\s*\(([^,]*,){3}', re.S), r'STRUCT_GROUP('), - - # Replace macros - # - # TODO: use NestedMatch for FOO($1, $2, ...) matches - # - # it is better to also move those to the NestedMatch logic, - # to ensure that parenthesis will be properly matched. - - (KernRe(r'__ETHTOOL_DECLARE_LINK_MODE_MASK\s*\(([^\)]+)\)', re.S), r'DECLARE_BITMAP(\1, __ETHTOOL_LINK_MODE_MASK_NBITS)'), - (KernRe(r'DECLARE_PHY_INTERFACE_MASK\s*\(([^\)]+)\)', re.S), r'DECLARE_BITMAP(\1, PHY_INTERFACE_MODE_MAX)'), - (KernRe(r'DECLARE_BITMAP\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'unsigned long \1[BITS_TO_LONGS(\2)]'), - (KernRe(r'DECLARE_HASHTABLE\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'unsigned long \1[1 << ((\2) - 1)]'), - (KernRe(r'DECLARE_KFIFO\s*\(' + args_pattern + r',\s*' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'\2 *\1'), - (KernRe(r'DECLARE_KFIFO_PTR\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'\2 *\1'), - (KernRe(r'(?:__)?DECLARE_FLEX_ARRAY\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'\1 \2[]'), - (KernRe(r'DEFINE_DMA_UNMAP_ADDR\s*\(' + args_pattern + r'\)', re.S), r'dma_addr_t \1'), - (KernRe(r'DEFINE_DMA_UNMAP_LEN\s*\(' + args_pattern + r'\)', re.S), r'__u32 \1'), - ] - - # Regexes here are guaranteed to have the end limiter matching - # the start delimiter. Yet, right now, only one replace group - # is allowed. - - sub_nested_prefixes = [ - (re.compile(r'\bSTRUCT_GROUP\('), r'\1'), - ] - + # + # Go through the list of members applying all of our transformations. + # members = trim_private_members(members) - for search, sub in sub_prefixes: + for search, sub in struct_prefixes: members = search.sub(sub, members) nested = NestedMatch() - - for search, sub in sub_nested_prefixes: + for search, sub in struct_nested_prefixes: members = nested.sub(search, sub, members) # Keeps the original declaration as-is From 0f7344129434a6b44d4abb5080a9d67dd734ee07 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 7 Aug 2025 15:16:32 -0600 Subject: [PATCH 00239/11391] docs: kdoc: split top-level prototype parsing out of dump_struct() Move the initial split of the prototype into its own function in the ongoing effort to cut dump_struct() down to size. Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250807211639.47286-6-corbet@lwn.net --- scripts/lib/kdoc/kdoc_parser.py | 43 +++++++++++++++------------------ 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py index 3d007d200da6..ab896dcd9572 100644 --- a/scripts/lib/kdoc/kdoc_parser.py +++ b/scripts/lib/kdoc/kdoc_parser.py @@ -624,13 +624,11 @@ class KernelDoc: self.emit_msg(ln, f"No description found for return value of '{declaration_name}'") - def dump_struct(self, ln, proto): - """ - Store an entry for an struct or union - """ - + # + # Split apart a structure prototype; returns (struct|union, name, members) or None + # + def split_struct_proto(self, proto): type_pattern = r'(struct|union)' - qualifiers = [ "__attribute__", "__packed", @@ -638,34 +636,33 @@ class KernelDoc: "____cacheline_aligned_in_smp", "____cacheline_aligned", ] - definition_body = r'\{(.*)\}\s*' + "(?:" + '|'.join(qualifiers) + ")?" - # Extract struct/union definition - members = None - declaration_name = None - decl_type = None - r = KernRe(type_pattern + r'\s+(\w+)\s*' + definition_body) if r.search(proto): - decl_type = r.group(1) - declaration_name = r.group(2) - members = r.group(3) + return (r.group(1), r.group(2), r.group(3)) else: r = KernRe(r'typedef\s+' + type_pattern + r'\s*' + definition_body + r'\s*(\w+)\s*;') - if r.search(proto): - decl_type = r.group(1) - declaration_name = r.group(3) - members = r.group(2) + return (r.group(1), r.group(3), r.group(2)) + return None - if not members: + def dump_struct(self, ln, proto): + """ + Store an entry for an struct or union + """ + # + # Do the basic parse to get the pieces of the declaration. + # + struct_parts = self.split_struct_proto(proto) + if not struct_parts: self.emit_msg(ln, f"{proto} error: Cannot parse struct or union!") return + decl_type, declaration_name, members = struct_parts if self.entry.identifier != declaration_name: - self.emit_msg(ln, - f"expecting prototype for {decl_type} {self.entry.identifier}. Prototype was for {decl_type} {declaration_name} instead\n") + self.emit_msg(ln, f"expecting prototype for {decl_type} {self.entry.identifier}. " + f"Prototype was for {decl_type} {declaration_name} instead\n") return # # Go through the list of members applying all of our transformations. @@ -695,7 +692,7 @@ class KernelDoc: # So, we need to have an extra loop on Python to override such # re limitation. - struct_members = KernRe(type_pattern + r'([^\{\};]+)(\{)([^\{\}]*)(\})([^\{\};]*)(;)') + struct_members = KernRe(r'(struct|union)([^\{\};]+)(\{)([^\{\}]*)(\})([^\{\};]*)(;)') while True: tuples = struct_members.findall(members) if not tuples: From 77e3c875f0a83d9192079e88d8569ac36c6b6bea Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 7 Aug 2025 15:16:33 -0600 Subject: [PATCH 00240/11391] docs: kdoc: split struct-member rewriting out of dump_struct() The massive loop that massages struct members shares no data with the rest of dump_struct(); split it out into its own function. Code movement only, no other changes. Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250807211639.47286-7-corbet@lwn.net --- scripts/lib/kdoc/kdoc_parser.py | 65 +++++++++++++++++---------------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py index ab896dcd9572..fbd7f6ce3360 100644 --- a/scripts/lib/kdoc/kdoc_parser.py +++ b/scripts/lib/kdoc/kdoc_parser.py @@ -647,37 +647,7 @@ class KernelDoc: return (r.group(1), r.group(3), r.group(2)) return None - def dump_struct(self, ln, proto): - """ - Store an entry for an struct or union - """ - # - # Do the basic parse to get the pieces of the declaration. - # - struct_parts = self.split_struct_proto(proto) - if not struct_parts: - self.emit_msg(ln, f"{proto} error: Cannot parse struct or union!") - return - decl_type, declaration_name, members = struct_parts - - if self.entry.identifier != declaration_name: - self.emit_msg(ln, f"expecting prototype for {decl_type} {self.entry.identifier}. " - f"Prototype was for {decl_type} {declaration_name} instead\n") - return - # - # Go through the list of members applying all of our transformations. - # - members = trim_private_members(members) - for search, sub in struct_prefixes: - members = search.sub(sub, members) - - nested = NestedMatch() - for search, sub in struct_nested_prefixes: - members = nested.sub(search, sub, members) - - # Keeps the original declaration as-is - declaration = members - + def rewrite_struct_members(self, members): # Split nested struct/union elements # # This loop was simpler at the original kernel-doc perl version, as @@ -768,6 +738,39 @@ class KernelDoc: newmember += f"{dtype} {s_id}.{name}; " members = members.replace(oldmember, newmember) + return members + + def dump_struct(self, ln, proto): + """ + Store an entry for an struct or union + """ + # + # Do the basic parse to get the pieces of the declaration. + # + struct_parts = self.split_struct_proto(proto) + if not struct_parts: + self.emit_msg(ln, f"{proto} error: Cannot parse struct or union!") + return + decl_type, declaration_name, members = struct_parts + + if self.entry.identifier != declaration_name: + self.emit_msg(ln, f"expecting prototype for {decl_type} {self.entry.identifier}. " + f"Prototype was for {decl_type} {declaration_name} instead\n") + return + # + # Go through the list of members applying all of our transformations. + # + members = trim_private_members(members) + for search, sub in struct_prefixes: + members = search.sub(sub, members) + + nested = NestedMatch() + for search, sub in struct_nested_prefixes: + members = nested.sub(search, sub, members) + + # Keeps the original declaration as-is + declaration = members + members = self.rewrite_struct_members(members) # Ignore other nested elements, like enums members = re.sub(r'(\{[^\{\}]*\})', '', members) From f8208676c1c85c0b91e726954c05f5859b890ccb Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 7 Aug 2025 15:16:34 -0600 Subject: [PATCH 00241/11391] docs: kdoc: rework the rewrite_struct_members() main loop Adopt a more Pythonic form for the main loop of this function, getting rid of the "while True:" construction and making the actual loop invariant explicit. Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250807211639.47286-8-corbet@lwn.net --- scripts/lib/kdoc/kdoc_parser.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py index fbd7f6ce3360..e11f3d6e9469 100644 --- a/scripts/lib/kdoc/kdoc_parser.py +++ b/scripts/lib/kdoc/kdoc_parser.py @@ -663,11 +663,8 @@ class KernelDoc: # re limitation. struct_members = KernRe(r'(struct|union)([^\{\};]+)(\{)([^\{\}]*)(\})([^\{\};]*)(;)') - while True: - tuples = struct_members.findall(members) - if not tuples: - break - + tuples = struct_members.findall(members) + while tuples: for t in tuples: newmember = "" maintype = t[0] @@ -738,6 +735,7 @@ class KernelDoc: newmember += f"{dtype} {s_id}.{name}; " members = members.replace(oldmember, newmember) + tuples = struct_members.findall(members) return members def dump_struct(self, ln, proto): From fb20e610393b02a832a0bf4964e12c20a7ffa2f8 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 7 Aug 2025 15:16:35 -0600 Subject: [PATCH 00242/11391] docs: kdoc: remove an extraneous strip() call ...the variable in question was already strip()ed at the top of the loop. Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250807211639.47286-9-corbet@lwn.net --- scripts/lib/kdoc/kdoc_parser.py | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py index e11f3d6e9469..0c279aa802a0 100644 --- a/scripts/lib/kdoc/kdoc_parser.py +++ b/scripts/lib/kdoc/kdoc_parser.py @@ -703,7 +703,6 @@ class KernelDoc: newmember += f"{dtype}{s_id}.{name}{extra}; " else: - arg = arg.strip() # Handle bitmaps arg = KernRe(r':\s*\d+\s*').sub('', arg) From a8c4b0a8f1969e5ee0e8abb62cde8f0d7bcc2009 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 7 Aug 2025 15:16:36 -0600 Subject: [PATCH 00243/11391] docs: kdoc: Some rewrite_struct_members() commenting Add comments to rewrite_struct_members() describing what it is actually doing, and reformat/comment the main struct_members regex so that it is (more) comprehensible to humans. Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250807211639.47286-10-corbet@lwn.net --- scripts/lib/kdoc/kdoc_parser.py | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py index 0c279aa802a0..e3d0270b1a19 100644 --- a/scripts/lib/kdoc/kdoc_parser.py +++ b/scripts/lib/kdoc/kdoc_parser.py @@ -647,22 +647,28 @@ class KernelDoc: return (r.group(1), r.group(3), r.group(2)) return None + # + # Rewrite the members of a structure or union for easier formatting later on. + # Among other things, this function will turn a member like: + # + # struct { inner_members; } foo; + # + # into: + # + # struct foo; inner_members; + # def rewrite_struct_members(self, members): - # Split nested struct/union elements # - # This loop was simpler at the original kernel-doc perl version, as - # while ($members =~ m/$struct_members/) { ... } - # reads 'members' string on each interaction. + # Process struct/union members from the most deeply nested outward. The + # trick is in the ^{ below - it prevents a match of an outer struct/union + # until the inner one has been munged (removing the "{" in the process). # - # Python behavior is different: it parses 'members' only once, - # creating a list of tuples from the first interaction. - # - # On other words, this won't get nested structs. - # - # So, we need to have an extra loop on Python to override such - # re limitation. - - struct_members = KernRe(r'(struct|union)([^\{\};]+)(\{)([^\{\}]*)(\})([^\{\};]*)(;)') + struct_members = KernRe(r'(struct|union)' # 0: declaration type + r'([^\{\};]+)' # 1: possible name + r'(\{)' + r'([^\{\}]*)' # 3: Contents of declaration + r'(\})' + r'([^\{\};]*)(;)') # 5: Remaining stuff after declaration tuples = struct_members.findall(members) while tuples: for t in tuples: From e6dd4e2a5ca1c1e2fb168249532da1d95b5b24af Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 7 Aug 2025 15:16:37 -0600 Subject: [PATCH 00244/11391] docs: kdoc: further rewrite_struct_members() cleanup Get rid of some redundant checks, and generally tighten up the code; no logical change. Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250807211639.47286-11-corbet@lwn.net --- scripts/lib/kdoc/kdoc_parser.py | 86 ++++++++++++++++----------------- 1 file changed, 41 insertions(+), 45 deletions(-) diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py index e3d0270b1a19..b3f937901037 100644 --- a/scripts/lib/kdoc/kdoc_parser.py +++ b/scripts/lib/kdoc/kdoc_parser.py @@ -673,73 +673,69 @@ class KernelDoc: while tuples: for t in tuples: newmember = "" - maintype = t[0] - s_ids = t[5] - content = t[3] - - oldmember = "".join(t) - - for s_id in s_ids.split(','): + oldmember = "".join(t) # Reconstruct the original formatting + dtype, name, lbr, content, rbr, rest, semi = t + # + # Pass through each field name, normalizing the form and formatting. + # + for s_id in rest.split(','): s_id = s_id.strip() - - newmember += f"{maintype} {s_id}; " + newmember += f"{dtype} {s_id}; " + # + # Remove bitfield/array/pointer info, getting the bare name. + # s_id = KernRe(r'[:\[].*').sub('', s_id) s_id = KernRe(r'^\s*\**(\S+)\s*').sub(r'\1', s_id) - + # + # Pass through the members of this inner structure/union. + # for arg in content.split(';'): arg = arg.strip() - - if not arg: - continue - + # + # Look for (type)(*name)(args) - pointer to function + # r = KernRe(r'^([^\(]+\(\*?\s*)([\w.]*)(\s*\).*)') if r.match(arg): + dtype, name, extra = r.group(1), r.group(2), r.group(3) # Pointer-to-function - dtype = r.group(1) - name = r.group(2) - extra = r.group(3) - - if not name: - continue - if not s_id: # Anonymous struct/union newmember += f"{dtype}{name}{extra}; " else: newmember += f"{dtype}{s_id}.{name}{extra}; " - + # + # Otherwise a non-function member. + # else: - # Handle bitmaps + # + # Remove bitmap and array portions and spaces around commas + # arg = KernRe(r':\s*\d+\s*').sub('', arg) - - # Handle arrays arg = KernRe(r'\[.*\]').sub('', arg) - - # Handle multiple IDs arg = KernRe(r'\s*,\s*').sub(',', arg) - + # + # Look for a normal decl - "type name[,name...]" + # r = KernRe(r'(.*)\s+([\S+,]+)') - if r.search(arg): - dtype = r.group(1) - names = r.group(2) + for name in r.group(2).split(','): + name = KernRe(r'^\s*\**(\S+)\s*').sub(r'\1', name) + if not s_id: + # Anonymous struct/union + newmember += f"{r.group(1)} {name}; " + else: + newmember += f"{r.group(1)} {s_id}.{name}; " else: newmember += f"{arg}; " - continue - - for name in names.split(','): - name = KernRe(r'^\s*\**(\S+)\s*').sub(r'\1', name).strip() - - if not name: - continue - - if not s_id: - # Anonymous struct/union - newmember += f"{dtype} {name}; " - else: - newmember += f"{dtype} {s_id}.{name}; " - + # + # At the end of the s_id loop, replace the original declaration with + # the munged version. + # members = members.replace(oldmember, newmember) + # + # End of the tuple loop - search again and see if there are outer members + # that now turn up. + # tuples = struct_members.findall(members) return members From 23c47b09315935df140ca5ce2ddddb85453ed64d Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 7 Aug 2025 15:16:38 -0600 Subject: [PATCH 00245/11391] docs: kdoc: extract output formatting from dump_struct() The last thing done in dump_struct() is to format the structure for printing. That, too, is a separate activity; split it out into its own function. dump_struct() now fits in a single, full-hight editor screen. Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250807211639.47286-12-corbet@lwn.net --- scripts/lib/kdoc/kdoc_parser.py | 72 +++++++++++++++++---------------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py index b3f937901037..878fbfab4ac7 100644 --- a/scripts/lib/kdoc/kdoc_parser.py +++ b/scripts/lib/kdoc/kdoc_parser.py @@ -739,6 +739,42 @@ class KernelDoc: tuples = struct_members.findall(members) return members + # + # Format the struct declaration into a standard form for inclusion in the + # resulting docs. + # + def format_struct_decl(self, declaration): + # + # Insert newlines, get rid of extra spaces. + # + declaration = KernRe(r'([\{;])').sub(r'\1\n', declaration) + declaration = KernRe(r'\}\s+;').sub('};', declaration) + # + # Format inline enums with each member on its own line. + # + r = KernRe(r'(enum\s+\{[^\}]+),([^\n])') + while r.search(declaration): + declaration = r.sub(r'\1,\n\2', declaration) + # + # Now go through and supply the right number of tabs + # for each line. + # + def_args = declaration.split('\n') + level = 1 + declaration = "" + for clause in def_args: + clause = KernRe(r'\s+').sub(' ', clause.strip(), count=1) + if clause: + if '}' in clause and level > 1: + level -= 1 + if not clause.startswith('#'): + declaration += "\t" * level + declaration += "\t" + clause + "\n" + if "{" in clause and "}" not in clause: + level += 1 + return declaration + + def dump_struct(self, ln, proto): """ Store an entry for an struct or union @@ -777,42 +813,8 @@ class KernelDoc: self.create_parameter_list(ln, decl_type, members, ';', declaration_name) self.check_sections(ln, declaration_name, decl_type) - - # Adjust declaration for better display - declaration = KernRe(r'([\{;])').sub(r'\1\n', declaration) - declaration = KernRe(r'\}\s+;').sub('};', declaration) - - # Better handle inlined enums - while True: - r = KernRe(r'(enum\s+\{[^\}]+),([^\n])') - if not r.search(declaration): - break - - declaration = r.sub(r'\1,\n\2', declaration) - - def_args = declaration.split('\n') - level = 1 - declaration = "" - for clause in def_args: - - clause = clause.strip() - clause = KernRe(r'\s+').sub(' ', clause, count=1) - - if not clause: - continue - - if '}' in clause and level > 1: - level -= 1 - - if not KernRe(r'^\s*#').match(clause): - declaration += "\t" * level - - declaration += "\t" + clause + "\n" - if "{" in clause and "}" not in clause: - level += 1 - self.output_declaration(decl_type, declaration_name, - definition=declaration, + definition=self.format_struct_decl(declaration), purpose=self.entry.declaration_purpose) def dump_enum(self, ln, proto): From e282303e718b2007b3db77c6db75ecaf4419a1af Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 7 Aug 2025 15:16:39 -0600 Subject: [PATCH 00246/11391] docs: kdoc: a few final dump_struct() touches Add a couple more comments so that each phase of the process is now clearly marked. Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250807211639.47286-13-corbet@lwn.net --- scripts/lib/kdoc/kdoc_parser.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py index 878fbfab4ac7..9b21fb86709a 100644 --- a/scripts/lib/kdoc/kdoc_parser.py +++ b/scripts/lib/kdoc/kdoc_parser.py @@ -802,14 +802,15 @@ class KernelDoc: nested = NestedMatch() for search, sub in struct_nested_prefixes: members = nested.sub(search, sub, members) - - # Keeps the original declaration as-is + # + # Deal with embedded struct and union members, and drop enums entirely. + # declaration = members members = self.rewrite_struct_members(members) - - # Ignore other nested elements, like enums members = re.sub(r'(\{[^\{\}]*\})', '', members) - + # + # Output the result and we are done. + # self.create_parameter_list(ln, decl_type, members, ';', declaration_name) self.check_sections(ln, declaration_name, decl_type) From b261da9e9ed8d7bfae7f34940a338750900e9b09 Mon Sep 17 00:00:00 2001 From: Antony Kurniawan Soemardi Date: Sun, 22 Jun 2025 18:26:38 +0000 Subject: [PATCH 00247/11391] ARM: dts: qcom: msm8960: add sdcc3 pinctrl states Adds sdcc3-default-state and sdcc3-sleep-state pinctrl states for MSM8960. These are required for devices like Sony Xperia SP to ensure micro SD card functionality, though they are a no-op on the Samsung Galaxy Express. Tested-by: Rudraksha Gupta Signed-off-by: Antony Kurniawan Soemardi Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250623-msm8960-sdcard-v2-1-340a5e8f7df0@smankusors.com Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/qcom-msm8960-pins.dtsi | 40 +++++++++++++++++++ .../qcom/qcom-msm8960-samsung-expressatt.dts | 5 +++ 2 files changed, 45 insertions(+) diff --git a/arch/arm/boot/dts/qcom/qcom-msm8960-pins.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8960-pins.dtsi index 4fa982771288..f18753e9f5ef 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8960-pins.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8960-pins.dtsi @@ -18,4 +18,44 @@ i2c3-pins { bias-bus-hold; }; }; + + sdcc3_default_state: sdcc3-default-state { + clk-pins { + pins = "sdc3_clk"; + drive-strength = <8>; + bias-disable; + }; + + cmd-pins { + pins = "sdc3_cmd"; + drive-strength = <8>; + bias-pull-up; + }; + + data-pins { + pins = "sdc3_data"; + drive-strength = <8>; + bias-pull-up; + }; + }; + + sdcc3_sleep_state: sdcc3-sleep-state { + clk-pins { + pins = "sdc3_clk"; + drive-strength = <2>; + bias-disable; + }; + + cmd-pins { + pins = "sdc3_cmd"; + drive-strength = <2>; + bias-pull-up; + }; + + data-pins { + pins = "sdc3_data"; + drive-strength = <2>; + bias-pull-up; + }; + }; }; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts b/arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts index af6cc6393d74..49d117ea033a 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts @@ -71,6 +71,11 @@ &sdcc1 { &sdcc3 { vmmc-supply = <&pm8921_l6>; vqmmc-supply = <&pm8921_l7>; + + pinctrl-0 = <&sdcc3_default_state>; + pinctrl-1 = <&sdcc3_sleep_state>; + pinctrl-names = "default", "sleep"; + status = "okay"; }; From 12bf7cfb5ad4e278ac555f209f2b18d81fb4783f Mon Sep 17 00:00:00 2001 From: Antony Kurniawan Soemardi Date: Sun, 22 Jun 2025 18:26:41 +0000 Subject: [PATCH 00248/11391] ARM: dts: qcom: msm8960: add gsbi8 and its serial configuration The LTE variant of the MSM8960 SoC has a gsbi8 node used for the serial console. That's if the downstream kernel is to be believed, as Xperia SP has a serial console on gsbi8 even on the non-LTE variant. Signed-off-by: Antony Kurniawan Soemardi Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250623-msm8960-sdcard-v2-2-340a5e8f7df0@smankusors.com Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/qcom-msm8960.dtsi | 28 ++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi index 203f0b69b353..cf0b1da230f1 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi @@ -333,6 +333,34 @@ gsbi5_serial: serial@16440000 { }; }; + gsbi8: gsbi@1a000000 { + compatible = "qcom,gsbi-v1.0.0"; + cell-index = <8>; + reg = <0x1a000000 0x100>; + clocks = <&gcc GSBI8_H_CLK>; + clock-names = "iface"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + syscon-tcsr = <&tcsr>; + + status = "disabled"; + + gsbi8_serial: serial@1a040000 { + compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; + reg = <0x1a040000 0x1000>, + <0x1a000000 0x1000>; + interrupts = ; + clocks = <&gcc GSBI8_UART_CLK>, + <&gcc GSBI8_H_CLK>; + clock-names = "core", + "iface"; + + status = "disabled"; + }; + }; + ssbi: ssbi@500000 { compatible = "qcom,ssbi"; reg = <0x500000 0x1000>; From 45f5d1dc6ff3b2b80e92071b507bee77c86f6ad6 Mon Sep 17 00:00:00 2001 From: Antony Kurniawan Soemardi Date: Sun, 22 Jun 2025 18:26:44 +0000 Subject: [PATCH 00249/11391] ARM: dts: qcom: msm8960: disable gsbi1 and gsbi5 nodes in msm8960 dtsi Not all devices use gsbi1 and gsbi5, so these nodes should be disabled in the SoC dtsi, following the existing pattern used for gsbi3. The upstream samsung-expressatt and msm8960-cdp devices already have status "okay" for these nodes, so this change should not break existing functionality. This eliminates the following error messages when gsbi nodes are not configured in the board's device tree: [ 1.109723] gsbi 16000000.gsbi: missing mode configuration [ 1.109797] gsbi 16000000.gsbi: probe with driver gsbi failed with error -22 (Note: Xperia SP doesn't use gsbi5) Signed-off-by: Antony Kurniawan Soemardi Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250623-msm8960-sdcard-v2-3-340a5e8f7df0@smankusors.com Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/qcom-msm8960.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi index cf0b1da230f1..6e272d5345a8 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi @@ -322,6 +322,8 @@ gsbi5: gsbi@16400000 { syscon-tcsr = <&tcsr>; + status = "disabled"; + gsbi5_serial: serial@16440000 { compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; reg = <0x16440000 0x1000>, @@ -445,6 +447,8 @@ gsbi1: gsbi@16000000 { #size-cells = <1>; ranges; + status = "disabled"; + gsbi1_spi: spi@16080000 { compatible = "qcom,spi-qup-v1.1.1"; #address-cells = <1>; From fc973dcd73f242480c61eccb1aa7306adafd2907 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 29 Jul 2025 18:43:03 +0200 Subject: [PATCH 00250/11391] docs: kernel-doc: avoid script crash on ancient Python While we do need at least 3.6 for kernel-doc to work, and at least 3.7 for it to output functions and structs with parameters at the right order, let the python binary be compatible with legacy versions. The rationale is that the Kernel build nowadays calls kernel-doc with -none on some places. Better not to bail out when older versions are found. With that, potentially this will run with python 2.7 and 3.2+, according with vermin: $ vermin --no-tips -v ./scripts/kernel-doc Detecting python files.. Analyzing using 24 processes.. 2.7, 3.2 /new_devel/v4l/docs/scripts/kernel-doc Minimum required versions: 2.7, 3.2 3.2 minimal requirement is due to argparse. The minimal version I could check was version 3.4 (using anaconda). Anaconda doesn't support 3.2 or 3.3 anymore, and 3.2 doesn't even compile (I tested compiling Python 3.2 on Fedora 42 and on Fedora 32 - no show). With 3.4, the script didn't crash and emitted the right warning: $ conda create -n py34 python=3.4 $ conda activate py34 python --version Python 3.4.5 $ python ./scripts/kernel-doc --none include/media Error: Python 3.6 or later is required by kernel-doc $ conda deactivate $ python --version Python 3.13.5 $ python ./scripts/kernel-doc --none include/media (no warnings and script ran properly) Supporting 2.7 is out of scope, as it is EOL for 5 years, and changing shebang to point to "python" instead of "python3" would have a wider impact. I did some extra checks about the differences from 3.2 and 3.4, and didn't find anything that would cause troubles: grep -rE "yield from|asyncio|pathlib|async|await|enum" scripts/kernel-doc Also, it doesn't use "@" operator. So, I'm confident that it should run (producing the exit warning) since Python 3.2. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/87d55e76b0b1391cb7a83e3e965dbddb83fa9786.1753806485.git.mchehab+huawei@kernel.org --- scripts/kernel-doc.py | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py index fc3d46ef519f..d9fe2bcbd39c 100755 --- a/scripts/kernel-doc.py +++ b/scripts/kernel-doc.py @@ -2,8 +2,17 @@ # SPDX-License-Identifier: GPL-2.0 # Copyright(c) 2025: Mauro Carvalho Chehab . # -# pylint: disable=C0103,R0915 -# +# pylint: disable=C0103,R0912,R0914,R0915 + +# NOTE: While kernel-doc requires at least version 3.6 to run, the +# command line should work with Python 3.2+ (tested with 3.4). +# The rationale is that it shall fail gracefully during Kernel +# compilation with older Kernel versions. Due to that: +# - encoding line is needed here; +# - no f-strings can be used on this file. +# - the libraries that require newer versions can only be included +# after Python version is checked. + # Converted from the kernel-doc script originally written in Perl # under GPLv2, copyrighted since 1998 by the following authors: # @@ -107,9 +116,6 @@ SRC_DIR = os.path.dirname(os.path.realpath(__file__)) sys.path.insert(0, os.path.join(SRC_DIR, LIB_DIR)) -from kdoc_files import KernelFiles # pylint: disable=C0413 -from kdoc_output import RestFormat, ManFormat # pylint: disable=C0413 - DESC = """ Read C language source or header FILEs, extract embedded documentation comments, and print formatted documentation to standard output. @@ -273,14 +279,22 @@ def main(): python_ver = sys.version_info[:2] if python_ver < (3,6): - logger.warning("Python 3.6 or later is required by kernel-doc") + # Depending on Kernel configuration, kernel-doc --none is called at + # build time. As we don't want to break compilation due to the + # usage of an old Python version, return 0 here. + if args.none: + logger.error("Python 3.6 or later is required by kernel-doc. skipping checks") + sys.exit(0) - # Return 0 here to avoid breaking compilation - sys.exit(0) + sys.exit("Python 3.6 or later is required by kernel-doc. Aborting.") if python_ver < (3,7): logger.warning("Python 3.7 or later is required for correct results") + # Import kernel-doc libraries only after checking Python version + from kdoc_files import KernelFiles # pylint: disable=C0415 + from kdoc_output import RestFormat, ManFormat # pylint: disable=C0415 + if args.man: out_style = ManFormat(modulename=args.modulename) elif args.none: @@ -308,11 +322,11 @@ def main(): sys.exit(0) if args.werror: - print(f"{error_count} warnings as errors") + print("%s warnings as errors" % error_count) # pylint: disable=C0209 sys.exit(error_count) if args.verbose: - print(f"{error_count} errors") + print("%s errors" % error_count) # pylint: disable=C0209 if args.none: sys.exit(0) From bc20c56e98e0bd08e89f4fe327f4f14994d339b5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 29 Jul 2025 18:43:04 +0200 Subject: [PATCH 00251/11391] docs: changes: better document Python needs Python is listed as an optional dependency, but this is not true, as: 1) arm (multi_v7_defconfig and other defconfigs) and arm64 defconfig needs it due to DRM_MSM dependencies; 2) CONFIG_LTO_CLANG runs a python script at scripts/Makefile.vmlinux_o; 3) kernel-doc is called during compilation when some DRM options like CONFIG_DRM_I915_WERROR are enabled; 4) allyesconfig/allmodconfig will enable CONFIG_* dependencies that needs it; 5) besides DRM, other subsystems seem to have logic calling *.py scripts. So, better document that and change the dependency from optional to mandatory to reflect the current needs. Signed-off-by: Mauro Carvalho Chehab Acked-by: Rob Herring (Arm) Acked-by: Akira Yokosawa Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/b03b95b8d09358e81e4f27942839191f49b0ba80.1753806485.git.mchehab+huawei@kernel.org --- Documentation/process/changes.rst | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Documentation/process/changes.rst b/Documentation/process/changes.rst index bccfa19b45df..4c9088e429c8 100644 --- a/Documentation/process/changes.rst +++ b/Documentation/process/changes.rst @@ -61,7 +61,7 @@ Sphinx\ [#f1]_ 3.4.3 sphinx-build --version GNU tar 1.28 tar --version gtags (optional) 6.6.5 gtags --version mkimage (optional) 2017.01 mkimage --version -Python (optional) 3.9.x python3 --version +Python 3.9.x python3 --version GNU AWK (optional) 5.1.0 gawk --version ====================== =============== ======================================== @@ -154,6 +154,13 @@ Perl You will need perl 5 and the following modules: ``Getopt::Long``, ``Getopt::Std``, ``File::Basename``, and ``File::Find`` to build the kernel. +Python +------ + +Several config options require it: it is required for arm/arm64 +default configs, CONFIG_LTO_CLANG, some DRM optional configs, +the kernel-doc tool, and docs build (Sphinx), among others. + BC -- From 119996c9a4be91f70779efe0a4f178356820249a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 7 Aug 2025 09:36:01 +0200 Subject: [PATCH 00252/11391] Documentation/printf: Use literal fwnode_handle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When looking for fwnode_handle in the printk format documentation, it is only found in the Chinese translation: $ git grep fwnode_handle -- Documentation/*printk-formats.rst Documentation/translations/zh_CN/core-api/printk-formats.rst:用于打印fwnode_handles的消息。默认情况下是打印完整的节点名称,包括路径。 This happens because the original documentation talks about "fwnode handles", without mentioning the actual type name. Signed-off-by: Geert Uytterhoeven Tested-by: Kunwu Chan Reviewed-by: Kunwu Chan Reviewed-by: Andy Shevchenko Reviewed-by: Sakari Ailus Fixes: 3bd32d6a2ee62db3 ("lib/vsprintf: Add %pfw conversion specifier for printing fwnode names") Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/07262c55e82fc4a3e3dbe7c45713b14955271e7f.1754552156.git.geert+renesas@glider.be --- Documentation/core-api/printk-formats.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst index 4b7f3646ec6c..7f2f11b48286 100644 --- a/Documentation/core-api/printk-formats.rst +++ b/Documentation/core-api/printk-formats.rst @@ -521,7 +521,7 @@ Fwnode handles %pfw[fP] -For printing information on fwnode handles. The default is to print the full +For printing information on an fwnode_handle. The default is to print the full node name, including the path. The modifiers are functionally equivalent to %pOF above. From 3feaa8a469ccb14e8adf69ae3235785182905bfc Mon Sep 17 00:00:00 2001 From: Osama Albahrani Date: Mon, 4 Aug 2025 18:25:14 +0300 Subject: [PATCH 00253/11391] docs: aoe: Remove trailing whitespace Fix `ERROR: trailing whitespace` errors from scripts/checkpatch.pl Signed-off-by: Osama Albahrani Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250804152516.16493-1-osalbahr@gmail.com --- Documentation/admin-guide/aoe/udev.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/admin-guide/aoe/udev.txt b/Documentation/admin-guide/aoe/udev.txt index 5fb756466bc7..d55ecb411c21 100644 --- a/Documentation/admin-guide/aoe/udev.txt +++ b/Documentation/admin-guide/aoe/udev.txt @@ -2,7 +2,7 @@ # They may be installed along the following lines. Check the section # 8 udev manpage to see whether your udev supports SUBSYSTEM, and # whether it uses one or two equal signs for SUBSYSTEM and KERNEL. -# +# # ecashin@makki ~$ su # Password: # bash# find /etc -type f -name udev.conf @@ -13,7 +13,7 @@ # 10-wacom.rules 50-udev.rules # bash# cp /path/to/linux/Documentation/admin-guide/aoe/udev.txt \ # /etc/udev/rules.d/60-aoe.rules -# +# # aoe char devices SUBSYSTEM=="aoe", KERNEL=="discover", NAME="etherd/%k", GROUP="disk", MODE="0220" @@ -22,5 +22,5 @@ SUBSYSTEM=="aoe", KERNEL=="interfaces", NAME="etherd/%k", GROUP="disk", MODE="02 SUBSYSTEM=="aoe", KERNEL=="revalidate", NAME="etherd/%k", GROUP="disk", MODE="0220" SUBSYSTEM=="aoe", KERNEL=="flush", NAME="etherd/%k", GROUP="disk", MODE="0220" -# aoe block devices +# aoe block devices KERNEL=="etherd*", GROUP="disk" From 3fcf228b6494e707aef960bad33461a513f16721 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 31 Jul 2025 13:34:04 +0800 Subject: [PATCH 00254/11391] f2fs: dump more information when checkpoint was blocked for long time generic/299 w/ mode=lfs will cause long time latency of checkpoint, let's dump more information once we hit case. CP merge: - Queued : 0 - Issued : 1 - Total : 1 - Cur time : 9765(ms) - Peak time : 9765(ms) F2FS-fs (vdc): blocked on checkpoint for 9765 ms CPU: 11 UID: 0 PID: 237 Comm: kworker/u128:29 Tainted: G O 6.16.0-rc3+ #409 PREEMPT(voluntary) Tainted: [O]=OOT_MODULE Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 Workqueue: writeback wb_workfn (flush-253:32) Call Trace: dump_stack_lvl+0x6e/0xa0 f2fs_issue_checkpoint+0x268/0x280 f2fs_write_node_pages+0x6a/0x2c0 do_writepages+0xd0/0x170 __writeback_single_inode+0x56/0x4c0 writeback_sb_inodes+0x22a/0x550 __writeback_inodes_wb+0x4c/0xf0 wb_writeback+0x300/0x400 wb_workfn+0x3de/0x500 process_one_work+0x230/0x5c0 worker_thread+0x1da/0x3d0 kthread+0x10d/0x250 ret_from_fork+0x164/0x190 ret_from_fork_asm+0x1a/0x30 Cc: Jan Prusakowski Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/checkpoint.c | 7 +++++++ fs/f2fs/f2fs.h | 8 +++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index db3831f7f2f5..02806e2edce4 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -1778,6 +1778,7 @@ static void __checkpoint_and_complete_reqs(struct f2fs_sb_info *sbi) llist_for_each_entry_safe(req, next, dispatch_list, llnode) { diff = (u64)ktime_ms_delta(ktime_get(), req->queue_time); req->ret = ret; + req->delta_time = diff; complete(&req->wait); sum_diff += diff; @@ -1873,6 +1874,12 @@ int f2fs_issue_checkpoint(struct f2fs_sb_info *sbi) else flush_remained_ckpt_reqs(sbi, &req); + if (unlikely(req.delta_time >= CP_LONG_LATENCY_THRESHOLD)) { + f2fs_warn_ratelimited(sbi, + "blocked on checkpoint for %u ms", cprc->peak_time); + dump_stack(); + } + return req.ret; } diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 46be7560548c..7b567ab953e4 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -334,7 +334,10 @@ struct ckpt_req { struct completion wait; /* completion for checkpoint done */ struct llist_node llnode; /* llist_node to be linked in wait queue */ int ret; /* return code of checkpoint */ - ktime_t queue_time; /* request queued time */ + union { + ktime_t queue_time; /* request queued time */ + ktime_t delta_time; /* time in queue */ + }; }; struct ckpt_req_control { @@ -350,6 +353,9 @@ struct ckpt_req_control { unsigned int peak_time; /* peak wait time in msec until now */ }; +/* a time threshold that checkpoint was blocked for, unit: ms */ +#define CP_LONG_LATENCY_THRESHOLD 5000 + /* for the bitmap indicate blocks to be discarded */ struct discard_entry { struct list_head list; /* list head */ From 57e74035ad5e427ed301c2dc28e2b07a1d523175 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 31 Jul 2025 13:34:05 +0800 Subject: [PATCH 00255/11391] f2fs: add time stats of checkpoint for debug checkpoint was blocked for 18643 ms Step 0: 0 ms Step 1: 38 ms Step 2: 63 ms Step 3: 4 ms Step 4: 0 ms Step 5: 0 ms Step 6: 9 ms Step 7: 0 ms Step 8: 18277 ms Step 9: 249 ms Cc: Jan Prusakowski Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/checkpoint.c | 46 ++++++++++++++++++++++++++++++++++++++++++++ fs/f2fs/f2fs.h | 22 +++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 02806e2edce4..bbe07e3a6c75 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -1442,6 +1442,34 @@ u64 f2fs_get_sectors_written(struct f2fs_sb_info *sbi) return get_sectors_written(sbi->sb->s_bdev); } +static inline void stat_cp_time(struct cp_control *cpc, enum cp_time type) +{ + cpc->stats.times[type] = ktime_get(); +} + +static inline void check_cp_time(struct f2fs_sb_info *sbi, struct cp_control *cpc) +{ + unsigned long long sb_diff, cur_diff; + enum cp_time ct; + + sb_diff = (u64)ktime_ms_delta(sbi->cp_stats.times[CP_TIME_END], + sbi->cp_stats.times[CP_TIME_START]); + cur_diff = (u64)ktime_ms_delta(cpc->stats.times[CP_TIME_END], + cpc->stats.times[CP_TIME_START]); + + if (cur_diff > sb_diff) { + sbi->cp_stats = cpc->stats; + if (cur_diff < CP_LONG_LATENCY_THRESHOLD) + return; + + f2fs_warn(sbi, "checkpoint was blocked for %llu ms", cur_diff); + for (ct = CP_TIME_START; ct < CP_TIME_MAX - 1; ct++) + f2fs_warn(sbi, "Step#%d: %llu ms", ct, + (u64)ktime_ms_delta(cpc->stats.times[ct + 1], + cpc->stats.times[ct])); + } +} + static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) { struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); @@ -1459,6 +1487,8 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) /* Flush all the NAT/SIT pages */ f2fs_sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO); + stat_cp_time(cpc, CP_TIME_SYNC_META); + /* start to update checkpoint, cp ver is already updated previously */ ckpt->elapsed_time = cpu_to_le64(get_mtime(sbi, true)); ckpt->free_segment_count = cpu_to_le32(free_segments(sbi)); @@ -1555,20 +1585,26 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) /* Here, we have one bio having CP pack except cp pack 2 page */ f2fs_sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO); + stat_cp_time(cpc, CP_TIME_SYNC_CP_META); + /* Wait for all dirty meta pages to be submitted for IO */ f2fs_wait_on_all_pages(sbi, F2FS_DIRTY_META); + stat_cp_time(cpc, CP_TIME_WAIT_DIRTY_META); /* wait for previous submitted meta pages writeback */ f2fs_wait_on_all_pages(sbi, F2FS_WB_CP_DATA); + stat_cp_time(cpc, CP_TIME_WAIT_CP_DATA); /* flush all device cache */ err = f2fs_flush_device_cache(sbi); if (err) return err; + stat_cp_time(cpc, CP_TIME_FLUSH_DEVICE); /* barrier and flush checkpoint cp pack 2 page if it can */ commit_checkpoint(sbi, ckpt, start_blk); f2fs_wait_on_all_pages(sbi, F2FS_WB_CP_DATA); + stat_cp_time(cpc, CP_TIME_WAIT_LAST_CP); /* * invalidate intermediate page cache borrowed from meta inode which are @@ -1613,6 +1649,8 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) unsigned long long ckpt_ver; int err = 0; + stat_cp_time(cpc, CP_TIME_START); + if (f2fs_readonly(sbi->sb) || f2fs_hw_is_readonly(sbi)) return -EROFS; @@ -1624,6 +1662,8 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) if (cpc->reason != CP_RESIZE) f2fs_down_write(&sbi->cp_global_sem); + stat_cp_time(cpc, CP_TIME_LOCK); + if (!is_sbi_flag_set(sbi, SBI_IS_DIRTY) && ((cpc->reason & CP_FASTBOOT) || (cpc->reason & CP_SYNC) || ((cpc->reason & CP_DISCARD) && !sbi->discard_blks))) @@ -1639,6 +1679,8 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) if (err) goto out; + stat_cp_time(cpc, CP_TIME_OP_LOCK); + trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish block_ops"); f2fs_flush_merged_writes(sbi); @@ -1678,6 +1720,8 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) f2fs_flush_sit_entries(sbi, cpc); + stat_cp_time(cpc, CP_TIME_FLUSH_META); + /* save inmem log status */ f2fs_save_inmem_curseg(sbi); @@ -1695,6 +1739,8 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) stat_inc_cp_count(sbi); stop: unblock_operations(sbi); + stat_cp_time(cpc, CP_TIME_END); + check_cp_time(sbi, cpc); if (cpc->reason & CP_RECOVERY) f2fs_notice(sbi, "checkpoint: version = %llx", ckpt_ver); diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 7b567ab953e4..64a4fda315c9 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -269,11 +269,32 @@ enum { #define DEF_DISABLE_QUICK_INTERVAL 1 /* 1 secs */ #define DEF_UMOUNT_DISCARD_TIMEOUT 5 /* 5 secs */ +enum cp_time { + CP_TIME_START, /* begin */ + CP_TIME_LOCK, /* after cp_global_sem */ + CP_TIME_OP_LOCK, /* after block_operation */ + CP_TIME_FLUSH_META, /* after flush sit/nat */ + CP_TIME_SYNC_META, /* after sync_meta_pages */ + CP_TIME_SYNC_CP_META, /* after sync cp meta pages */ + CP_TIME_WAIT_DIRTY_META,/* after wait on dirty meta */ + CP_TIME_WAIT_CP_DATA, /* after wait on cp data */ + CP_TIME_FLUSH_DEVICE, /* after flush device cache */ + CP_TIME_WAIT_LAST_CP, /* after wait on last cp pack */ + CP_TIME_END, /* after unblock_operation */ + CP_TIME_MAX, +}; + +/* time cost stats of checkpoint */ +struct cp_stats { + ktime_t times[CP_TIME_MAX]; +}; + struct cp_control { int reason; __u64 trim_start; __u64 trim_end; __u64 trim_minlen; + struct cp_stats stats; }; /* @@ -1643,6 +1664,7 @@ struct f2fs_sb_info { unsigned long last_time[MAX_TIME]; /* to store time in jiffies */ long interval_time[MAX_TIME]; /* to store thresholds */ struct ckpt_req_control cprc_info; /* for checkpoint request control */ + struct cp_stats cp_stats; /* for time stat of checkpoint */ struct inode_management im[MAX_INO_ENTRY]; /* manage inode cache */ From e75ce117905d2830976a289e718470f3230fa30a Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 31 Jul 2025 14:03:38 +0800 Subject: [PATCH 00256/11391] f2fs: fix condition in __allow_reserved_blocks() If reserve_root mount option is not assigned, __allow_reserved_blocks() will return false, it's not correct, fix it. Fixes: 7e65be49ed94 ("f2fs: add reserved blocks for root user") Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/f2fs.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 64a4fda315c9..6b66db642e09 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -2389,8 +2389,6 @@ static inline bool __allow_reserved_blocks(struct f2fs_sb_info *sbi, { if (!inode) return true; - if (!test_opt(sbi, RESERVE_ROOT)) - return false; if (IS_NOQUOTA(inode)) return true; if (uid_eq(F2FS_OPTION(sbi).s_resuid, current_fsuid())) @@ -2411,7 +2409,7 @@ static inline unsigned int get_available_block_count(struct f2fs_sb_info *sbi, avail_user_block_count = sbi->user_block_count - sbi->current_reserved_blocks; - if (!__allow_reserved_blocks(sbi, inode, cap)) + if (test_opt(sbi, RESERVE_ROOT) && !__allow_reserved_blocks(sbi, inode, cap)) avail_user_block_count -= F2FS_OPTION(sbi).root_reserved_blocks; if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) { From 76bb6a72bc1daa3d973395349f366231768f8877 Mon Sep 17 00:00:00 2001 From: "mason.zhang" Date: Thu, 31 Jul 2025 23:19:17 +0800 Subject: [PATCH 00257/11391] f2fs: add error checking in do_write_page() Otherwise, the filesystem may unaware of potential file corruption. Signed-off-by: mason.zhang Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index cc82d42ef14c..04b0a3c1804d 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -3936,12 +3936,18 @@ static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio) int seg_type = log_type_to_seg_type(type); bool keep_order = (f2fs_lfs_mode(fio->sbi) && seg_type == CURSEG_COLD_DATA); + int err; if (keep_order) f2fs_down_read(&fio->sbi->io_order_lock); - if (f2fs_allocate_data_block(fio->sbi, folio, fio->old_blkaddr, - &fio->new_blkaddr, sum, type, fio)) { + err = f2fs_allocate_data_block(fio->sbi, folio, fio->old_blkaddr, + &fio->new_blkaddr, sum, type, fio); + if (unlikely(err)) { + f2fs_err_ratelimited(fio->sbi, + "%s Failed to allocate data block, ino:%u, index:%lu, type:%d, old_blkaddr:0x%x, new_blkaddr:0x%x, err:%d", + __func__, fio->ino, folio->index, type, + fio->old_blkaddr, fio->new_blkaddr, err); if (fscrypt_inode_uses_fs_layer_crypto(folio->mapping->host)) fscrypt_finalize_bounce_page(&fio->encrypted_page); folio_end_writeback(folio); From 632f0b6c3e32758e5c93d4e3c2860a3708b9853e Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Mon, 4 Aug 2025 23:52:26 -0700 Subject: [PATCH 00258/11391] f2fs: add lookup_mode mount option For casefolded directories, f2fs may fall back to a linear search if a hash-based lookup fails. This can cause severe performance regressions. While this behavior can be controlled by userspace tools (e.g. mkfs, fsck) by setting an on-disk flag, a kernel-level solution is needed to guarantee the lookup behavior regardless of the on-disk state. This commit introduces the 'lookup_mode' mount option to provide this kernel-side control. The option accepts three values: - perf: (Default) Enforces a hash-only lookup. The linear fallback is always disabled. - compat: Enables the linear search fallback for compatibility with directory entries from older kernels. - auto: Determines the mode based on the on-disk flag, preserving the userspace-based behavior. Signed-off-by: Daniel Lee Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- Documentation/filesystems/f2fs.rst | 19 +++++++++++++++++++ fs/f2fs/dir.c | 17 ++++++++++++++++- fs/f2fs/f2fs.h | 7 +++++++ fs/f2fs/super.c | 25 +++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 1 deletion(-) diff --git a/Documentation/filesystems/f2fs.rst b/Documentation/filesystems/f2fs.rst index e5bb89452aff..5cad369ceb92 100644 --- a/Documentation/filesystems/f2fs.rst +++ b/Documentation/filesystems/f2fs.rst @@ -370,6 +370,25 @@ errors=%s Specify f2fs behavior on critical errors. This supports modes: ====================== =============== =============== ======== nat_bits Enable nat_bits feature to enhance full/empty nat blocks access, by default it's disabled. +lookup_mode=%s Control the directory lookup behavior for casefolded + directories. This option has no effect on directories + that do not have the casefold feature enabled. + + ================== ======================================== + Value Description + ================== ======================================== + perf (Default) Enforces a hash-only lookup. + The linear search fallback is always + disabled, ignoring the on-disk flag. + compat Enables the linear search fallback for + compatibility with directory entries + created by older kernel that used a + different case-folding algorithm. + This mode ignores the on-disk flag. + auto F2FS determines the mode based on the + on-disk `SB_ENC_NO_COMPAT_FALLBACK_FL` + flag. + ================== ======================================== ======================== ============================================================ Debugfs Entries diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index fffd7749d6d1..48f4f98afb01 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -16,6 +16,21 @@ #include "xattr.h" #include +static inline bool f2fs_should_fallback_to_linear(struct inode *dir) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(dir); + + switch (F2FS_OPTION(sbi).lookup_mode) { + case LOOKUP_PERF: + return false; + case LOOKUP_COMPAT: + return true; + case LOOKUP_AUTO: + return !sb_no_casefold_compat_fallback(sbi->sb); + } + return false; +} + #if IS_ENABLED(CONFIG_UNICODE) extern struct kmem_cache *f2fs_cf_name_slab; #endif @@ -366,7 +381,7 @@ struct f2fs_dir_entry *__f2fs_find_entry(struct inode *dir, out: #if IS_ENABLED(CONFIG_UNICODE) - if (!sb_no_casefold_compat_fallback(dir->i_sb) && + if (f2fs_should_fallback_to_linear(dir) && IS_CASEFOLDED(dir) && !de && use_hash) { use_hash = false; goto start_find_entry; diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 6b66db642e09..36d6a6803916 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -212,6 +212,7 @@ struct f2fs_mount_info { int compress_mode; /* compression mode */ unsigned char extensions[COMPRESS_EXT_NUM][F2FS_EXTENSION_LEN]; /* extensions */ unsigned char noextensions[COMPRESS_EXT_NUM][F2FS_EXTENSION_LEN]; /* extensions */ + unsigned int lookup_mode; }; #define F2FS_FEATURE_ENCRYPT 0x00000001 @@ -1475,6 +1476,12 @@ enum { TOTAL_CALL = FOREGROUND, }; +enum f2fs_lookup_mode { + LOOKUP_PERF, + LOOKUP_COMPAT, + LOOKUP_AUTO, +}; + static inline int f2fs_test_bit(unsigned int nr, char *addr); static inline void f2fs_set_bit(unsigned int nr, char *addr); static inline void f2fs_clear_bit(unsigned int nr, char *addr); diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index e16c4e2830c2..0638ae9816ac 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -181,6 +181,7 @@ enum { Opt_nat_bits, Opt_jqfmt, Opt_checkpoint, + Opt_lookup_mode, Opt_err, }; @@ -244,6 +245,13 @@ static const struct constant_table f2fs_param_errors[] = { {} }; +static const struct constant_table f2fs_param_lookup_mode[] = { + {"perf", LOOKUP_PERF}, + {"compat", LOOKUP_COMPAT}, + {"auto", LOOKUP_AUTO}, + {} +}; + static const struct fs_parameter_spec f2fs_param_specs[] = { fsparam_enum("background_gc", Opt_gc_background, f2fs_param_background_gc), fsparam_flag("disable_roll_forward", Opt_disable_roll_forward), @@ -300,6 +308,7 @@ static const struct fs_parameter_spec f2fs_param_specs[] = { fsparam_enum("memory", Opt_memory_mode, f2fs_param_memory_mode), fsparam_flag("age_extent_cache", Opt_age_extent_cache), fsparam_enum("errors", Opt_errors, f2fs_param_errors), + fsparam_enum("lookup_mode", Opt_lookup_mode, f2fs_param_lookup_mode), {} }; @@ -336,6 +345,7 @@ static match_table_t f2fs_checkpoint_tokens = { #define F2FS_SPEC_discard_unit (1 << 21) #define F2FS_SPEC_memory_mode (1 << 22) #define F2FS_SPEC_errors (1 << 23) +#define F2FS_SPEC_lookup_mode (1 << 24) struct f2fs_fs_context { struct f2fs_mount_info info; @@ -1143,6 +1153,10 @@ static int f2fs_parse_param(struct fs_context *fc, struct fs_parameter *param) case Opt_nat_bits: ctx_set_opt(ctx, F2FS_MOUNT_NAT_BITS); break; + case Opt_lookup_mode: + F2FS_CTX_INFO(ctx).lookup_mode = result.uint_32; + ctx->spec_mask |= F2FS_SPEC_lookup_mode; + break; } return 0; } @@ -1652,6 +1666,8 @@ static void f2fs_apply_options(struct fs_context *fc, struct super_block *sb) F2FS_OPTION(sbi).memory_mode = F2FS_CTX_INFO(ctx).memory_mode; if (ctx->spec_mask & F2FS_SPEC_errors) F2FS_OPTION(sbi).errors = F2FS_CTX_INFO(ctx).errors; + if (ctx->spec_mask & F2FS_SPEC_lookup_mode) + F2FS_OPTION(sbi).lookup_mode = F2FS_CTX_INFO(ctx).lookup_mode; f2fs_apply_compression(fc, sb); f2fs_apply_test_dummy_encryption(fc, sb); @@ -2416,6 +2432,13 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) if (test_opt(sbi, NAT_BITS)) seq_puts(seq, ",nat_bits"); + if (F2FS_OPTION(sbi).lookup_mode == LOOKUP_PERF) + seq_show_option(seq, "lookup_mode", "perf"); + else if (F2FS_OPTION(sbi).lookup_mode == LOOKUP_COMPAT) + seq_show_option(seq, "lookup_mode", "compat"); + else if (F2FS_OPTION(sbi).lookup_mode == LOOKUP_AUTO) + seq_show_option(seq, "lookup_mode", "auto"); + return 0; } @@ -2480,6 +2503,8 @@ static void default_options(struct f2fs_sb_info *sbi, bool remount) #endif f2fs_build_fault_attr(sbi, 0, 0, FAULT_ALL); + + F2FS_OPTION(sbi).lookup_mode = LOOKUP_PERF; } #ifdef CONFIG_QUOTA From 4fff5db420fef91d439f87f6c0d439ef291b3dd2 Mon Sep 17 00:00:00 2001 From: Kim Tae Hyun Date: Sat, 2 Aug 2025 21:58:01 +0900 Subject: [PATCH 00259/11391] docs: update physical memory documentation by adding N_GENERIC_INITIATOR to enum node_states While reading physical_memory.rst, I noticed that N_GENERIC_INITIATOR has not been update from the node_states list, even though it's already added in commit 894c26a1c274b8eafbb4b1dad67e70e51a106061. Signed-off-by: Kim Tae Hyun Acked-by: Mike Rapoport (Microsoft) Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250802125801.10068-1-kimth0312@gmail.com --- Documentation/mm/physical_memory.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/mm/physical_memory.rst b/Documentation/mm/physical_memory.rst index 9af11b5bd145..b76183545e5b 100644 --- a/Documentation/mm/physical_memory.rst +++ b/Documentation/mm/physical_memory.rst @@ -171,6 +171,8 @@ nodes with particular properties as defined by ``enum node_states``: The node has memory(regular, high, movable) ``N_CPU`` The node has one or more CPUs +``N_GENERIC_INITIATOR`` + The node has one or more Generic Initiators For each node that has a property described above, the bit corresponding to the node ID in the ``node_states[]`` bitmask is set. From 1bd119da0b93d6d61891edf2b9d036800aba687f Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Mon, 4 Aug 2025 23:52:27 -0700 Subject: [PATCH 00260/11391] f2fs: add sysfs entry for effective lookup mode This commit introduces a new read-only sysfs entry at /sys/fs/f2fs//effective_lookup_mode. This entry displays the actual directory lookup mode F2FS is currently using. This is needed for debugging and verification, as the behavior is determined by both on-disk flags and mount options. Signed-off-by: Daniel Lee Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- Documentation/ABI/testing/sysfs-fs-f2fs | 15 +++++++++++++++ fs/f2fs/sysfs.c | 18 ++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs index bc0e7fefc39d..ce189acd1908 100644 --- a/Documentation/ABI/testing/sysfs-fs-f2fs +++ b/Documentation/ABI/testing/sysfs-fs-f2fs @@ -883,3 +883,18 @@ Date: June 2025 Contact: "Daeho Jeong" Description: Control GC algorithm for boost GC. 0: cost benefit, 1: greedy Default: 1 + +What: /sys/fs/f2fs//effective_lookup_mode +Date: August 2025 +Contact: "Daniel Lee" +Description: + This is a read-only entry to show the effective directory lookup mode + F2FS is currently using for casefolded directories. + This considers both the "lookup_mode" mount option and the on-disk + encoding flag, SB_ENC_NO_COMPAT_FALLBACK_FL. + + Possible values are: + - "perf": Hash-only lookup. + - "compat": Hash-based lookup with a linear search fallback enabled + - "auto:perf": lookup_mode is auto and fallback is disabled on-disk + - "auto:compat": lookup_mode is auto and fallback is enabled on-disk diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c index f736052dea50..82489c78aeda 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c @@ -281,6 +281,22 @@ static ssize_t encoding_flags_show(struct f2fs_attr *a, le16_to_cpu(F2FS_RAW_SUPER(sbi)->s_encoding_flags)); } +static ssize_t effective_lookup_mode_show(struct f2fs_attr *a, + struct f2fs_sb_info *sbi, char *buf) +{ + switch (F2FS_OPTION(sbi).lookup_mode) { + case LOOKUP_PERF: + return sysfs_emit(buf, "perf\n"); + case LOOKUP_COMPAT: + return sysfs_emit(buf, "compat\n"); + case LOOKUP_AUTO: + if (sb_no_casefold_compat_fallback(sbi->sb)) + return sysfs_emit(buf, "auto:perf\n"); + return sysfs_emit(buf, "auto:compat\n"); + } + return 0; +} + static ssize_t mounted_time_sec_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { @@ -1211,6 +1227,7 @@ F2FS_GENERAL_RO_ATTR(current_reserved_blocks); F2FS_GENERAL_RO_ATTR(unusable); F2FS_GENERAL_RO_ATTR(encoding); F2FS_GENERAL_RO_ATTR(encoding_flags); +F2FS_GENERAL_RO_ATTR(effective_lookup_mode); F2FS_GENERAL_RO_ATTR(mounted_time_sec); F2FS_GENERAL_RO_ATTR(main_blkaddr); F2FS_GENERAL_RO_ATTR(pending_discard); @@ -1329,6 +1346,7 @@ static struct attribute *f2fs_attrs[] = { ATTR_LIST(current_reserved_blocks), ATTR_LIST(encoding), ATTR_LIST(encoding_flags), + ATTR_LIST(effective_lookup_mode), ATTR_LIST(mounted_time_sec), #ifdef CONFIG_F2FS_STAT_FS ATTR_LIST(cp_foreground_calls), From 0fe1c6bec54ea68ed8c987b3890f2296364e77bb Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Tue, 5 Aug 2025 14:29:10 +0800 Subject: [PATCH 00261/11391] f2fs: fix to avoid overflow while left shift operation Should cast type of folio->index from pgoff_t to loff_t to avoid overflow while left shift operation. Fixes: 3265d3db1f16 ("f2fs: support partial truncation on compressed inode") Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/compress.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c index 5c1f47e45dab..6cd8902849cf 100644 --- a/fs/f2fs/compress.c +++ b/fs/f2fs/compress.c @@ -1245,7 +1245,7 @@ int f2fs_truncate_partial_cluster(struct inode *inode, u64 from, bool lock) for (i = cluster_size - 1; i >= 0; i--) { struct folio *folio = page_folio(rpages[i]); - loff_t start = folio->index << PAGE_SHIFT; + loff_t start = (loff_t)folio->index << PAGE_SHIFT; if (from <= start) { folio_zero_segment(folio, 0, folio_size(folio)); From 0b2cd5092139f499544c77b5107a74e5fdb3a386 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Wed, 6 Aug 2025 14:11:06 +0800 Subject: [PATCH 00262/11391] f2fs: fix to zero data after EOF for compressed file correctly generic/091 may fail, then it bisects to the bad commit ba8dac350faf ("f2fs: fix to zero post-eof page"). What will cause generic/091 to fail is something like below Testcase #1: 1. write 16k as compressed blocks 2. truncate to 12k 3. truncate to 20k 4. verify data in range of [12k, 16k], however data is not zero as expected Script of Testcase #1 mkfs.f2fs -f -O extra_attr,compression /dev/vdb mount -t f2fs -o compress_extension=* /dev/vdb /mnt/f2fs dd if=/dev/zero of=/mnt/f2fs/file bs=12k count=1 dd if=/dev/random of=/mnt/f2fs/file bs=4k count=1 seek=3 conv=notrunc sync truncate -s $((12*1024)) /mnt/f2fs/file truncate -s $((20*1024)) /mnt/f2fs/file dd if=/mnt/f2fs/file of=/mnt/f2fs/data bs=4k count=1 skip=3 od /mnt/f2fs/data umount /mnt/f2fs Analisys: in step 2), we will redirty all data pages from #0 to #3 in compressed cluster, and zero page #3, in step 3), f2fs_setattr() will call f2fs_zero_post_eof_page() to drop all page cache post eof, includeing dirtied page #3, in step 4) when we read data from page #3, it will decompressed cluster and extra random data to page #3, finally, we hit the non-zeroed data post eof. However, the commit ba8dac350faf ("f2fs: fix to zero post-eof page") just let the issue be reproduced easily, w/o the commit, it can reproduce this bug w/ below Testcase #2: 1. write 16k as compressed blocks 2. truncate to 8k 3. truncate to 12k 4. truncate to 20k 5. verify data in range of [12k, 16k], however data is not zero as expected Script of Testcase #2 mkfs.f2fs -f -O extra_attr,compression /dev/vdb mount -t f2fs -o compress_extension=* /dev/vdb /mnt/f2fs dd if=/dev/zero of=/mnt/f2fs/file bs=12k count=1 dd if=/dev/random of=/mnt/f2fs/file bs=4k count=1 seek=3 conv=notrunc sync truncate -s $((8*1024)) /mnt/f2fs/file truncate -s $((12*1024)) /mnt/f2fs/file truncate -s $((20*1024)) /mnt/f2fs/file echo 3 > /proc/sys/vm/drop_caches dd if=/mnt/f2fs/file of=/mnt/f2fs/data bs=4k count=1 skip=3 od /mnt/f2fs/data umount /mnt/f2fs Anlysis: in step 2), we will redirty all data pages from #0 to #3 in compressed cluster, and zero page #2 and #3, in step 3), we will truncate page #3 in page cache, in step 4), expand file size, in step 5), hit random data post eof w/ the same reason in Testcase #1. Root Cause: In f2fs_truncate_partial_cluster(), after we truncate partial data block on compressed cluster, all pages in cluster including the one post eof will be dirtied, after another tuncation, dirty page post eof will be dropped, however on-disk compressed cluster is still valid, it may include non-zero data post eof, result in exposing previous non-zero data post eof while reading. Fix: In f2fs_truncate_partial_cluster(), let change as below to fix: - call filemap_write_and_wait_range() to flush dirty page - call truncate_pagecache() to drop pages or zero partial page post eof - call f2fs_do_truncate_blocks() to truncate non-compress cluster to last valid block Fixes: 3265d3db1f16 ("f2fs: support partial truncation on compressed inode") Reported-by: Jan Prusakowski Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/compress.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c index 6cd8902849cf..72bc05b913af 100644 --- a/fs/f2fs/compress.c +++ b/fs/f2fs/compress.c @@ -1246,19 +1246,28 @@ int f2fs_truncate_partial_cluster(struct inode *inode, u64 from, bool lock) for (i = cluster_size - 1; i >= 0; i--) { struct folio *folio = page_folio(rpages[i]); loff_t start = (loff_t)folio->index << PAGE_SHIFT; + loff_t offset = from > start ? from - start : 0; - if (from <= start) { - folio_zero_segment(folio, 0, folio_size(folio)); - } else { - folio_zero_segment(folio, from - start, - folio_size(folio)); + folio_zero_segment(folio, offset, folio_size(folio)); + + if (from >= start) break; - } } f2fs_compress_write_end(inode, fsdata, start_idx, true); + + err = filemap_write_and_wait_range(inode->i_mapping, + round_down(from, cluster_size << PAGE_SHIFT), + LLONG_MAX); + if (err) + return err; + + truncate_pagecache(inode, from); + + err = f2fs_do_truncate_blocks(inode, + round_up(from, PAGE_SIZE), lock); } - return 0; + return err; } static int f2fs_write_compressed_pages(struct compress_ctx *cc, From cbba5038ee29f16f583978d6debe486503693c70 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Tue, 5 Aug 2025 14:29:12 +0800 Subject: [PATCH 00263/11391] f2fs: clean up f2fs_truncate_partial_cluster() Clean up codes as below: - avoid unnecessary "err > 0" check condition - use "1 << log_cluster_size" instead of F2FS_I(inode)->i_cluster_size No logic changes. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/compress.c | 48 +++++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c index 72bc05b913af..6ad8d3bc6df7 100644 --- a/fs/f2fs/compress.c +++ b/fs/f2fs/compress.c @@ -1215,9 +1215,11 @@ int f2fs_truncate_partial_cluster(struct inode *inode, u64 from, bool lock) { void *fsdata = NULL; struct page *pagep; + struct page **rpages; int log_cluster_size = F2FS_I(inode)->i_log_cluster_size; pgoff_t start_idx = from >> (PAGE_SHIFT + log_cluster_size) << log_cluster_size; + int i; int err; err = f2fs_is_compressed_cluster(inode, start_idx); @@ -1238,36 +1240,30 @@ int f2fs_truncate_partial_cluster(struct inode *inode, u64 from, bool lock) if (err <= 0) return err; - if (err > 0) { - struct page **rpages = fsdata; - int cluster_size = F2FS_I(inode)->i_cluster_size; - int i; + rpages = fsdata; - for (i = cluster_size - 1; i >= 0; i--) { - struct folio *folio = page_folio(rpages[i]); - loff_t start = (loff_t)folio->index << PAGE_SHIFT; - loff_t offset = from > start ? from - start : 0; + for (i = (1 << log_cluster_size) - 1; i >= 0; i--) { + struct folio *folio = page_folio(rpages[i]); + loff_t start = (loff_t)folio->index << PAGE_SHIFT; + loff_t offset = from > start ? from - start : 0; - folio_zero_segment(folio, offset, folio_size(folio)); + folio_zero_segment(folio, offset, folio_size(folio)); - if (from >= start) - break; - } - - f2fs_compress_write_end(inode, fsdata, start_idx, true); - - err = filemap_write_and_wait_range(inode->i_mapping, - round_down(from, cluster_size << PAGE_SHIFT), - LLONG_MAX); - if (err) - return err; - - truncate_pagecache(inode, from); - - err = f2fs_do_truncate_blocks(inode, - round_up(from, PAGE_SIZE), lock); + if (from >= start) + break; } - return err; + + f2fs_compress_write_end(inode, fsdata, start_idx, true); + + err = filemap_write_and_wait_range(inode->i_mapping, + round_down(from, 1 << log_cluster_size << PAGE_SHIFT), + LLONG_MAX); + if (err) + return err; + + truncate_pagecache(inode, from); + + return f2fs_do_truncate_blocks(inode, round_up(from, PAGE_SIZE), lock); } static int f2fs_write_compressed_pages(struct compress_ctx *cc, From 7069b5296e968d0e7d5fd6b825f221f0d766f3ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0t=C4=9Bp=C3=A1n=20N=C4=9Bmec?= Date: Tue, 29 Jul 2025 20:40:36 +0200 Subject: [PATCH 00264/11391] docs: admin-guide: update to current minimum pipe size default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pipe size limit used when the fs.pipe-user-pages-soft sysctl value is reached was increased from one to two pages in commit 46c4c9d1beb7; update the documentation to match the new reality. Fixes: 46c4c9d1beb7 ("pipe: increase minimum default pipe size to 2 pages") Signed-off-by: Štěpán Němec Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250729-pipedoc-v2-1-18b8e735a9c6@smrk.net --- Documentation/admin-guide/sysctl/fs.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/admin-guide/sysctl/fs.rst b/Documentation/admin-guide/sysctl/fs.rst index 6c54718c9d04..9b7f65c3efd8 100644 --- a/Documentation/admin-guide/sysctl/fs.rst +++ b/Documentation/admin-guide/sysctl/fs.rst @@ -164,8 +164,8 @@ pipe-user-pages-soft -------------------- Maximum total number of pages a non-privileged user may allocate for pipes -before the pipe size gets limited to a single page. Once this limit is reached, -new pipes will be limited to a single page in size for this user in order to +before the pipe size gets limited to two pages. Once this limit is reached, +new pipes will be limited to two pages in size for this user in order to limit total memory usage, and trying to increase them using ``fcntl()`` will be denied until usage goes below the limit again. The default value allows to allocate up to 1024 pipes at their default size. When set to 0, no limit is From 1f590377eb3c2680cb1101fa1a6a1f20a5fc4002 Mon Sep 17 00:00:00 2001 From: Ranganath V N Date: Sat, 26 Jul 2025 12:06:44 +0530 Subject: [PATCH 00265/11391] Documentation: Fix minor typos Corrected a few spelling errors and improved the phrasing changes since v1: --corrected as per review Signed-off-by: Ranganath V N Reviewed-by: Randy Dunlap Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250726063645.4156-1-vnranganath.20@gmail.com --- Documentation/arch/loongarch/irq-chip-model.rst | 4 ++-- Documentation/arch/x86/cpuinfo.rst | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/arch/loongarch/irq-chip-model.rst b/Documentation/arch/loongarch/irq-chip-model.rst index a7ecce11e445..8f5c3345109e 100644 --- a/Documentation/arch/loongarch/irq-chip-model.rst +++ b/Documentation/arch/loongarch/irq-chip-model.rst @@ -139,13 +139,13 @@ Feature EXTIOI_HAS_INT_ENCODE is part of standard EIOINTC. If it is 1, it indicates that CPU Interrupt Pin selection can be normal method rather than bitmap method, so interrupt can be routed to IP0 - IP15. -Feature EXTIOI_HAS_CPU_ENCODE is entension of V-EIOINTC. If it is 1, it +Feature EXTIOI_HAS_CPU_ENCODE is extension of V-EIOINTC. If it is 1, it indicates that CPU selection can be normal method rather than bitmap method, so interrupt can be routed to CPU0 - CPU255. EXTIOI_VIRT_CONFIG ------------------ -This register is read-write register, for compatibility intterupt routed uses +This register is read-write register, for compatibility interrupt routed uses the default method which is the same with standard EIOINTC. If the bit is set with 1, it indicated HW to use normal method rather than bitmap method. diff --git a/Documentation/arch/x86/cpuinfo.rst b/Documentation/arch/x86/cpuinfo.rst index dd8b7806944e..9f2e47c4b1c8 100644 --- a/Documentation/arch/x86/cpuinfo.rst +++ b/Documentation/arch/x86/cpuinfo.rst @@ -11,7 +11,7 @@ The list of feature flags in /proc/cpuinfo is not complete and represents an ill-fated attempt from long time ago to put feature flags in an easy to find place for userspace. -However, the amount of feature flags is growing by the CPU generation, +However, the number of feature flags is growing with each CPU generation, leading to unparseable and unwieldy /proc/cpuinfo. What is more, those feature flags do not even need to be in that file From 3fa1095979393d5b178264cc1bdfb473e80ab774 Mon Sep 17 00:00:00 2001 From: Kathiravan Thirumoorthy Date: Fri, 2 May 2025 18:47:49 +0530 Subject: [PATCH 00266/11391] dt-bindings: sram: qcom,imem: Document IPQ5424 compatible Add compatible for Qualcomm's IPQ5424 IMEM. Acked-by: Rob Herring (Arm) Signed-off-by: Kathiravan Thirumoorthy Link: https://lore.kernel.org/r/20250502-wdt_reset_reason-v3-1-b2dc7ace38ca@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/sram/qcom,imem.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/sram/qcom,imem.yaml b/Documentation/devicetree/bindings/sram/qcom,imem.yaml index 72d35e30c439..6a627c57ae2f 100644 --- a/Documentation/devicetree/bindings/sram/qcom,imem.yaml +++ b/Documentation/devicetree/bindings/sram/qcom,imem.yaml @@ -18,6 +18,7 @@ properties: items: - enum: - qcom,apq8064-imem + - qcom,ipq5424-imem - qcom,msm8226-imem - qcom,msm8974-imem - qcom,msm8976-imem From 2115dc3e3376b7bd5021950b45eebbcd992e9be9 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 24 Jul 2025 08:34:42 -0700 Subject: [PATCH 00267/11391] docs: filesystems: sysfs: Recommend sysfs_emit() for new code only The advantages of converting existing sysfs show() methods to sysfs_emit() and sysfs_emit_at() do not outweigh the risk of introducing bugs. Hence recommend sysfs_emit() and sysfs_emit_at() only for new implementations of show() methods. Cc: Greg Kroah-Hartman Cc: James Bottomley Cc: Martin K. Petersen Signed-off-by: Bart Van Assche Reviewed-by: Martin K. Petersen Acked-by: Greg Kroah-Hartman Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250724153449.2433395-1-bvanassche@acm.org --- Documentation/filesystems/sysfs.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/filesystems/sysfs.rst b/Documentation/filesystems/sysfs.rst index c32993bc83c7..624e4f51212e 100644 --- a/Documentation/filesystems/sysfs.rst +++ b/Documentation/filesystems/sysfs.rst @@ -243,8 +243,8 @@ Other notes: - show() methods should return the number of bytes printed into the buffer. -- show() should only use sysfs_emit() or sysfs_emit_at() when formatting - the value to be returned to user space. +- New implementations of show() methods should only use sysfs_emit() or + sysfs_emit_at() when formatting the value to be returned to user space. - store() should return the number of bytes used from the buffer. If the entire buffer has been used, just return the count argument. From 0e6608d4938eb209616e8673c95364bb2a7d55bd Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Sun, 3 Aug 2025 18:22:40 +0800 Subject: [PATCH 00268/11391] fscrypt: Remove redundant __GFP_NOWARN GFP_NOWAIT already includes __GFP_NOWARN, so let's remove the redundant __GFP_NOWARN. Signed-off-by: Qianfeng Rong Link: https://lore.kernel.org/r/20250803102243.623705-3-rongqianfeng@vivo.com Signed-off-by: Eric Biggers --- fs/crypto/bio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c index 486fcb2ecf13..e92967e20e2a 100644 --- a/fs/crypto/bio.c +++ b/fs/crypto/bio.c @@ -148,7 +148,7 @@ int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, */ for (i = 0; i < nr_pages; i++) { pages[i] = fscrypt_alloc_bounce_page(i == 0 ? GFP_NOFS : - GFP_NOWAIT | __GFP_NOWARN); + GFP_NOWAIT); if (!pages[i]) break; } From 690de2902dca98aec96de004428c020ca902f047 Mon Sep 17 00:00:00 2001 From: Wojciech Siudy Date: Tue, 3 Jun 2025 14:47:20 +0200 Subject: [PATCH 00269/11391] i2c: muxes: pca954x: Use reset controller only Fallback to legacy reset-gpios is no more needed, because the framework can use reset-gpios properity now as well. Signed-off-by: Wojciech Siudy [wsa: fixed whitespace issue] Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-pca954x.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index b9f370c9f018..a9ddd548781c 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -118,7 +118,6 @@ struct pca954x { raw_spinlock_t lock; struct regulator *supply; - struct gpio_desc *reset_gpio; struct reset_control *reset_cont; }; @@ -527,17 +526,6 @@ static int pca954x_get_reset(struct device *dev, struct pca954x *data) if (IS_ERR(data->reset_cont)) return dev_err_probe(dev, PTR_ERR(data->reset_cont), "Failed to get reset\n"); - else if (data->reset_cont) - return 0; - - /* - * fallback to legacy reset-gpios - */ - data->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(data->reset_gpio)) { - return dev_err_probe(dev, PTR_ERR(data->reset_gpio), - "Failed to get reset gpio"); - } return 0; } @@ -546,8 +534,6 @@ static void pca954x_reset_deassert(struct pca954x *data) { if (data->reset_cont) reset_control_deassert(data->reset_cont); - else - gpiod_set_value_cansleep(data->reset_gpio, 0); } /* @@ -589,7 +575,7 @@ static int pca954x_probe(struct i2c_client *client) if (ret) goto fail_cleanup; - if (data->reset_cont || data->reset_gpio) { + if (data->reset_cont) { udelay(1); pca954x_reset_deassert(data); /* Give the chip some time to recover. */ From 94c29677640312fcfab261bddc1006bc43efe4ba Mon Sep 17 00:00:00 2001 From: Wojciech Siudy Date: Tue, 3 Jun 2025 14:47:21 +0200 Subject: [PATCH 00270/11391] i2c: muxes: pca954x: Reset if (de)select fails If the channel selection or deselection times out, it indicates a failure in the mux's I2C subsystem. Without sending a reset pulse, a power-on-reset of the entire device would be required to restore communication. The datasheet specifies a minimum hold time of 4 ns for the reset pulse, but due to the path's capacitance and themux having its own clock, it is recommended to extend this to approximately 1 us. Since reset controller is used, there is no need to take care of other devices sharing the same reset line. Signed-off-by: Wojciech Siudy [wsa: removed superfluous prinout, unneeded braces and fixed indent] Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-pca954x.c | 34 ++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index a9ddd548781c..75c8d08fa24e 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -315,6 +315,25 @@ static u8 pca954x_regval(struct pca954x *data, u8 chan) return 1 << chan; } +static void pca954x_reset_assert(struct pca954x *data) +{ + if (data->reset_cont) + reset_control_assert(data->reset_cont); +} + +static void pca954x_reset_deassert(struct pca954x *data) +{ + if (data->reset_cont) + reset_control_deassert(data->reset_cont); +} + +static void pca954x_reset_mux(struct pca954x *data) +{ + pca954x_reset_assert(data); + udelay(1); + pca954x_reset_deassert(data); +} + static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan) { struct pca954x *data = i2c_mux_priv(muxc); @@ -328,6 +347,8 @@ static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan) ret = pca954x_reg_write(muxc->parent, client, regval); data->last_chan = ret < 0 ? 0 : regval; } + if (ret == -ETIMEDOUT && data->reset_cont) + pca954x_reset_mux(data); return ret; } @@ -337,6 +358,7 @@ static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan) struct pca954x *data = i2c_mux_priv(muxc); struct i2c_client *client = data->client; s32 idle_state; + int ret = 0; idle_state = READ_ONCE(data->idle_state); if (idle_state >= 0) @@ -346,8 +368,10 @@ static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan) if (idle_state == MUX_IDLE_DISCONNECT) { /* Deselect active channel */ data->last_chan = 0; - return pca954x_reg_write(muxc->parent, client, - data->last_chan); + ret = pca954x_reg_write(muxc->parent, client, + data->last_chan); + if (ret == -ETIMEDOUT && data->reset_cont) + pca954x_reset_mux(data); } /* otherwise leave as-is */ @@ -530,12 +554,6 @@ static int pca954x_get_reset(struct device *dev, struct pca954x *data) return 0; } -static void pca954x_reset_deassert(struct pca954x *data) -{ - if (data->reset_cont) - reset_control_deassert(data->reset_cont); -} - /* * I2C init/probing/exit functions */ From de68c05189cc4508c3ac4e1e44da1ddb16b1bceb Mon Sep 17 00:00:00 2001 From: Andrea Righi Date: Mon, 4 Aug 2025 13:04:49 +0200 Subject: [PATCH 00271/11391] tools/sched_ext: Receive updates from SCX repo Receive tools/sched_ext updates form https://github.com/sched-ext/scx to sync userspace bits: - basic BPF arena allocator abstractions, - additional process flags definitions, - fixed is_migration_disabled() helper, - separate out user_exit_info BPF and user space code. This also fixes the following warning when building the selftests: tools/sched_ext/include/scx/common.bpf.h:550:9: warning: 'likely' macro redefined [-Wmacro-redefined] 550 | #define likely(x) __builtin_expect(!!(x), 1) | ^ Co-developed-by: Cheng-Yang Chou Signed-off-by: Andrea Righi Signed-off-by: Tejun Heo --- .../include/scx/bpf_arena_common.bpf.h | 175 ++++++++++++++++++ .../sched_ext/include/scx/bpf_arena_common.h | 33 ++++ tools/sched_ext/include/scx/common.bpf.h | 102 +++++++++- tools/sched_ext/include/scx/common.h | 5 +- tools/sched_ext/include/scx/compat.bpf.h | 5 + .../include/scx/user_exit_info.bpf.h | 40 ++++ tools/sched_ext/include/scx/user_exit_info.h | 49 +---- .../include/scx/user_exit_info_common.h | 30 +++ tools/sched_ext/scx_central.bpf.c | 2 +- tools/sched_ext/scx_central.c | 1 + tools/sched_ext/scx_flatcg.bpf.c | 2 +- tools/sched_ext/scx_flatcg.c | 2 + tools/sched_ext/scx_simple.c | 2 + 13 files changed, 388 insertions(+), 60 deletions(-) create mode 100644 tools/sched_ext/include/scx/bpf_arena_common.bpf.h create mode 100644 tools/sched_ext/include/scx/bpf_arena_common.h create mode 100644 tools/sched_ext/include/scx/user_exit_info.bpf.h create mode 100644 tools/sched_ext/include/scx/user_exit_info_common.h diff --git a/tools/sched_ext/include/scx/bpf_arena_common.bpf.h b/tools/sched_ext/include/scx/bpf_arena_common.bpf.h new file mode 100644 index 000000000000..4366fb3c91ce --- /dev/null +++ b/tools/sched_ext/include/scx/bpf_arena_common.bpf.h @@ -0,0 +1,175 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ +#pragma once + +#ifndef PAGE_SIZE +#define PAGE_SIZE __PAGE_SIZE +/* + * for older kernels try sizeof(struct genradix_node) + * or flexible: + * static inline long __bpf_page_size(void) { + * return bpf_core_enum_value(enum page_size_enum___l, __PAGE_SIZE___l) ?: sizeof(struct genradix_node); + * } + * but generated code is not great. + */ +#endif + +#if defined(__BPF_FEATURE_ADDR_SPACE_CAST) && !defined(BPF_ARENA_FORCE_ASM) +#define __arena __attribute__((address_space(1))) +#define __arena_global __attribute__((address_space(1))) +#define cast_kern(ptr) /* nop for bpf prog. emitted by LLVM */ +#define cast_user(ptr) /* nop for bpf prog. emitted by LLVM */ +#else + +/* emit instruction: + * rX = rX .off = BPF_ADDR_SPACE_CAST .imm32 = (dst_as << 16) | src_as + * + * This is a workaround for LLVM compiler versions without + * __BPF_FEATURE_ADDR_SPACE_CAST that do not automatically cast between arena + * pointers and native kernel/userspace ones. In this case we explicitly do so + * with cast_kern() and cast_user(). E.g., in the Linux kernel tree, + * tools/testing/selftests/bpf includes tests that use these macros to implement + * linked lists and hashtables backed by arena memory. In sched_ext, we use + * cast_kern() and cast_user() for compatibility with older LLVM toolchains. + */ +#ifndef bpf_addr_space_cast +#define bpf_addr_space_cast(var, dst_as, src_as)\ + asm volatile(".byte 0xBF; \ + .ifc %[reg], r0; \ + .byte 0x00; \ + .endif; \ + .ifc %[reg], r1; \ + .byte 0x11; \ + .endif; \ + .ifc %[reg], r2; \ + .byte 0x22; \ + .endif; \ + .ifc %[reg], r3; \ + .byte 0x33; \ + .endif; \ + .ifc %[reg], r4; \ + .byte 0x44; \ + .endif; \ + .ifc %[reg], r5; \ + .byte 0x55; \ + .endif; \ + .ifc %[reg], r6; \ + .byte 0x66; \ + .endif; \ + .ifc %[reg], r7; \ + .byte 0x77; \ + .endif; \ + .ifc %[reg], r8; \ + .byte 0x88; \ + .endif; \ + .ifc %[reg], r9; \ + .byte 0x99; \ + .endif; \ + .short %[off]; \ + .long %[as]" \ + : [reg]"+r"(var) \ + : [off]"i"(BPF_ADDR_SPACE_CAST) \ + , [as]"i"((dst_as << 16) | src_as)); +#endif + +#define __arena +#define __arena_global SEC(".addr_space.1") +#define cast_kern(ptr) bpf_addr_space_cast(ptr, 0, 1) +#define cast_user(ptr) bpf_addr_space_cast(ptr, 1, 0) +#endif + +void __arena* bpf_arena_alloc_pages(void *map, void __arena *addr, __u32 page_cnt, + int node_id, __u64 flags) __ksym __weak; +void bpf_arena_free_pages(void *map, void __arena *ptr, __u32 page_cnt) __ksym __weak; + +/* + * Note that cond_break can only be portably used in the body of a breakable + * construct, whereas can_loop can be used anywhere. + */ +#ifdef TEST +#define can_loop true +#define __cond_break(expr) expr +#else +#ifdef __BPF_FEATURE_MAY_GOTO +#define can_loop \ + ({ __label__ l_break, l_continue; \ + bool ret = true; \ + asm volatile goto("may_goto %l[l_break]" \ + :::: l_break); \ + goto l_continue; \ + l_break: ret = false; \ + l_continue:; \ + ret; \ + }) + +#define __cond_break(expr) \ + ({ __label__ l_break, l_continue; \ + asm volatile goto("may_goto %l[l_break]" \ + :::: l_break); \ + goto l_continue; \ + l_break: expr; \ + l_continue:; \ + }) +#else +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define can_loop \ + ({ __label__ l_break, l_continue; \ + bool ret = true; \ + asm volatile goto("1:.byte 0xe5; \ + .byte 0; \ + .long ((%l[l_break] - 1b - 8) / 8) & 0xffff; \ + .short 0" \ + :::: l_break); \ + goto l_continue; \ + l_break: ret = false; \ + l_continue:; \ + ret; \ + }) + +#define __cond_break(expr) \ + ({ __label__ l_break, l_continue; \ + asm volatile goto("1:.byte 0xe5; \ + .byte 0; \ + .long ((%l[l_break] - 1b - 8) / 8) & 0xffff; \ + .short 0" \ + :::: l_break); \ + goto l_continue; \ + l_break: expr; \ + l_continue:; \ + }) +#else +#define can_loop \ + ({ __label__ l_break, l_continue; \ + bool ret = true; \ + asm volatile goto("1:.byte 0xe5; \ + .byte 0; \ + .long (((%l[l_break] - 1b - 8) / 8) & 0xffff) << 16; \ + .short 0" \ + :::: l_break); \ + goto l_continue; \ + l_break: ret = false; \ + l_continue:; \ + ret; \ + }) + +#define __cond_break(expr) \ + ({ __label__ l_break, l_continue; \ + asm volatile goto("1:.byte 0xe5; \ + .byte 0; \ + .long (((%l[l_break] - 1b - 8) / 8) & 0xffff) << 16; \ + .short 0" \ + :::: l_break); \ + goto l_continue; \ + l_break: expr; \ + l_continue:; \ + }) +#endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */ +#endif /* __BPF_FEATURE_MAY_GOTO */ +#endif /* TEST */ + +#define cond_break __cond_break(break) +#define cond_break_label(label) __cond_break(goto label) + + +void bpf_preempt_disable(void) __weak __ksym; +void bpf_preempt_enable(void) __weak __ksym; diff --git a/tools/sched_ext/include/scx/bpf_arena_common.h b/tools/sched_ext/include/scx/bpf_arena_common.h new file mode 100644 index 000000000000..10141db0b59d --- /dev/null +++ b/tools/sched_ext/include/scx/bpf_arena_common.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ +#pragma once + +#ifndef arena_container_of +#define arena_container_of(ptr, type, member) \ + ({ \ + void __arena *__mptr = (void __arena *)(ptr); \ + ((type *)(__mptr - offsetof(type, member))); \ + }) +#endif + +/* Provide the definition of PAGE_SIZE. */ +#include + +#define __arena +#define __arg_arena +#define cast_kern(ptr) /* nop for user space */ +#define cast_user(ptr) /* nop for user space */ +char __attribute__((weak)) arena[1]; + +#ifndef offsetof +#define offsetof(type, member) ((unsigned long)&((type *)0)->member) +#endif + +static inline void __arena* bpf_arena_alloc_pages(void *map, void *addr, __u32 page_cnt, + int node_id, __u64 flags) +{ + return NULL; +} +static inline void bpf_arena_free_pages(void *map, void __arena *ptr, __u32 page_cnt) +{ +} diff --git a/tools/sched_ext/include/scx/common.bpf.h b/tools/sched_ext/include/scx/common.bpf.h index d4e21558e982..86abdb3c3142 100644 --- a/tools/sched_ext/include/scx/common.bpf.h +++ b/tools/sched_ext/include/scx/common.bpf.h @@ -24,14 +24,26 @@ #include #include #include -#include "user_exit_info.h" +#include "user_exit_info.bpf.h" #include "enum_defs.autogen.h" +#define PF_IDLE 0x00000002 /* I am an IDLE thread */ +#define PF_IO_WORKER 0x00000010 /* Task is an IO worker */ #define PF_WQ_WORKER 0x00000020 /* I'm a workqueue worker */ +#define PF_KCOMPACTD 0x00010000 /* I am kcompactd */ +#define PF_KSWAPD 0x00020000 /* I am kswapd */ #define PF_KTHREAD 0x00200000 /* I am a kernel thread */ #define PF_EXITING 0x00000004 #define CLOCK_MONOTONIC 1 +#ifndef NR_CPUS +#define NR_CPUS 1024 +#endif + +#ifndef NUMA_NO_NODE +#define NUMA_NO_NODE (-1) +#endif + extern int LINUX_KERNEL_VERSION __kconfig; extern const char CONFIG_CC_VERSION_TEXT[64] __kconfig __weak; extern const char CONFIG_LOCALVERSION[64] __kconfig __weak; @@ -107,6 +119,9 @@ void scx_bpf_events(struct scx_event_stats *events, size_t events__sz) __ksym __ static inline __attribute__((format(printf, 1, 2))) void ___scx_bpf_bstr_format_checker(const char *fmt, ...) {} +#define SCX_STRINGIFY(x) #x +#define SCX_TOSTRING(x) SCX_STRINGIFY(x) + /* * Helper macro for initializing the fmt and variadic argument inputs to both * bstr exit kfuncs. Callers to this function should use ___fmt and ___param to @@ -141,13 +156,15 @@ void ___scx_bpf_bstr_format_checker(const char *fmt, ...) {} * scx_bpf_error() wraps the scx_bpf_error_bstr() kfunc with variadic arguments * instead of an array of u64. Invoking this macro will cause the scheduler to * exit in an erroneous state, with diagnostic information being passed to the - * user. + * user. It appends the file and line number to aid debugging. */ #define scx_bpf_error(fmt, args...) \ ({ \ - scx_bpf_bstr_preamble(fmt, args) \ + scx_bpf_bstr_preamble( \ + __FILE__ ":" SCX_TOSTRING(__LINE__) ": " fmt, ##args) \ scx_bpf_error_bstr(___fmt, ___param, sizeof(___param)); \ - ___scx_bpf_bstr_format_checker(fmt, ##args); \ + ___scx_bpf_bstr_format_checker( \ + __FILE__ ":" SCX_TOSTRING(__LINE__) ": " fmt, ##args); \ }) /* @@ -229,6 +246,7 @@ BPF_PROG(name, ##args) * be a pointer to the area. Use `MEMBER_VPTR(*ptr, .member)` instead of * `MEMBER_VPTR(ptr, ->member)`. */ +#ifndef MEMBER_VPTR #define MEMBER_VPTR(base, member) (typeof((base) member) *) \ ({ \ u64 __base = (u64)&(base); \ @@ -245,6 +263,7 @@ BPF_PROG(name, ##args) [max]"i"(sizeof(base) - sizeof((base) member))); \ __addr; \ }) +#endif /* MEMBER_VPTR */ /** * ARRAY_ELEM_PTR - Obtain the verified pointer to an array element @@ -260,6 +279,7 @@ BPF_PROG(name, ##args) * size of the array to compute the max, which will result in rejection by * the verifier. */ +#ifndef ARRAY_ELEM_PTR #define ARRAY_ELEM_PTR(arr, i, n) (typeof(arr[i]) *) \ ({ \ u64 __base = (u64)arr; \ @@ -274,7 +294,7 @@ BPF_PROG(name, ##args) [max]"r"(sizeof(arr[0]) * ((n) - 1))); \ __addr; \ }) - +#endif /* ARRAY_ELEM_PTR */ /* * BPF declarations and helpers @@ -438,8 +458,27 @@ static __always_inline const struct cpumask *cast_mask(struct bpf_cpumask *mask) */ static inline bool is_migration_disabled(const struct task_struct *p) { - if (bpf_core_field_exists(p->migration_disabled)) - return p->migration_disabled; + /* + * Testing p->migration_disabled in a BPF code is tricky because the + * migration is _always_ disabled while running the BPF code. + * The prolog (__bpf_prog_enter) and epilog (__bpf_prog_exit) for BPF + * code execution disable and re-enable the migration of the current + * task, respectively. So, the _current_ task of the sched_ext ops is + * always migration-disabled. Moreover, p->migration_disabled could be + * two or greater when a sched_ext ops BPF code (e.g., ops.tick) is + * executed in the middle of the other BPF code execution. + * + * Therefore, we should decide that the _current_ task is + * migration-disabled only when its migration_disabled count is greater + * than one. In other words, when p->migration_disabled == 1, there is + * an ambiguity, so we should check if @p is the current task or not. + */ + if (bpf_core_field_exists(p->migration_disabled)) { + if (p->migration_disabled == 1) + return bpf_get_current_task_btf() != p; + else + return p->migration_disabled; + } return false; } @@ -476,7 +515,7 @@ static inline s64 time_delta(u64 after, u64 before) */ static inline bool time_after(u64 a, u64 b) { - return (s64)(b - a) < 0; + return (s64)(b - a) < 0; } /** @@ -500,7 +539,7 @@ static inline bool time_before(u64 a, u64 b) */ static inline bool time_after_eq(u64 a, u64 b) { - return (s64)(a - b) >= 0; + return (s64)(a - b) >= 0; } /** @@ -547,9 +586,15 @@ static inline bool time_in_range_open(u64 a, u64 b, u64 c) */ /* useful compiler attributes */ +#ifndef likely #define likely(x) __builtin_expect(!!(x), 1) +#endif +#ifndef unlikely #define unlikely(x) __builtin_expect(!!(x), 0) +#endif +#ifndef __maybe_unused #define __maybe_unused __attribute__((__unused__)) +#endif /* * READ/WRITE_ONCE() are from kernel (include/asm-generic/rwonce.h). They @@ -632,6 +677,26 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s __u.__val; \ }) +/* + * __calc_avg - Calculate exponential weighted moving average (EWMA) with + * @old and @new values. @decay represents how large the @old value remains. + * With a larger @decay value, the moving average changes slowly, exhibiting + * fewer fluctuations. + */ +#define __calc_avg(old, new, decay) ({ \ + typeof(decay) thr = 1 << (decay); \ + typeof(old) ret; \ + if (((old) < thr) || ((new) < thr)) { \ + if (((old) == 1) && ((new) == 0)) \ + ret = 0; \ + else \ + ret = ((old) - ((old) >> 1)) + ((new) >> 1); \ + } else { \ + ret = ((old) - ((old) >> (decay))) + ((new) >> (decay)); \ + } \ + ret; \ +}) + /* * log2_u32 - Compute the base 2 logarithm of a 32-bit exponential value. * @v: The value for which we're computing the base 2 logarithm. @@ -662,6 +727,25 @@ static inline u32 log2_u64(u64 v) return log2_u32(v) + 1; } +/* + * sqrt_u64 - Calculate the square root of value @x using Newton's method. + */ +static inline u64 __sqrt_u64(u64 x) +{ + if (x == 0 || x == 1) + return x; + + u64 r = ((1ULL << 32) > x) ? x : (1ULL << 32); + + for (int i = 0; i < 8; ++i) { + u64 q = x / r; + if (r <= q) + break; + r = (r + q) >> 1; + } + return r; +} + /* * Return a value proportionally scaled to the task's weight. */ diff --git a/tools/sched_ext/include/scx/common.h b/tools/sched_ext/include/scx/common.h index 1dc76bd84296..b3c6372bcf81 100644 --- a/tools/sched_ext/include/scx/common.h +++ b/tools/sched_ext/include/scx/common.h @@ -75,8 +75,9 @@ typedef int64_t s64; #include "enums.h" /* not available when building kernel tools/sched_ext */ -#if __has_include() -#include +#if __has_include() +#include "bpf_arena_common.h" +#include #endif #endif /* __SCHED_EXT_COMMON_H */ diff --git a/tools/sched_ext/include/scx/compat.bpf.h b/tools/sched_ext/include/scx/compat.bpf.h index 9252e1a00556..36e0cd2fd4ed 100644 --- a/tools/sched_ext/include/scx/compat.bpf.h +++ b/tools/sched_ext/include/scx/compat.bpf.h @@ -38,6 +38,7 @@ void scx_bpf_dispatch_from_dsq_set_slice___compat(struct bpf_iter_scx_dsq *it__i void scx_bpf_dispatch_from_dsq_set_vtime___compat(struct bpf_iter_scx_dsq *it__iter, u64 vtime) __ksym __weak; bool scx_bpf_dispatch_from_dsq___compat(struct bpf_iter_scx_dsq *it__iter, struct task_struct *p, u64 dsq_id, u64 enq_flags) __ksym __weak; bool scx_bpf_dispatch_vtime_from_dsq___compat(struct bpf_iter_scx_dsq *it__iter, struct task_struct *p, u64 dsq_id, u64 enq_flags) __ksym __weak; +int bpf_cpumask_populate(struct cpumask *dst, void *src, size_t src__sz) __ksym __weak; #define scx_bpf_dsq_insert(p, dsq_id, slice, enq_flags) \ (bpf_ksym_exists(scx_bpf_dsq_insert) ? \ @@ -82,6 +83,10 @@ bool scx_bpf_dispatch_vtime_from_dsq___compat(struct bpf_iter_scx_dsq *it__iter, scx_bpf_dispatch_vtime_from_dsq___compat((it__iter), (p), (dsq_id), (enq_flags)) : \ false)) +#define __COMPAT_bpf_cpumask_populate(cpumask, src, size__sz) \ + (bpf_ksym_exists(bpf_cpumask_populate) ? \ + (bpf_cpumask_populate(cpumask, src, size__sz)) : -EOPNOTSUPP) + #define scx_bpf_dispatch(p, dsq_id, slice, enq_flags) \ _Static_assert(false, "scx_bpf_dispatch() renamed to scx_bpf_dsq_insert()") diff --git a/tools/sched_ext/include/scx/user_exit_info.bpf.h b/tools/sched_ext/include/scx/user_exit_info.bpf.h new file mode 100644 index 000000000000..e7ac6611a990 --- /dev/null +++ b/tools/sched_ext/include/scx/user_exit_info.bpf.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Define struct user_exit_info which is shared between BPF and userspace parts + * to communicate exit status and other information. + * + * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. + * Copyright (c) 2022 Tejun Heo + * Copyright (c) 2022 David Vernet + */ + +#ifndef __USER_EXIT_INFO_BPF_H +#define __USER_EXIT_INFO_BPF_H + +#ifndef LSP +#include "vmlinux.h" +#endif +#include + +#include "user_exit_info_common.h" + +#define UEI_DEFINE(__name) \ + char RESIZABLE_ARRAY(data, __name##_dump); \ + const volatile u32 __name##_dump_len; \ + struct user_exit_info __name SEC(".data") + +#define UEI_RECORD(__uei_name, __ei) ({ \ + bpf_probe_read_kernel_str(__uei_name.reason, \ + sizeof(__uei_name.reason), (__ei)->reason); \ + bpf_probe_read_kernel_str(__uei_name.msg, \ + sizeof(__uei_name.msg), (__ei)->msg); \ + bpf_probe_read_kernel_str(__uei_name##_dump, \ + __uei_name##_dump_len, (__ei)->dump); \ + if (bpf_core_field_exists((__ei)->exit_code)) \ + __uei_name.exit_code = (__ei)->exit_code; \ + /* use __sync to force memory barrier */ \ + __sync_val_compare_and_swap(&__uei_name.kind, __uei_name.kind, \ + (__ei)->kind); \ +}) + +#endif /* __USER_EXIT_INFO_BPF_H */ diff --git a/tools/sched_ext/include/scx/user_exit_info.h b/tools/sched_ext/include/scx/user_exit_info.h index 66f856640ee7..399697fa372f 100644 --- a/tools/sched_ext/include/scx/user_exit_info.h +++ b/tools/sched_ext/include/scx/user_exit_info.h @@ -10,55 +10,11 @@ #ifndef __USER_EXIT_INFO_H #define __USER_EXIT_INFO_H -#ifdef LSP -#define __bpf__ -#include "../vmlinux.h" -#endif - -enum uei_sizes { - UEI_REASON_LEN = 128, - UEI_MSG_LEN = 1024, - UEI_DUMP_DFL_LEN = 32768, -}; - -struct user_exit_info { - int kind; - s64 exit_code; - char reason[UEI_REASON_LEN]; - char msg[UEI_MSG_LEN]; -}; - -#ifdef __bpf__ - -#ifndef LSP -#include "vmlinux.h" -#endif -#include - -#define UEI_DEFINE(__name) \ - char RESIZABLE_ARRAY(data, __name##_dump); \ - const volatile u32 __name##_dump_len; \ - struct user_exit_info __name SEC(".data") - -#define UEI_RECORD(__uei_name, __ei) ({ \ - bpf_probe_read_kernel_str(__uei_name.reason, \ - sizeof(__uei_name.reason), (__ei)->reason); \ - bpf_probe_read_kernel_str(__uei_name.msg, \ - sizeof(__uei_name.msg), (__ei)->msg); \ - bpf_probe_read_kernel_str(__uei_name##_dump, \ - __uei_name##_dump_len, (__ei)->dump); \ - if (bpf_core_field_exists((__ei)->exit_code)) \ - __uei_name.exit_code = (__ei)->exit_code; \ - /* use __sync to force memory barrier */ \ - __sync_val_compare_and_swap(&__uei_name.kind, __uei_name.kind, \ - (__ei)->kind); \ -}) - -#else /* !__bpf__ */ - #include #include +#include "user_exit_info_common.h" + /* no need to call the following explicitly if SCX_OPS_LOAD() is used */ #define UEI_SET_SIZE(__skel, __ops_name, __uei_name) ({ \ u32 __len = (__skel)->struct_ops.__ops_name->exit_dump_len ?: UEI_DUMP_DFL_LEN; \ @@ -114,5 +70,4 @@ enum uei_ecode_mask { #define UEI_ECODE_RESTART(__ecode) (UEI_ECODE_SYS_ACT((__ecode)) == SCX_ECODE_ACT_RESTART) -#endif /* __bpf__ */ #endif /* __USER_EXIT_INFO_H */ diff --git a/tools/sched_ext/include/scx/user_exit_info_common.h b/tools/sched_ext/include/scx/user_exit_info_common.h new file mode 100644 index 000000000000..2d0981aedd89 --- /dev/null +++ b/tools/sched_ext/include/scx/user_exit_info_common.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Define struct user_exit_info which is shared between BPF and userspace parts + * to communicate exit status and other information. + * + * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. + * Copyright (c) 2022 Tejun Heo + * Copyright (c) 2022 David Vernet + */ +#ifndef __USER_EXIT_INFO_COMMON_H +#define __USER_EXIT_INFO_COMMON_H + +#ifdef LSP +#include "../vmlinux.h" +#endif + +enum uei_sizes { + UEI_REASON_LEN = 128, + UEI_MSG_LEN = 1024, + UEI_DUMP_DFL_LEN = 32768, +}; + +struct user_exit_info { + int kind; + s64 exit_code; + char reason[UEI_REASON_LEN]; + char msg[UEI_MSG_LEN]; +}; + +#endif /* __USER_EXIT_INFO_COMMON_H */ diff --git a/tools/sched_ext/scx_central.bpf.c b/tools/sched_ext/scx_central.bpf.c index 50bc1737c167..55df8b798865 100644 --- a/tools/sched_ext/scx_central.bpf.c +++ b/tools/sched_ext/scx_central.bpf.c @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * A central FIFO sched_ext scheduler which demonstrates the followings: + * A central FIFO sched_ext scheduler which demonstrates the following: * * a. Making all scheduling decisions from one CPU: * diff --git a/tools/sched_ext/scx_central.c b/tools/sched_ext/scx_central.c index 6ba6e610eeaa..55931a4cd71c 100644 --- a/tools/sched_ext/scx_central.c +++ b/tools/sched_ext/scx_central.c @@ -61,6 +61,7 @@ int main(int argc, char **argv) skel->rodata->nr_cpu_ids = libbpf_num_possible_cpus(); skel->rodata->slice_ns = __COMPAT_ENUM_OR_ZERO("scx_public_consts", "SCX_SLICE_DFL"); + assert(skel->rodata->nr_cpu_ids > 0); assert(skel->rodata->nr_cpu_ids <= INT32_MAX); while ((opt = getopt(argc, argv, "s:c:pvh")) != -1) { diff --git a/tools/sched_ext/scx_flatcg.bpf.c b/tools/sched_ext/scx_flatcg.bpf.c index fdc7170639e6..2c720e3ecad5 100644 --- a/tools/sched_ext/scx_flatcg.bpf.c +++ b/tools/sched_ext/scx_flatcg.bpf.c @@ -950,5 +950,5 @@ SCX_OPS_DEFINE(flatcg_ops, .cgroup_move = (void *)fcg_cgroup_move, .init = (void *)fcg_init, .exit = (void *)fcg_exit, - .flags = SCX_OPS_ENQ_EXITING, + .flags = SCX_OPS_HAS_CGROUP_WEIGHT | SCX_OPS_ENQ_EXITING, .name = "flatcg"); diff --git a/tools/sched_ext/scx_flatcg.c b/tools/sched_ext/scx_flatcg.c index 6dd423eeb4ff..cd85eb401179 100644 --- a/tools/sched_ext/scx_flatcg.c +++ b/tools/sched_ext/scx_flatcg.c @@ -6,6 +6,7 @@ */ #include #include +#include #include #include #include @@ -137,6 +138,7 @@ int main(int argc, char **argv) skel = SCX_OPS_OPEN(flatcg_ops, scx_flatcg); skel->rodata->nr_cpus = libbpf_num_possible_cpus(); + assert(skel->rodata->nr_cpus > 0); skel->rodata->cgrp_slice_ns = __COMPAT_ENUM_OR_ZERO("scx_public_consts", "SCX_SLICE_DFL"); while ((opt = getopt(argc, argv, "s:i:dfvh")) != -1) { diff --git a/tools/sched_ext/scx_simple.c b/tools/sched_ext/scx_simple.c index 76d83199545c..06d4b13bf76b 100644 --- a/tools/sched_ext/scx_simple.c +++ b/tools/sched_ext/scx_simple.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +42,7 @@ static void sigint_handler(int simple) static void read_stats(struct scx_simple *skel, __u64 *stats) { int nr_cpus = libbpf_num_possible_cpus(); + assert(nr_cpus > 0); __u64 cnts[2][nr_cpus]; __u32 idx; From 450a80623e3b8bb5dae59e0d56046fc3d0a88f3b Mon Sep 17 00:00:00 2001 From: Sricharan Ramabadhran Date: Thu, 12 Jun 2025 10:46:14 +0400 Subject: [PATCH 00272/11391] arm64: dts: qcom: ipq5018: Add tsens node IPQ5018 has tsens V1.0 IP with 5 sensors, though 4 are in use. There is no RPM, so tsens has to be manually enabled. Adding the tsens and nvmem nodes and adding 4 thermal sensors (zones). The critical trip temperature is set to 120'C with an action to reboot. In addition, adding a cooling device to the CPU thermal zone which uses CPU frequency scaling. Reviewed-by: Dmitry Baryshkov Signed-off-by: Sricharan Ramabadhran Signed-off-by: George Moussalem Reviewed-by: Konrad Dybcio [bjorn: Added tsens-v1 fallback compatible, per binding] Link: https://lore.kernel.org/r/20250612-ipq5018-tsens-v13-2-a210f3683240@outlook.com --- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 178 ++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/ipq5018.dtsi b/arch/arm64/boot/dts/qcom/ipq5018.dtsi index 130360014c5e..baf583c75e76 100644 --- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi @@ -9,6 +9,7 @@ #include #include #include +#include / { interrupt-parent = <&intc>; @@ -39,6 +40,7 @@ cpu0: cpu@0 { next-level-cache = <&l2_0>; clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>; operating-points-v2 = <&cpu_opp_table>; + #cooling-cells = <2>; }; cpu1: cpu@1 { @@ -49,6 +51,7 @@ cpu1: cpu@1 { next-level-cache = <&l2_0>; clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>; operating-points-v2 = <&cpu_opp_table>; + #cooling-cells = <2>; }; l2_0: l2-cache { @@ -182,6 +185,117 @@ pcie0_phy: phy@86000 { status = "disabled"; }; + qfprom: qfprom@a0000 { + compatible = "qcom,ipq5018-qfprom", "qcom,qfprom"; + reg = <0x000a0000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + tsens_mode: mode@249 { + reg = <0x249 0x1>; + bits = <0 3>; + }; + + tsens_base1: base1@249 { + reg = <0x249 0x2>; + bits = <3 8>; + }; + + tsens_base2: base2@24a { + reg = <0x24a 0x2>; + bits = <3 8>; + }; + + tsens_s0_p1: s0-p1@24b { + reg = <0x24b 0x2>; + bits = <2 6>; + }; + + tsens_s0_p2: s0-p2@24c { + reg = <0x24c 0x1>; + bits = <1 6>; + }; + + tsens_s1_p1: s1-p1@24c { + reg = <0x24c 0x2>; + bits = <7 6>; + }; + + tsens_s1_p2: s1-p2@24d { + reg = <0x24d 0x2>; + bits = <5 6>; + }; + + tsens_s2_p1: s2-p1@24e { + reg = <0x24e 0x2>; + bits = <3 6>; + }; + + tsens_s2_p2: s2-p2@24f { + reg = <0x24f 0x1>; + bits = <1 6>; + }; + + tsens_s3_p1: s3-p1@24f { + reg = <0x24f 0x2>; + bits = <7 6>; + }; + + tsens_s3_p2: s3-p2@250 { + reg = <0x250 0x2>; + bits = <5 6>; + }; + + tsens_s4_p1: s4-p1@251 { + reg = <0x251 0x2>; + bits = <3 6>; + }; + + tsens_s4_p2: s4-p2@254 { + reg = <0x254 0x1>; + bits = <0 6>; + }; + }; + + tsens: thermal-sensor@4a9000 { + compatible = "qcom,ipq5018-tsens", "qcom,tsens-v1"; + reg = <0x004a9000 0x1000>, + <0x004a8000 0x1000>; + + nvmem-cells = <&tsens_mode>, + <&tsens_base1>, + <&tsens_base2>, + <&tsens_s0_p1>, + <&tsens_s0_p2>, + <&tsens_s1_p1>, + <&tsens_s1_p2>, + <&tsens_s2_p1>, + <&tsens_s2_p2>, + <&tsens_s3_p1>, + <&tsens_s3_p2>, + <&tsens_s4_p1>, + <&tsens_s4_p2>; + + nvmem-cell-names = "mode", + "base1", + "base2", + "s0_p1", + "s0_p2", + "s1_p1", + "s1_p2", + "s2_p1", + "s2_p2", + "s3_p1", + "s3_p2", + "s4_p1", + "s4_p2"; + + interrupts = ; + interrupt-names = "uplow"; + #qcom,sensors = <5>; + #thermal-sensor-cells = <1>; + }; + tlmm: pinctrl@1000000 { compatible = "qcom,ipq5018-tlmm"; reg = <0x01000000 0x300000>; @@ -631,6 +745,70 @@ pcie@0 { }; }; + thermal-zones { + cpu-thermal { + thermal-sensors = <&tsens 2>; + + trips { + cpu-critical { + temperature = <120000>; + hysteresis = <1000>; + type = "critical"; + }; + + cpu_alert: cpu-passive { + temperature = <100000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu_alert>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + + gephy-thermal { + thermal-sensors = <&tsens 4>; + + trips { + gephy-critical { + temperature = <120000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + top-glue-thermal { + thermal-sensors = <&tsens 3>; + + trips { + top-glue-critical { + temperature = <120000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + ubi32-thermal { + thermal-sensors = <&tsens 1>; + + trips { + ubi32-critical { + temperature = <120000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + }; + timer { compatible = "arm,armv8-timer"; interrupts = , From e08d75e4834cb9a6224bfa090fce0e6259113d7a Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 21 Jun 2025 21:20:02 +0300 Subject: [PATCH 00273/11391] arm64: dts: qcom: sdm845: rename DisplayPort labels Rename DP labels to have mdss_ prefix, so that corresponding device nodes are grouped together. Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250621-sdm845-dp-rename-v1-1-6f7f13443b43@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index c0f466d96630..2311ebd515d7 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -4089,7 +4089,7 @@ port@2 { reg = <2>; usb_1_qmpphy_dp_in: endpoint { - remote-endpoint = <&dp_out>; + remote-endpoint = <&mdss_dp_out>; }; }; }; @@ -4603,7 +4603,7 @@ ports { port@0 { reg = <0>; dpu_intf0_out: endpoint { - remote-endpoint = <&dp_in>; + remote-endpoint = <&mdss_dp_in>; }; }; @@ -4682,14 +4682,14 @@ ports { #size-cells = <0>; port@0 { reg = <0>; - dp_in: endpoint { + mdss_dp_in: endpoint { remote-endpoint = <&dpu_intf0_out>; }; }; port@1 { reg = <1>; - dp_out: endpoint { + mdss_dp_out: endpoint { remote-endpoint = <&usb_1_qmpphy_dp_in>; }; }; From 5bde57b9cd3c769f5f4c85c021c37e2d151ca228 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 18 Jun 2025 20:49:51 +0300 Subject: [PATCH 00274/11391] arm64: dts: qcom: sar2130p: use TAG_ALWAYS for MDSS's mdp0-mem path Switch the main memory interconnect of the MDSS device to use QCOM_ICC_TAG_ALWAYS instead of _ACTIVE_ONLY. Fixes: 541d0b2f4dcd ("arm64: dts: qcom: sar2130p: add display nodes") Suggested-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250618-sar2130p-fix-mdss-v1-1-78c2fb9e9fba@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sar2130p.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sar2130p.dtsi b/arch/arm64/boot/dts/qcom/sar2130p.dtsi index e400ea4cdee8..6d7d4f05d502 100644 --- a/arch/arm64/boot/dts/qcom/sar2130p.dtsi +++ b/arch/arm64/boot/dts/qcom/sar2130p.dtsi @@ -2036,8 +2036,8 @@ mdss: display-subsystem@ae00000 { power-domains = <&dispcc MDSS_GDSC>; - interconnects = <&mmss_noc MASTER_MDP QCOM_ICC_TAG_ACTIVE_ONLY - &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>, + interconnects = <&mmss_noc MASTER_MDP QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY &config_noc SLAVE_DISPLAY_CFG QCOM_ICC_TAG_ACTIVE_ONLY>; interconnect-names = "mdp0-mem", "cpu-cfg"; From b1f622224b8e5da3d08dac33ad76b0672c21eded Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 18 Jun 2025 20:49:52 +0300 Subject: [PATCH 00275/11391] arm64: dts: qcom: sar2130p: correct VBIF region size for MDSS Correct the VBIF region size for the display device on the SAR1230P platform. Fixes: 541d0b2f4dcd ("arm64: dts: qcom: sar2130p: add display nodes") Reported-by: Konrad Dybcio Closes: https://lore.kernel.org/all/c14dfd37-7d12-40c3-8281-fd0a7410813e@oss.qualcomm.com/ Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250618-sar2130p-fix-mdss-v1-2-78c2fb9e9fba@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sar2130p.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sar2130p.dtsi b/arch/arm64/boot/dts/qcom/sar2130p.dtsi index 6d7d4f05d502..d9948360cc01 100644 --- a/arch/arm64/boot/dts/qcom/sar2130p.dtsi +++ b/arch/arm64/boot/dts/qcom/sar2130p.dtsi @@ -2053,7 +2053,7 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, mdss_mdp: display-controller@ae01000 { compatible = "qcom,sar2130p-dpu"; reg = <0x0 0x0ae01000 0x0 0x8f000>, - <0x0 0x0aeb0000 0x0 0x2008>; + <0x0 0x0aeb0000 0x0 0x3000>; reg-names = "mdp", "vbif"; From e2a01c3b1033ae39c2153ab5e84ae7167016826c Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 18 Jun 2025 20:49:53 +0300 Subject: [PATCH 00276/11391] arm64: dts: qcom: sar2130p: use defines for DSI PHY clocks Use defined IDs to reference DSI PHY clocks instead of using raw numbers. Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250618-sar2130p-fix-mdss-v1-3-78c2fb9e9fba@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sar2130p.dtsi | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sar2130p.dtsi b/arch/arm64/boot/dts/qcom/sar2130p.dtsi index d9948360cc01..38f7869616ff 100644 --- a/arch/arm64/boot/dts/qcom/sar2130p.dtsi +++ b/arch/arm64/boot/dts/qcom/sar2130p.dtsi @@ -3,6 +3,7 @@ * Copyright (c) 2024, Linaro Limited */ +#include #include #include #include @@ -2237,8 +2238,8 @@ mdss_dsi0: dsi@ae94000 { assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, <&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>; - assigned-clock-parents = <&mdss_dsi0_phy 0>, - <&mdss_dsi0_phy 1>; + assigned-clock-parents = <&mdss_dsi0_phy DSI_BYTE_PLL_CLK>, + <&mdss_dsi0_phy DSI_PIXEL_PLL_CLK>; operating-points-v2 = <&mdss_dsi_opp_table>; @@ -2333,8 +2334,8 @@ mdss_dsi1: dsi@ae96000 { assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE1_CLK_SRC>, <&dispcc DISP_CC_MDSS_PCLK1_CLK_SRC>; - assigned-clock-parents = <&mdss_dsi1_phy 0>, - <&mdss_dsi1_phy 1>; + assigned-clock-parents = <&mdss_dsi1_phy DSI_BYTE_PLL_CLK>, + <&mdss_dsi1_phy DSI_PIXEL_PLL_CLK>; operating-points-v2 = <&mdss_dsi_opp_table>; @@ -2392,10 +2393,10 @@ dispcc: clock-controller@af00000 { <&rpmhcc RPMH_CXO_CLK_A>, <&gcc GCC_DISP_AHB_CLK>, <&sleep_clk>, - <&mdss_dsi0_phy 0>, - <&mdss_dsi0_phy 1>, - <&mdss_dsi1_phy 0>, - <&mdss_dsi1_phy 1>, + <&mdss_dsi0_phy DSI_BYTE_PLL_CLK>, + <&mdss_dsi0_phy DSI_PIXEL_PLL_CLK>, + <&mdss_dsi1_phy DSI_BYTE_PLL_CLK>, + <&mdss_dsi1_phy DSI_PIXEL_PLL_CLK>, <&usb_dp_qmpphy QMP_USB43DP_DP_LINK_CLK>, <&usb_dp_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>, <0>, /* dp1 */ From c02716951e665181aecf59c663622689a576bccb Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sun, 8 Jun 2025 19:16:05 +0300 Subject: [PATCH 00277/11391] arm64: dts: qcom: sdm850-lenovo-yoga-c630: add routing for second USB connector On Lenovo Yoga C630 second (left) Type-C port is not connected to the SoC directly. Instead it has a USB hub, which also powers on the onboard USB camera. Describe these signal lines properly. Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250608-c630-ports-v1-1-e4951db96efa@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/sdm850-lenovo-yoga-c630.dts | 104 +++++++++++++++++- 1 file changed, 102 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts b/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts index 8ef6db3be6e3..480192c86fb7 100644 --- a/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts +++ b/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts @@ -421,9 +421,46 @@ connector@1 { data-role = "host"; /* - * connected to the onboard USB hub, orientation is - * handled by the controller + * connected to the onboard USB hub, each pair of lanes + * (and D+/D- pair) is connected to a separate port on + * the hub. */ + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + ucsi1_hs_in_1: endpoint@1 { + reg = <1>; + remote-endpoint = <&usb_hub_2_1>; + }; + + ucsi1_hs_in_2: endpoint@2 { + reg = <2>; + remote-endpoint = <&usb_hub_2_2>; + }; + }; + + port@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + ucsi1_ss_in_1: endpoint@1 { + reg = <1>; + remote-endpoint = <&usb_hub_3_1>; + }; + + ucsi1_ss_in_2: endpoint@2 { + reg = <2>; + remote-endpoint = <&usb_hub_3_2>; + }; + }; + }; }; }; }; @@ -842,6 +879,69 @@ &usb_2 { &usb_2_dwc3 { dr_mode = "host"; + #address-cells = <1>; + #size-cells = <0>; + + usb_hub_2_x: hub@1 { + compatible = "usb5e3,610"; + reg = <1>; + peer-hub = <&usb_hub_3_x>; + #address-cells = <1>; + #size-cells = <0>; + + camera@3 { + compatible = "usb4f2,b61e"; + reg = <3>; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + + usb_hub_2_1: endpoint { + remote-endpoint = <&ucsi1_hs_in_1>; + }; + }; + + port@2 { + reg = <2>; + + usb_hub_2_2: endpoint { + remote-endpoint = <&ucsi1_hs_in_2>; + }; + }; + }; + }; + + usb_hub_3_x: hub@2 { + compatible = "usb5e3,620"; + reg = <2>; + peer-hub = <&usb_hub_2_x>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + + usb_hub_3_1: endpoint { + remote-endpoint = <&ucsi1_ss_in_1>; + }; + }; + + port@2 { + reg = <2>; + + usb_hub_3_2: endpoint { + remote-endpoint = <&ucsi1_ss_in_2>; + }; + }; + }; + }; }; &usb_2_hsphy { From 0403e42f2fbb43fe38d645fb399727327e1002c6 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 2 Jun 2025 10:23:35 +0300 Subject: [PATCH 00278/11391] arm64: dts: qcom: sa8775p: rename bus clock to follow the bindings DT bindings for the DPU SA8775P declare the first clock to be "nrt_bus", not just "bus". Fix the DT file accordingly. Fixes: 2f39d2d46c73 ("arm64: dts: qcom: sa8775p: add display dt nodes for MDSS0 and DPU") Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250602-sa8775p-fix-dts-v1-1-f9f6271b33a3@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/lemans.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi index 0a9c92aa7234..322abd0294be 100644 --- a/arch/arm64/boot/dts/qcom/lemans.dtsi +++ b/arch/arm64/boot/dts/qcom/lemans.dtsi @@ -4417,7 +4417,7 @@ mdss0_mdp: display-controller@ae01000 { <&dispcc0 MDSS_DISP_CC_MDSS_MDP_LUT_CLK>, <&dispcc0 MDSS_DISP_CC_MDSS_MDP_CLK>, <&dispcc0 MDSS_DISP_CC_MDSS_VSYNC_CLK>; - clock-names = "bus", + clock-names = "nrt_bus", "iface", "lut", "core", From 3e0252ea5d91ac21c6b606f71f42733b526646df Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 4 Jun 2025 16:40:28 +0300 Subject: [PATCH 00279/11391] dt-bindings: arm: qcom: add qcom,sm6150 fallback compatible to QCS615 QCS615 SoC is based on the earlier mobile chip SM6150. Add corresponding compatible string to follow established practice for IoT chips. Signed-off-by: Dmitry Baryshkov Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250604-qcs615-sm6150-v1-1-2f01fd46c365@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/arm/qcom.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml index bf5f3beb320b..1b705079c1ae 100644 --- a/Documentation/devicetree/bindings/arm/qcom.yaml +++ b/Documentation/devicetree/bindings/arm/qcom.yaml @@ -87,6 +87,7 @@ description: | sm6115 sm6115p sm6125 + sm6150 sm6350 sm6375 sm7125 @@ -949,6 +950,7 @@ properties: - enum: - qcom,qcs615-ride - const: qcom,qcs615 + - const: qcom,sm6150 - items: - enum: From 9af4e5351229a4364030c6102babc6af831fbb84 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 4 Jun 2025 16:40:29 +0300 Subject: [PATCH 00280/11391] arm64: dts: qcom: rename qcs615.dtsi to sm6150.dtsi The established practice is to have the base DTSI file named after the base SoC name (see examples of qrb5165-rb5.dts vs sm8250.dtsi, qrb2210-rb1.dts vs qcm2290.dtsi, qrb4210-rb2.dts vs sm4250.dtsi vs sm6115.dtsi). Rename the SoC dtsi file accordingly and add "qcom,sm6150" as a fallback compat string. Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250604-qcs615-sm6150-v1-2-2f01fd46c365@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/qcs615-ride.dts | 4 ++-- arch/arm64/boot/dts/qcom/{qcs615.dtsi => sm6150.dtsi} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename arch/arm64/boot/dts/qcom/{qcs615.dtsi => sm6150.dtsi} (100%) diff --git a/arch/arm64/boot/dts/qcom/qcs615-ride.dts b/arch/arm64/boot/dts/qcom/qcs615-ride.dts index a6652e4817d1..fdad6388f6f7 100644 --- a/arch/arm64/boot/dts/qcom/qcs615-ride.dts +++ b/arch/arm64/boot/dts/qcom/qcs615-ride.dts @@ -7,11 +7,11 @@ #include #include #include -#include "qcs615.dtsi" +#include "sm6150.dtsi" #include "pm8150.dtsi" / { model = "Qualcomm Technologies, Inc. QCS615 Ride"; - compatible = "qcom,qcs615-ride", "qcom,qcs615"; + compatible = "qcom,qcs615-ride", "qcom,qcs615", "qcom,sm6150"; chassis-type = "embedded"; aliases { diff --git a/arch/arm64/boot/dts/qcom/qcs615.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi similarity index 100% rename from arch/arm64/boot/dts/qcom/qcs615.dtsi rename to arch/arm64/boot/dts/qcom/sm6150.dtsi From 8ff47ada5e95577fdb8a1da903d37c75636808e6 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Sat, 14 Jun 2025 21:05:19 +0200 Subject: [PATCH 00281/11391] arm64: dts: qcom: msm8916: Drop venus-enc/decoder node Commit 687bfbba5a1c ("media: venus: Add support for static video encoder/decoder declarations") invalidates these empty nodes. Get rid of them. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250614-topic-encdec-v1-1-f974c3e9cb43@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/msm8916.dtsi | 8 -------- 1 file changed, 8 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi index de9fdc0dfc5f..b50c7e6e0bfc 100644 --- a/arch/arm64/boot/dts/qcom/msm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi @@ -1834,14 +1834,6 @@ venus: video-codec@1d00000 { iommus = <&apps_iommu 5>; memory-region = <&venus_mem>; status = "disabled"; - - video-decoder { - compatible = "venus-decoder"; - }; - - video-encoder { - compatible = "venus-encoder"; - }; }; apps_iommu: iommu@1ef0000 { From 1f67c23f98bd64d4034898af5a149304a09080be Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Sat, 14 Jun 2025 21:05:20 +0200 Subject: [PATCH 00282/11391] arm64: dts: qcom: sc7180: Drop venus-enc/decoder node Commit 687bfbba5a1c ("media: venus: Add support for static video encoder/decoder declarations") invalidates these empty nodes. Get rid of them. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250614-topic-encdec-v1-2-f974c3e9cb43@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc7180.dtsi | 8 -------- 1 file changed, 8 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sc7180.dtsi b/arch/arm64/boot/dts/qcom/sc7180.dtsi index 3afb69921be3..8f827f1d8515 100644 --- a/arch/arm64/boot/dts/qcom/sc7180.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7180.dtsi @@ -3095,14 +3095,6 @@ venus: video-codec@aa00000 { <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_VENUS_CFG 0>; interconnect-names = "video-mem", "cpu-cfg"; - video-decoder { - compatible = "venus-decoder"; - }; - - video-encoder { - compatible = "venus-encoder"; - }; - venus_opp_table: opp-table { compatible = "operating-points-v2"; From dce1122f076c7f4acc809cd2c9b7e3ed3fe19a4c Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Sat, 14 Jun 2025 21:05:21 +0200 Subject: [PATCH 00283/11391] arm64: dts: qcom: sdm845: Drop venus-enc/decoder node Commit 687bfbba5a1c ("media: venus: Add support for static video encoder/decoder declarations") invalidates these empty nodes. Get rid of them. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250614-topic-encdec-v1-3-f974c3e9cb43@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 8 -------- 1 file changed, 8 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 2311ebd515d7..828b55cb6baf 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -4286,14 +4286,6 @@ venus: video-codec@aa00000 { status = "disabled"; - video-core0 { - compatible = "venus-decoder"; - }; - - video-core1 { - compatible = "venus-encoder"; - }; - venus_opp_table: opp-table { compatible = "operating-points-v2"; From 71ef5e99e925fc4e3f8bfd071a546c4dd6b45825 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Sat, 14 Jun 2025 21:05:22 +0200 Subject: [PATCH 00284/11391] arm64: dts: qcom: sm8250: Drop venus-enc/decoder node Commit 687bfbba5a1c ("media: venus: Add support for static video encoder/decoder declarations") invalidates these empty nodes. Get rid of them. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250614-topic-encdec-v1-4-f974c3e9cb43@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8250.dtsi | 8 -------- 1 file changed, 8 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qcom/sm8250.dtsi index 2b3442a74a5a..244339cfbed5 100644 --- a/arch/arm64/boot/dts/qcom/sm8250.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi @@ -4338,14 +4338,6 @@ venus: video-codec@aa00000 { status = "disabled"; - video-decoder { - compatible = "venus-decoder"; - }; - - video-encoder { - compatible = "venus-encoder"; - }; - venus_opp_table: opp-table { compatible = "operating-points-v2"; From 1aa0b4e364361ccaf047a34308527ccf7441feef Mon Sep 17 00:00:00 2001 From: Akhil P Oommen Date: Mon, 23 Jun 2025 19:42:09 +0530 Subject: [PATCH 00285/11391] arm64: dts: qcom: x1p42100: Add GPU support X1P42100 SoC has a new GPU called Adreno X1-45 which is a smaller version of Adreno X1-85 GPU. Describe this new GPU and also add the secure gpu firmware path that should used for X1P42100 CRD. Tested-by: Jens Glathe Reviewed-by: Konrad Dybcio Tested-by: Aleksandrs Vinarskis # x1-26-100 Signed-off-by: Akhil P Oommen Link: https://lore.kernel.org/r/20250623-x1p-adreno-v4-4-d2575c839cbb@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/x1e80100.dtsi | 7 ++ arch/arm64/boot/dts/qcom/x1p42100-crd.dts | 4 + arch/arm64/boot/dts/qcom/x1p42100.dtsi | 120 +++++++++++++++++++++- 3 files changed, 129 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/x1e80100.dtsi b/arch/arm64/boot/dts/qcom/x1e80100.dtsi index a9a7bb676c6f..5e9a8fa3cf96 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100.dtsi +++ b/arch/arm64/boot/dts/qcom/x1e80100.dtsi @@ -8251,6 +8251,13 @@ sbsa_watchdog: watchdog@1c840000 { interrupts = ; }; + qfprom: efuse@221c8000 { + compatible = "qcom,x1e80100-qfprom", "qcom,qfprom"; + reg = <0 0x221c8000 0 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + }; + pmu@24091000 { compatible = "qcom,x1e80100-llcc-bwmon", "qcom,sc7280-llcc-bwmon"; reg = <0 0x24091000 0 0x1000>; diff --git a/arch/arm64/boot/dts/qcom/x1p42100-crd.dts b/arch/arm64/boot/dts/qcom/x1p42100-crd.dts index cf07860a63e9..cf999c2cf8d4 100644 --- a/arch/arm64/boot/dts/qcom/x1p42100-crd.dts +++ b/arch/arm64/boot/dts/qcom/x1p42100-crd.dts @@ -15,3 +15,7 @@ / { model = "Qualcomm Technologies, Inc. X1P42100 CRD"; compatible = "qcom,x1p42100-crd", "qcom,x1p42100"; }; + +&gpu_zap_shader { + firmware-name = "qcom/x1p42100/gen71500_zap.mbn"; +}; diff --git a/arch/arm64/boot/dts/qcom/x1p42100.dtsi b/arch/arm64/boot/dts/qcom/x1p42100.dtsi index 9af9e707f982..b7326be4d064 100644 --- a/arch/arm64/boot/dts/qcom/x1p42100.dtsi +++ b/arch/arm64/boot/dts/qcom/x1p42100.dtsi @@ -17,6 +17,7 @@ /delete-node/ &cpu_pd9; /delete-node/ &cpu_pd10; /delete-node/ &cpu_pd11; +/delete-node/ &gpu_opp_table; /delete-node/ &pcie3_phy; /delete-node/ &thermal_zones; @@ -24,9 +25,117 @@ &gcc { compatible = "qcom,x1p42100-gcc", "qcom,x1e80100-gcc"; }; -/* The GPU is physically different and will be brought up later */ +&gmu { + compatible = "qcom,adreno-gmu-x145.0", "qcom,adreno-gmu"; +}; + &gpu { - /delete-property/ compatible; + compatible = "qcom,adreno-43030c00", "qcom,adreno"; + + nvmem-cells = <&gpu_speed_bin>; + nvmem-cell-names = "speed_bin"; + + gpu_opp_table: opp-table { + compatible = "operating-points-v2-adreno", "operating-points-v2"; + + opp-1400000000 { + opp-hz = /bits/ 64 <1400000000>; + opp-level = ; + opp-peak-kBps = <16500000>; + qcom,opp-acd-level = <0xa8295ffd>; + opp-supported-hw = <0x3>; + }; + + opp-1250000000 { + opp-hz = /bits/ 64 <1250000000>; + opp-level = ; + opp-peak-kBps = <16500000>; + qcom,opp-acd-level = <0x882a5ffd>; + opp-supported-hw = <0x7>; + }; + + opp-1107000000 { + opp-hz = /bits/ 64 <1107000000>; + opp-level = ; + opp-peak-kBps = <16500000>; + qcom,opp-acd-level = <0x882a5ffd>; + opp-supported-hw = <0xf>; + }; + + opp-1014000000 { + opp-hz = /bits/ 64 <1014000000>; + opp-level = ; + opp-peak-kBps = <14398438>; + qcom,opp-acd-level = <0xa82a5ffd>; + opp-supported-hw = <0xf>; + }; + + opp-940000000 { + opp-hz = /bits/ 64 <940000000>; + opp-level = ; + opp-peak-kBps = <14398438>; + qcom,opp-acd-level = <0xa82a5ffd>; + opp-supported-hw = <0xf>; + }; + + opp-825000000 { + opp-hz = /bits/ 64 <825000000>; + opp-level = ; + opp-peak-kBps = <12449219>; + qcom,opp-acd-level = <0x882b5ffd>; + opp-supported-hw = <0xf>; + }; + + opp-720000000 { + opp-hz = /bits/ 64 <720000000>; + opp-level = ; + opp-peak-kBps = <10687500>; + qcom,opp-acd-level = <0xa82c5ffd>; + opp-supported-hw = <0xf>; + }; + + opp-666000000-0 { + opp-hz = /bits/ 64 <666000000>; + opp-level = ; + opp-peak-kBps = <8171875>; + qcom,opp-acd-level = <0xa82d5ffd>; + opp-supported-hw = <0xf>; + }; + + /* Only applicable for SKUs which has 666Mhz as Fmax */ + opp-666000000-1 { + opp-hz = /bits/ 64 <666000000>; + opp-level = ; + opp-peak-kBps = <16500000>; + qcom,opp-acd-level = <0xa82d5ffd>; + opp-supported-hw = <0x10>; + }; + + opp-550000000 { + opp-hz = /bits/ 64 <550000000>; + opp-level = ; + opp-peak-kBps = <6074219>; + qcom,opp-acd-level = <0x882e5ffd>; + opp-supported-hw = <0x1f>; + }; + + opp-380000000 { + opp-hz = /bits/ 64 <380000000>; + opp-level = ; + opp-peak-kBps = <3000000>; + qcom,opp-acd-level = <0xc82f5ffd>; + opp-supported-hw = <0x1f>; + }; + + opp-280000000 { + opp-hz = /bits/ 64 <280000000>; + opp-level = ; + opp-peak-kBps = <2136719>; + qcom,opp-acd-level = <0xc82f5ffd>; + opp-supported-hw = <0x1f>; + }; + }; + }; &gpucc { @@ -42,6 +151,13 @@ &pcie6a_phy { compatible = "qcom,x1p42100-qmp-gen4x4-pcie-phy"; }; +&qfprom { + gpu_speed_bin: gpu-speed-bin@119 { + reg = <0x119 0x2>; + bits = <7 9>; + }; +}; + &soc { /* The PCIe3 PHY on X1P42100 uses a different IP block */ pcie3_phy: phy@1bd4000 { From ebf6fc452ad61f79d801f68f8298c7d00796c580 Mon Sep 17 00:00:00 2001 From: Jens Glathe Date: Tue, 24 Jun 2025 08:46:00 +0200 Subject: [PATCH 00286/11391] arm64: dts: qcom: x1e80100-lenovo-yoga-slim7x: add Bluetooth support To enable Bluetooth pwrseq appears to be required for the WCN7850. Add the nodes from QCP, add the TODO hint for vreg_wcn_0p95 and vreg_wcn_1p9 Add uart14 for the BT interface. Tested-by: Anthony Ruhier Signed-off-by: Jens Glathe Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250624-slim7x-bt-v3-1-7ada18058419@oldschoolsolutions.biz Signed-off-by: Bjorn Andersson --- .../dts/qcom/x1e80100-lenovo-yoga-slim7x.dts | 143 ++++++++++++++++++ 1 file changed, 143 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts b/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts index dad0f11e8e85..d02f8d4f7baf 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts +++ b/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts @@ -18,6 +18,7 @@ / { aliases { serial0 = &uart21; + serial1 = &uart14; }; chosen { @@ -404,6 +405,107 @@ vph_pwr: regulator-vph-pwr { regulator-always-on; regulator-boot-on; }; + + vreg_wcn_3p3: regulator-wcn-3p3 { + compatible = "regulator-fixed"; + + regulator-name = "VREG_WCN_3P3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + gpio = <&tlmm 214 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-0 = <&wcn_sw_en>; + pinctrl-names = "default"; + + regulator-boot-on; + }; + + /* + * TODO: These two regulators are actually part of the removable M.2 + * card and not the CRD mainboard. Need to describe this differently. + * Functionally it works correctly, because all we need to do is to + * turn on the actual 3.3V supply above. + */ + vreg_wcn_0p95: regulator-wcn-0p95 { + compatible = "regulator-fixed"; + + regulator-name = "VREG_WCN_0P95"; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <950000>; + + vin-supply = <&vreg_wcn_3p3>; + }; + + vreg_wcn_1p9: regulator-wcn-1p9 { + compatible = "regulator-fixed"; + + regulator-name = "VREG_WCN_1P9"; + regulator-min-microvolt = <1900000>; + regulator-max-microvolt = <1900000>; + + vin-supply = <&vreg_wcn_3p3>; + }; + + wcn7850-pmu { + compatible = "qcom,wcn7850-pmu"; + + vdd-supply = <&vreg_wcn_0p95>; + vddio-supply = <&vreg_l15b_1p8>; + vddaon-supply = <&vreg_wcn_0p95>; + vdddig-supply = <&vreg_wcn_0p95>; + vddrfa1p2-supply = <&vreg_wcn_1p9>; + vddrfa1p8-supply = <&vreg_wcn_1p9>; + + wlan-enable-gpios = <&tlmm 117 GPIO_ACTIVE_HIGH>; + bt-enable-gpios = <&tlmm 116 GPIO_ACTIVE_HIGH>; + + pinctrl-0 = <&wcn_wlan_bt_en>; + pinctrl-names = "default"; + + regulators { + vreg_pmu_rfa_cmn: ldo0 { + regulator-name = "vreg_pmu_rfa_cmn"; + }; + + vreg_pmu_aon_0p59: ldo1 { + regulator-name = "vreg_pmu_aon_0p59"; + }; + + vreg_pmu_wlcx_0p8: ldo2 { + regulator-name = "vreg_pmu_wlcx_0p8"; + }; + + vreg_pmu_wlmx_0p85: ldo3 { + regulator-name = "vreg_pmu_wlmx_0p85"; + }; + + vreg_pmu_btcmx_0p85: ldo4 { + regulator-name = "vreg_pmu_btcmx_0p85"; + }; + + vreg_pmu_rfa_0p8: ldo5 { + regulator-name = "vreg_pmu_rfa_0p8"; + }; + + vreg_pmu_rfa_1p2: ldo6 { + regulator-name = "vreg_pmu_rfa_1p2"; + }; + + vreg_pmu_rfa_1p8: ldo7 { + regulator-name = "vreg_pmu_rfa_1p8"; + }; + + vreg_pmu_pcie_0p9: ldo8 { + regulator-name = "vreg_pmu_pcie_0p9"; + }; + + vreg_pmu_pcie_1p8: ldo9 { + regulator-name = "vreg_pmu_pcie_1p8"; + }; + }; + }; }; &apps_rsc { @@ -1045,6 +1147,16 @@ &pcie4_port0 { wifi@0 { compatible = "pci17cb,1107"; reg = <0x10000 0x0 0x0 0x0 0x0>; + + vddaon-supply = <&vreg_pmu_aon_0p59>; + vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; + vddwlmx-supply = <&vreg_pmu_wlmx_0p85>; + vddrfacmn-supply = <&vreg_pmu_rfa_cmn>; + vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; + vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; + vddrfa1p8-supply = <&vreg_pmu_rfa_1p8>; + vddpcie0p9-supply = <&vreg_pmu_pcie_0p9>; + vddpcie1p8-supply = <&vreg_pmu_pcie_1p8>; }; }; @@ -1403,6 +1515,37 @@ usb2_pwr_3p3_reg_en: usb2-pwr-3p3-reg-en-state { drive-strength = <2>; bias-disable; }; + + wcn_sw_en: wcn-sw-en-state { + pins = "gpio214"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + wcn_wlan_bt_en: wcn-wlan-bt-en-state { + pins = "gpio116", "gpio117"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; +}; + +&uart14 { + status = "okay"; + + bluetooth { + compatible = "qcom,wcn7850-bt"; + max-speed = <3200000>; + + vddaon-supply = <&vreg_pmu_aon_0p59>; + vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; + vddwlmx-supply = <&vreg_pmu_wlmx_0p85>; + vddrfacmn-supply = <&vreg_pmu_rfa_cmn>; + vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; + vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; + vddrfa1p8-supply = <&vreg_pmu_rfa_1p8>; + }; }; &uart21 { From 6a5e9b9738a32229e2673d4eccfcbfe2ef3a1ab4 Mon Sep 17 00:00:00 2001 From: Viken Dadhaniya Date: Mon, 30 Jun 2025 12:13:38 +0530 Subject: [PATCH 00287/11391] arm64: dts: qcom: qcs615: add missing dt property in QUP SEs Add the missing required-opps and operating-points-v2 properties to several I2C, SPI, and UART nodes in the QUP SEs. Fixes: f6746dc9e379 ("arm64: dts: qcom: qcs615: Add QUPv3 configuration") Cc: stable@vger.kernel.org Signed-off-by: Viken Dadhaniya Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250630064338.2487409-1-viken.dadhaniya@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm6150.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index bfbb21035492..e033b53f0f0f 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -631,6 +631,7 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, interconnect-names = "qup-core", "qup-config"; power-domains = <&rpmhpd RPMHPD_CX>; + operating-points-v2 = <&qup_opp_table>; status = "disabled"; }; @@ -654,6 +655,7 @@ &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd RPMHPD_CX>; + required-opps = <&rpmhpd_opp_low_svs>; dmas = <&gpi_dma0 0 1 QCOM_GPI_I2C>, <&gpi_dma0 1 1 QCOM_GPI_I2C>; dma-names = "tx", @@ -681,6 +683,7 @@ &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd RPMHPD_CX>; + required-opps = <&rpmhpd_opp_low_svs>; dmas = <&gpi_dma0 0 2 QCOM_GPI_I2C>, <&gpi_dma0 1 2 QCOM_GPI_I2C>; dma-names = "tx", @@ -703,6 +706,7 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, interconnect-names = "qup-core", "qup-config"; power-domains = <&rpmhpd RPMHPD_CX>; + operating-points-v2 = <&qup_opp_table>; dmas = <&gpi_dma0 0 2 QCOM_GPI_SPI>, <&gpi_dma0 1 2 QCOM_GPI_SPI>; dma-names = "tx", @@ -728,6 +732,7 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, interconnect-names = "qup-core", "qup-config"; power-domains = <&rpmhpd RPMHPD_CX>; + operating-points-v2 = <&qup_opp_table>; status = "disabled"; }; @@ -751,6 +756,7 @@ &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd RPMHPD_CX>; + required-opps = <&rpmhpd_opp_low_svs>; dmas = <&gpi_dma0 0 3 QCOM_GPI_I2C>, <&gpi_dma0 1 3 QCOM_GPI_I2C>; dma-names = "tx", From bbc5a9b5d9d91e9159be95856363979829ec0b80 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Thu, 1 May 2025 08:48:50 +0200 Subject: [PATCH 00288/11391] arm64: dts: qcom: sm6350: Add q6usbdai node Add a node for q6usb which handles USB audio offloading, allowing to play audio via a USB-C headset with lower power consumption and enabling some other features. We also need to set num-hc-interrupters for the dwc3 for the q6usb to be able to use its sideband interrupter. Reviewed-by: Dmitry Baryshkov Signed-off-by: Luca Weiss Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250501-fp4-usb-audio-offload-v2-4-30f4596281cd@fairphone.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm6350.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6350.dtsi b/arch/arm64/boot/dts/qcom/sm6350.dtsi index ff1eb2c53e7b..c7230cdcf714 100644 --- a/arch/arm64/boot/dts/qcom/sm6350.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6350.dtsi @@ -1351,6 +1351,13 @@ q6afecc: clock-controller { compatible = "qcom,q6afe-clocks"; #clock-cells = <2>; }; + + q6usbdai: usbd { + compatible = "qcom,q6usb"; + iommus = <&apps_smmu 0x100f 0x0>; + #sound-dai-cells = <1>; + qcom,usb-audio-intr-idx = /bits/ 16 <2>; + }; }; q6asm: service@7 { @@ -1979,6 +1986,7 @@ usb_1_dwc3: usb@a600000 { reg = <0x0 0x0a600000 0x0 0xcd00>; interrupts = ; iommus = <&apps_smmu 0x540 0x0>; + num-hc-interrupters = /bits/ 16 <3>; snps,dis_u2_susphy_quirk; snps,dis_enblslpm_quirk; snps,has-lpm-erratum; From 5ce2aa520d3f87e54338a3874a76139ad6341bc2 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Thu, 1 May 2025 08:48:51 +0200 Subject: [PATCH 00289/11391] arm64: dts: qcom: sm7225-fairphone-fp4: Enable USB audio offload support Enable USB audio offloading which allows to play audio via a USB-C headset with lower power consumption and enabling some other features. This can be used like the following: $ amixer -c0 cset name='USB_RX Audio Mixer MultiMedia1' On $ aplay --device=plughw:0,0 test.wav Compared to regular playback to the USB sound card no xhci-hcd interrupts appear during playback, instead the ADSP will be handling the USB transfers. Reviewed-by: Dmitry Baryshkov Signed-off-by: Luca Weiss Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250501-fp4-usb-audio-offload-v2-5-30f4596281cd@fairphone.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm6350.dtsi | 3 ++ .../boot/dts/qcom/sm7225-fairphone-fp4.dts | 36 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6350.dtsi b/arch/arm64/boot/dts/qcom/sm6350.dtsi index c7230cdcf714..2d891a5640de 100644 --- a/arch/arm64/boot/dts/qcom/sm6350.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6350.dtsi @@ -2970,6 +2970,9 @@ wifi: wifi@18800000 { }; }; + sound: sound { + }; + thermal-zones { aoss0-thermal { thermal-sensors = <&tsens0 0>; diff --git a/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts b/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts index 52b16a4fdc43..4afbab570ca1 100644 --- a/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts +++ b/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "sm7225.dtsi" #include "pm6150l.dtsi" @@ -938,6 +939,12 @@ channel@644 { }; }; +&q6asmdai { + dai@0 { + reg = ; + }; +}; + &qup_uart1_cts { /* * Configure a bias-bus-hold on CTS to lower power @@ -1006,6 +1013,35 @@ &sdhc_2 { status = "okay"; }; +&sound { + compatible = "fairphone,fp4-sndcard"; + model = "Fairphone 4"; + + mm1-dai-link { + link-name = "MultiMedia1"; + + cpu { + sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA1>; + }; + }; + + usb-dai-link { + link-name = "USB Playback"; + + codec { + sound-dai = <&q6usbdai USB_RX>; + }; + + cpu { + sound-dai = <&q6afedai USB_RX>; + }; + + platform { + sound-dai = <&q6routing>; + }; + }; +}; + &tlmm { gpio-reserved-ranges = <13 4>, <56 2>; From 682c9d0e788b2e35ece1cbae5448bec1dadaf9af Mon Sep 17 00:00:00 2001 From: Luo Jie Date: Tue, 10 Jun 2025 18:35:20 +0800 Subject: [PATCH 00290/11391] arm64: dts: qcom: ipq5424: Add CMN PLL node Add CMN PLL node for enabling output clocks to the networking hardware blocks on IPQ5424 devices. The reference clock of CMN PLL is routed from XO to the CMN PLL through the internal WiFi block. .XO (48 MHZ or 96 MHZ or 192 MHZ)-->WiFi (multiplier/divider)--> 48 MHZ to CMN PLL. Reviewed-by: Konrad Dybcio Signed-off-by: Luo Jie Link: https://lore.kernel.org/r/20250610-qcom_ipq5424_cmnpll-v3-3-ceada8165645@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/ipq5424-rdp466.dts | 17 +++++++++++++- arch/arm64/boot/dts/qcom/ipq5424.dtsi | 26 ++++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/ipq5424-rdp466.dts b/arch/arm64/boot/dts/qcom/ipq5424-rdp466.dts index 1f89530cb035..5ca578904f85 100644 --- a/arch/arm64/boot/dts/qcom/ipq5424-rdp466.dts +++ b/arch/arm64/boot/dts/qcom/ipq5424-rdp466.dts @@ -2,7 +2,7 @@ /* * IPQ5424 RDP466 board device tree source * - * Copyright (c) 2024 The Linux Foundation. All rights reserved. + * Copyright (c) 2024-2025 The Linux Foundation. All rights reserved. */ /dts-v1/; @@ -253,6 +253,21 @@ &usb3 { status = "okay"; }; +/* + * The bootstrap pins for the board select the XO clock frequency that + * supports 48 MHZ, 96 MHZ or 192 MHZ. This setting automatically + * enables the right dividers, to ensure the reference clock output + * from WiFi to the CMN PLL is 48 MHZ. + */ +&ref_48mhz_clk { + clock-div = <1>; + clock-mult = <1>; +}; + &xo_board { clock-frequency = <24000000>; }; + +&xo_clk { + clock-frequency = <48000000>; +}; diff --git a/arch/arm64/boot/dts/qcom/ipq5424.dtsi b/arch/arm64/boot/dts/qcom/ipq5424.dtsi index 66bd2261eb25..13c641fced8f 100644 --- a/arch/arm64/boot/dts/qcom/ipq5424.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq5424.dtsi @@ -3,10 +3,11 @@ * IPQ5424 device tree source * * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. */ #include +#include #include #include #include @@ -18,6 +19,12 @@ / { interrupt-parent = <&intc>; clocks { + ref_48mhz_clk: ref-48mhz-clk { + compatible = "fixed-factor-clock"; + clocks = <&xo_clk>; + #clock-cells = <0>; + }; + sleep_clk: sleep-clk { compatible = "fixed-clock"; #clock-cells = <0>; @@ -27,6 +34,11 @@ xo_board: xo-board-clk { compatible = "fixed-clock"; #clock-cells = <0>; }; + + xo_clk: xo-clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + }; }; cpus: cpus { @@ -210,6 +222,18 @@ pcie1_phy: phy@8c000 { status = "disabled"; }; + cmn_pll: clock-controller@9b000 { + compatible = "qcom,ipq5424-cmn-pll"; + reg = <0 0x0009b000 0 0x800>; + clocks = <&ref_48mhz_clk>, + <&gcc GCC_CMN_12GPLL_AHB_CLK>, + <&gcc GCC_CMN_12GPLL_SYS_CLK>; + clock-names = "ref", "ahb", "sys"; + #clock-cells = <1>; + assigned-clocks = <&cmn_pll IPQ5424_CMN_PLL_CLK>; + assigned-clock-rates-u64 = /bits/ 64 <12000000000>; + }; + efuse@a4000 { compatible = "qcom,ipq5424-qfprom", "qcom,qfprom"; reg = <0 0x000a4000 0 0x741>; From e5612530e325897da9a70dc78828d6ff2138ae32 Mon Sep 17 00:00:00 2001 From: Luo Jie Date: Tue, 10 Jun 2025 18:35:21 +0800 Subject: [PATCH 00291/11391] arm64: dts: qcom: Update IPQ5424 xo_board to use fixed factor clock xo_board is fixed to 24 MHZ, which is routed from WiFi output clock 48 MHZ (also being the reference clock of CMN PLL) divided 2 by analog block routing channel. Reviewed-by: Konrad Dybcio Signed-off-by: Luo Jie Link: https://lore.kernel.org/r/20250610-qcom_ipq5424_cmnpll-v3-4-ceada8165645@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/ipq5424-rdp466.dts | 7 ++++++- arch/arm64/boot/dts/qcom/ipq5424.dtsi | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/ipq5424-rdp466.dts b/arch/arm64/boot/dts/qcom/ipq5424-rdp466.dts index 5ca578904f85..117f1785e8b8 100644 --- a/arch/arm64/boot/dts/qcom/ipq5424-rdp466.dts +++ b/arch/arm64/boot/dts/qcom/ipq5424-rdp466.dts @@ -264,8 +264,13 @@ &ref_48mhz_clk { clock-mult = <1>; }; +/* + * The frequency of xo_board is fixed to 24 MHZ, which is routed + * from WiFi output clock 48 MHZ divided by 2. + */ &xo_board { - clock-frequency = <24000000>; + clock-div = <2>; + clock-mult = <1>; }; &xo_clk { diff --git a/arch/arm64/boot/dts/qcom/ipq5424.dtsi b/arch/arm64/boot/dts/qcom/ipq5424.dtsi index 13c641fced8f..2eea8a078595 100644 --- a/arch/arm64/boot/dts/qcom/ipq5424.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq5424.dtsi @@ -31,7 +31,8 @@ sleep_clk: sleep-clk { }; xo_board: xo-board-clk { - compatible = "fixed-clock"; + compatible = "fixed-factor-clock"; + clocks = <&ref_48mhz_clk>; #clock-cells = <0>; }; From 1e2261a669a9596ba435c6fe524e026bac0f0e2f Mon Sep 17 00:00:00 2001 From: George Moussalem Date: Mon, 30 Jun 2025 16:35:01 +0400 Subject: [PATCH 00292/11391] arm64: dts: qcom: ipq5018: Add MDIO buses IPQ5018 contains two mdio buses of which one bus is used to control the SoC's internal GE PHY, while the other bus is connected to external PHYs or switches. There's already support for IPQ5018 in the mdio-ipq4019 driver, so let's simply add the mdio nodes for them. Reviewed-by: Konrad Dybcio Signed-off-by: George Moussalem Link: https://lore.kernel.org/r/20250630-ipq5018-ge-phy-v6-2-01be06378c15@outlook.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/ipq5018.dtsi b/arch/arm64/boot/dts/qcom/ipq5018.dtsi index baf583c75e76..6e93495ce14c 100644 --- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi @@ -185,6 +185,30 @@ pcie0_phy: phy@86000 { status = "disabled"; }; + mdio0: mdio@88000 { + compatible = "qcom,ipq5018-mdio"; + reg = <0x00088000 0x64>; + #address-cells = <1>; + #size-cells = <0>; + + clocks = <&gcc GCC_MDIO0_AHB_CLK>; + clock-names = "gcc_mdio_ahb_clk"; + + status = "disabled"; + }; + + mdio1: mdio@90000 { + compatible = "qcom,ipq5018-mdio"; + reg = <0x00090000 0x64>; + #address-cells = <1>; + #size-cells = <0>; + + clocks = <&gcc GCC_MDIO1_AHB_CLK>; + clock-names = "gcc_mdio_ahb_clk"; + + status = "disabled"; + }; + qfprom: qfprom@a0000 { compatible = "qcom,ipq5018-qfprom", "qcom,qfprom"; reg = <0x000a0000 0x1000>; From f5f2b835e316df29b89e28ed7e467df473932e8d Mon Sep 17 00:00:00 2001 From: George Moussalem Date: Mon, 30 Jun 2025 16:35:02 +0400 Subject: [PATCH 00293/11391] arm64: dts: qcom: ipq5018: Add GE PHY to internal mdio bus The IPQ5018 SoC contains an internal GE PHY, always at phy address 7. As such, let's add the GE PHY node to the SoC dtsi. The LDO controller found in the SoC must be enabled to provide constant low voltages to the PHY. The mdio-ipq4019 driver already has support for this, so adding the appropriate TCSR register offset. In addition, the GE PHY outputs both the RX and TX clocks to the GCC which gate controls them and routes them back to the PHY itself. So let's create two DT fixed clocks and register them in the GCC node. Reviewed-by: Konrad Dybcio Signed-off-by: George Moussalem Link: https://lore.kernel.org/r/20250630-ipq5018-ge-phy-v6-3-01be06378c15@outlook.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/ipq5018.dtsi b/arch/arm64/boot/dts/qcom/ipq5018.dtsi index 6e93495ce14c..9ce73682e4ae 100644 --- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi @@ -17,6 +17,18 @@ / { #size-cells = <2>; clocks { + gephy_rx_clk: gephy-rx-clk { + compatible = "fixed-clock"; + clock-frequency = <125000000>; + #clock-cells = <0>; + }; + + gephy_tx_clk: gephy-tx-clk { + compatible = "fixed-clock"; + clock-frequency = <125000000>; + #clock-cells = <0>; + }; + sleep_clk: sleep-clk { compatible = "fixed-clock"; #clock-cells = <0>; @@ -187,7 +199,8 @@ pcie0_phy: phy@86000 { mdio0: mdio@88000 { compatible = "qcom,ipq5018-mdio"; - reg = <0x00088000 0x64>; + reg = <0x00088000 0x64>, + <0x019475c4 0x4>; #address-cells = <1>; #size-cells = <0>; @@ -195,6 +208,13 @@ mdio0: mdio@88000 { clock-names = "gcc_mdio_ahb_clk"; status = "disabled"; + + ge_phy: ethernet-phy@7 { + compatible = "ethernet-phy-id004d.d0c0"; + reg = <7>; + + resets = <&gcc GCC_GEPHY_MISC_ARES>; + }; }; mdio1: mdio@90000 { @@ -346,8 +366,8 @@ gcc: clock-controller@1800000 { <&pcie0_phy>, <&pcie1_phy>, <0>, - <0>, - <0>, + <&gephy_rx_clk>, + <&gephy_tx_clk>, <0>, <0>; #clock-cells = <1>; From 718cc7542a000e2911c8d18878ba2eac5f29e744 Mon Sep 17 00:00:00 2001 From: Krishna chaitanya chundru Date: Fri, 25 Jul 2025 19:23:45 +0800 Subject: [PATCH 00294/11391] arm64: dts: qcom: qcs615: enable pcie Add configurations in devicetree for PCIe0, including registers, clocks, interrupts and phy setting sequence. Add PCIe lane equalization preset properties for 8 GT/s. Signed-off-by: Krishna chaitanya chundru Reviewed-by: Konrad Dybcio Reviewed-by: Manivannan Sadhasivam Signed-off-by: Ziyue Zhang Link: https://lore.kernel.org/r/20250725112346.614316-2-ziyue.zhang@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm6150.dtsi | 138 +++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index e033b53f0f0f..6fa4614c13ae 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -1072,6 +1072,144 @@ mmss_noc: interconnect@1740000 { qcom,bcm-voters = <&apps_bcm_voter>; }; + pcie: pcie@1c08000 { + device_type = "pci"; + compatible = "qcom,pcie-qcs615", "qcom,pcie-sm8150"; + reg = <0x0 0x01c08000 0x0 0x3000>, + <0x0 0x40000000 0x0 0xf1d>, + <0x0 0x40000f20 0x0 0xa8>, + <0x0 0x40001000 0x0 0x1000>, + <0x0 0x40100000 0x0 0x100000>, + <0x0 0x01c0b000 0x0 0x1000>; + reg-names = "parf", + "dbi", + "elbi", + "atu", + "config", + "mhi"; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x01000000 0x0 0x00000000 0x0 0x40200000 0x0 0x100000>, + <0x02000000 0x0 0x40300000 0x0 0x40300000 0x0 0x1fd00000>; + bus-range = <0x00 0xff>; + + dma-coherent; + + linux,pci-domain = <0>; + num-lanes = <1>; + + interrupts = , + , + , + , + , + , + , + , + ; + interrupt-names = "msi0", + "msi1", + "msi2", + "msi3", + "msi4", + "msi5", + "msi6", + "msi7", + "global"; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0x7>; + interrupt-map = <0 0 0 1 &intc GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 2 &intc GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 3 &intc GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 4 &intc GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>; + + clocks = <&gcc GCC_PCIE_0_PIPE_CLK>, + <&gcc GCC_PCIE_0_AUX_CLK>, + <&gcc GCC_PCIE_0_CFG_AHB_CLK>, + <&gcc GCC_PCIE_0_MSTR_AXI_CLK>, + <&gcc GCC_PCIE_0_SLV_AXI_CLK>, + <&gcc GCC_PCIE_0_SLV_Q2A_AXI_CLK>; + clock-names = "pipe", + "aux", + "cfg", + "bus_master", + "bus_slave", + "slave_q2a"; + assigned-clocks = <&gcc GCC_PCIE_0_AUX_CLK>; + assigned-clock-rates = <19200000>; + + interconnects = <&aggre1_noc MASTER_PCIE QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &config_noc SLAVE_PCIE_0 QCOM_ICC_TAG_ACTIVE_ONLY>; + interconnect-names = "pcie-mem", "cpu-pcie"; + + iommu-map = <0x0 &apps_smmu 0x400 0x1>, + <0x100 &apps_smmu 0x401 0x1>; + + resets = <&gcc GCC_PCIE_0_BCR>; + reset-names = "pci"; + + power-domains = <&gcc PCIE_0_GDSC>; + + phys = <&pcie_phy>; + phy-names = "pciephy"; + + max-link-speed = <2>; + + operating-points-v2 = <&pcie_opp_table>; + + status = "disabled"; + + pcie_opp_table: opp-table { + compatible = "operating-points-v2"; + + /* GEN 1 x1 */ + opp-2500000 { + opp-hz = /bits/ 64 <2500000>; + required-opps = <&rpmhpd_opp_low_svs>; + opp-peak-kBps = <250000 1>; + }; + + /* GEN 2 x1 */ + opp-5000000 { + opp-hz = /bits/ 64 <5000000>; + required-opps = <&rpmhpd_opp_low_svs>; + opp-peak-kBps = <500000 1>; + }; + }; + }; + + pcie_phy: phy@1c0e000 { + compatible = "qcom,qcs615-qmp-gen3x1-pcie-phy"; + reg = <0x0 0x01c0e000 0x0 0x1000>; + + clocks = <&gcc GCC_PCIE_PHY_AUX_CLK>, + <&gcc GCC_PCIE_0_CFG_AHB_CLK>, + <&gcc GCC_PCIE_0_CLKREF_CLK>, + <&gcc GCC_PCIE0_PHY_REFGEN_CLK>, + <&gcc GCC_PCIE_0_PIPE_CLK>; + clock-names = "aux", + "cfg_ahb", + "ref", + "refgen", + "pipe"; + + resets = <&gcc GCC_PCIE_0_PHY_BCR>; + reset-names = "phy"; + + assigned-clocks = <&gcc GCC_PCIE0_PHY_REFGEN_CLK>; + assigned-clock-rates = <100000000>; + + #clock-cells = <0>; + clock-output-names = "pcie_0_pipe_clk"; + + #phy-cells = <0>; + + status = "disabled"; + }; + ufs_mem_hc: ufshc@1d84000 { compatible = "qcom,qcs615-ufshc", "qcom,ufshc", "jedec,ufs-2.0"; reg = <0x0 0x01d84000 0x0 0x3000>, From 414be2b5a79de8694db1e26a3ea63a2aee5957ad Mon Sep 17 00:00:00 2001 From: Krishna chaitanya chundru Date: Fri, 25 Jul 2025 19:23:46 +0800 Subject: [PATCH 00295/11391] arm64: dts: qcom: qcs615-ride: Enable PCIe interface Add platform configurations in devicetree for PCIe, board related gpios, PMIC regulators, etc. Reviewed-by: Konrad Dybcio Signed-off-by: Krishna chaitanya chundru Signed-off-by: Ziyue Zhang Link: https://lore.kernel.org/r/20250725112346.614316-3-ziyue.zhang@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/qcs615-ride.dts | 42 ++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs615-ride.dts b/arch/arm64/boot/dts/qcom/qcs615-ride.dts index fdad6388f6f7..2dd26267ba2e 100644 --- a/arch/arm64/boot/dts/qcom/qcs615-ride.dts +++ b/arch/arm64/boot/dts/qcom/qcs615-ride.dts @@ -217,6 +217,23 @@ &gcc { <&sleep_clk>; }; +&pcie { + perst-gpios = <&tlmm 101 GPIO_ACTIVE_LOW>; + wake-gpios = <&tlmm 100 GPIO_ACTIVE_HIGH>; + + pinctrl-0 = <&pcie_default_state>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&pcie_phy { + vdda-phy-supply = <&vreg_l5a>; + vdda-pll-supply = <&vreg_l12a>; + + status = "okay"; +}; + &pm8150_gpios { usb2_en: usb2-en-state { pins = "gpio10"; @@ -256,6 +273,31 @@ &rpmhcc { clocks = <&xo_board_clk>; }; +&tlmm { + pcie_default_state: pcie-default-state { + clkreq-pins { + pins = "gpio90"; + function = "pcie_clk_req"; + drive-strength = <2>; + bias-pull-up; + }; + + perst-pins { + pins = "gpio101"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + wake-pins { + pins = "gpio100"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; +}; + &sdhc_1 { pinctrl-0 = <&sdc1_state_on>; pinctrl-1 = <&sdc1_state_off>; From e13555a3e17b572609901c0f1992f03243a45121 Mon Sep 17 00:00:00 2001 From: "Yu Zhang(Yuriy)" Date: Sun, 27 Jul 2025 18:22:36 +0800 Subject: [PATCH 00296/11391] arm64: dts: qcom: qcs615: add a PCIe port for WLAN Add an original PCIe port for WLAN. This port will be referenced and supplemented by specific WLAN devices. Signed-off-by: Yu Zhang (Yuriy) Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250727-615-v7-1-2adb6233bbb9@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm6150.dtsi | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index 6fa4614c13ae..591fcb740259 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -1179,6 +1179,15 @@ opp-5000000 { opp-peak-kBps = <500000 1>; }; }; + + pcie_port0: pcie@0 { + device_type = "pci"; + reg = <0x0 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + bus-range = <0x01 0xff>; + }; }; pcie_phy: phy@1c0e000 { From b5634bf97913756c208bb29f6061ee39154458cf Mon Sep 17 00:00:00 2001 From: "Yu Zhang(Yuriy)" Date: Sun, 27 Jul 2025 18:22:37 +0800 Subject: [PATCH 00297/11391] arm64: dts: qcom: qcs615-ride: Enable WiFi/BT nodes Enable WiFi/BT on qcs615-ride by adding a node for the PMU module of the WCN6855 and assigning its LDO power outputs to the existing WiFi/BT module. Signed-off-by: Yu Zhang (Yuriy) Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250727-615-v7-2-2adb6233bbb9@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/qcs615-ride.dts | 135 +++++++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs615-ride.dts b/arch/arm64/boot/dts/qcom/qcs615-ride.dts index 2dd26267ba2e..36978fdfe3dd 100644 --- a/arch/arm64/boot/dts/qcom/qcs615-ride.dts +++ b/arch/arm64/boot/dts/qcom/qcs615-ride.dts @@ -18,6 +18,7 @@ aliases { mmc0 = &sdhc_1; mmc1 = &sdhc_2; serial0 = &uart0; + serial1 = &uart7; }; chosen { @@ -38,6 +39,22 @@ xo_board_clk: xo-board-clk { }; }; + vreg_conn_1p8: regulator-conn-1p8 { + compatible = "regulator-fixed"; + regulator-name = "vreg_conn_1p8"; + startup-delay-us = <4000>; + enable-active-high; + gpio = <&pm8150_gpios 1 GPIO_ACTIVE_HIGH>; + }; + + vreg_conn_pa: regulator-conn-pa { + compatible = "regulator-fixed"; + regulator-name = "vreg_conn_pa"; + startup-delay-us = <4000>; + enable-active-high; + gpio = <&pm8150_gpios 6 GPIO_ACTIVE_HIGH>; + }; + regulator-usb2-vbus { compatible = "regulator-fixed"; regulator-name = "USB2_VBUS"; @@ -47,6 +64,69 @@ regulator-usb2-vbus { enable-active-high; regulator-always-on; }; + + wcn6855-pmu { + compatible = "qcom,wcn6855-pmu"; + + pinctrl-0 = <&bt_en_state>, <&wlan_en_state>; + pinctrl-names = "default"; + + bt-enable-gpios = <&tlmm 85 GPIO_ACTIVE_HIGH>; + wlan-enable-gpios = <&tlmm 98 GPIO_ACTIVE_HIGH>; + + vddio-supply = <&vreg_conn_pa>; + vddaon-supply = <&vreg_s5a>; + vddpmu-supply = <&vreg_conn_1p8>; + vddpmumx-supply = <&vreg_conn_1p8>; + vddpmucx-supply = <&vreg_conn_pa>; + vddrfa0p95-supply = <&vreg_s5a>; + vddrfa1p3-supply = <&vreg_s6a>; + vddrfa1p9-supply = <&vreg_l15a>; + vddpcie1p3-supply = <&vreg_s6a>; + vddpcie1p9-supply = <&vreg_l15a>; + + regulators { + vreg_pmu_rfa_cmn: ldo0 { + regulator-name = "vreg_pmu_rfa_cmn"; + }; + + vreg_pmu_aon_0p59: ldo1 { + regulator-name = "vreg_pmu_aon_0p59"; + }; + + vreg_pmu_wlcx_0p8: ldo2 { + regulator-name = "vreg_pmu_wlcx_0p8"; + }; + + vreg_pmu_wlmx_0p85: ldo3 { + regulator-name = "vreg_pmu_wlmx_0p85"; + }; + + vreg_pmu_btcmx_0p85: ldo4 { + regulator-name = "vreg_pmu_btcmx_0p85"; + }; + + vreg_pmu_rfa_0p8: ldo5 { + regulator-name = "vreg_pmu_rfa_0p8"; + }; + + vreg_pmu_rfa_1p2: ldo6 { + regulator-name = "vreg_pmu_rfa_1p2"; + }; + + vreg_pmu_rfa_1p7: ldo7 { + regulator-name = "vreg_pmu_rfa_1p7"; + }; + + vreg_pmu_pcie_0p9: ldo8 { + regulator-name = "vreg_pmu_pcie_0p9"; + }; + + vreg_pmu_pcie_1p8: ldo9 { + regulator-name = "vreg_pmu_pcie_1p8"; + }; + }; + }; }; &apps_rsc { @@ -234,6 +314,25 @@ &pcie_phy { status = "okay"; }; +&pcie_port0 { + wifi@0 { + compatible = "pci17cb,1103"; + reg = <0x10000 0x0 0x0 0x0 0x0>; + + qcom,calibration-variant = "QC_QCS615_Ride"; + + vddrfacmn-supply = <&vreg_pmu_rfa_cmn>; + vddaon-supply = <&vreg_pmu_aon_0p59>; + vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; + vddwlmx-supply = <&vreg_pmu_wlmx_0p85>; + vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; + vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; + vddrfa1p8-supply = <&vreg_pmu_rfa_1p7>; + vddpcie0p9-supply = <&vreg_pmu_pcie_0p9>; + vddpcie1p8-supply = <&vreg_pmu_pcie_1p8>; + }; +}; + &pm8150_gpios { usb2_en: usb2-en-state { pins = "gpio10"; @@ -257,6 +356,10 @@ &qupv3_id_0 { status = "okay"; }; +&qupv3_id_1 { + status = "okay"; +}; + &remoteproc_adsp { firmware-name = "qcom/qcs615/adsp.mbn"; @@ -274,6 +377,13 @@ &rpmhcc { }; &tlmm { + bt_en_state: bt-en-state { + pins = "gpio85"; + function = "gpio"; + bias-pull-down; + output-low; + }; + pcie_default_state: pcie-default-state { clkreq-pins { pins = "gpio90"; @@ -296,6 +406,13 @@ wake-pins { bias-pull-up; }; }; + + wlan_en_state: wlan-en-state { + pins = "gpio98"; + function = "gpio"; + bias-pull-down; + output-low; + }; }; &sdhc_1 { @@ -336,6 +453,24 @@ &uart0 { status = "okay"; }; +&uart7 { + status = "okay"; + + bluetooth { + compatible = "qcom,wcn6855-bt"; + firmware-name = "QCA6698/hpnv21", "QCA6698/hpbtfw21.tlv"; + + vddrfacmn-supply = <&vreg_pmu_rfa_cmn>; + vddaon-supply = <&vreg_pmu_aon_0p59>; + vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; + vddwlmx-supply = <&vreg_pmu_wlmx_0p85>; + vddbtcmx-supply = <&vreg_pmu_btcmx_0p85>; + vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; + vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; + vddrfa1p8-supply = <&vreg_pmu_rfa_1p7>; + }; +}; + &usb_1_hsphy { vdd-supply = <&vreg_l5a>; vdda-pll-supply = <&vreg_l12a>; From 35e0b432d5ca73b7498398d7eb369c5665cc3ab1 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 25 Jun 2025 11:11:25 +0200 Subject: [PATCH 00298/11391] arm64: dts: qcom: pmk8550: Correct gpio node name The reg for the GPIOs is 0xb800 and not 0x8800, so fix this copy-paste mistake. Fixes: e9c0a4e48489 ("arm64: dts: qcom: Add PMK8550 pmic dtsi") Signed-off-by: Luca Weiss Reviewed-by: Konrad Dybcio Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250625-pmk8550-gpio-name-v1-1-58402849f365@fairphone.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/pmk8550.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/pmk8550.dtsi b/arch/arm64/boot/dts/qcom/pmk8550.dtsi index c7ac9b2eaacf..583f61fc16ad 100644 --- a/arch/arm64/boot/dts/qcom/pmk8550.dtsi +++ b/arch/arm64/boot/dts/qcom/pmk8550.dtsi @@ -64,7 +64,7 @@ reboot_reason: reboot-reason@48 { }; }; - pmk8550_gpios: gpio@8800 { + pmk8550_gpios: gpio@b800 { compatible = "qcom,pmk8550-gpio", "qcom,spmi-gpio"; reg = <0xb800>; gpio-controller; From b2659ddbc2999e8b56edbcd12251b3e469bd0bca Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 11 Aug 2025 17:06:48 +0200 Subject: [PATCH 00299/11391] arm64: dts: qcom: qrb2210-rb1: fix GPIO lookup flags for i2c SDA and SCL The I2C GPIO bus driver enforces the SDA and SCL pins as open-drain outputs but the lookup flags in the DTS don't reflect that triggering warnings from GPIO core. Add the appropriate flags. Tested-by: Alexey Klimov Reported-by: Alexey Klimov Reviewed-by: Konrad Dybcio Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20250811-qcom-gpio-lookup-open-drain-v1-1-b5496f80e047@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/qrb2210-rb1.dts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts b/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts index b2e0fc5501c1..277b33100ac0 100644 --- a/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts +++ b/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts @@ -5,6 +5,7 @@ /dts-v1/; +#include #include #include "qcm2290.dtsi" #include "pm4125.dtsi" @@ -63,8 +64,8 @@ hdmi_con: endpoint { i2c2_gpio: i2c { compatible = "i2c-gpio"; - sda-gpios = <&tlmm 6 GPIO_ACTIVE_HIGH>; - scl-gpios = <&tlmm 7 GPIO_ACTIVE_HIGH>; + sda-gpios = <&tlmm 6 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + scl-gpios = <&tlmm 7 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; #address-cells = <1>; #size-cells = <0>; From f07f492773b70efe01f9966703fef658b428f17b Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 11 Aug 2025 17:06:49 +0200 Subject: [PATCH 00300/11391] arm64: dts: qcom: qrb4210-rb2: fix GPIO lookup flags for i2c SDA and SCL The I2C GPIO bus driver enforces the SDA and SCL pins as open-drain outputs but the lookup flags in the DTS don't reflect that triggering warnings from GPIO core. Add the appropriate flags. Reported-by: Alexey Klimov Reviewed-by: Konrad Dybcio Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20250811-qcom-gpio-lookup-open-drain-v1-2-b5496f80e047@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/qrb4210-rb2.dts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts b/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts index a37860175d27..bdf2d66e40c6 100644 --- a/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts +++ b/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts @@ -5,6 +5,7 @@ /dts-v1/; +#include #include #include #include @@ -65,8 +66,8 @@ hdmi_con: endpoint { i2c2_gpio: i2c { compatible = "i2c-gpio"; - sda-gpios = <&tlmm 6 GPIO_ACTIVE_HIGH>; - scl-gpios = <&tlmm 7 GPIO_ACTIVE_HIGH>; + sda-gpios = <&tlmm 6 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + scl-gpios = <&tlmm 7 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; #address-cells = <1>; #size-cells = <0>; From 25197809e78c5ff521353acce00406cc2b4bbc16 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 11 Aug 2025 17:06:50 +0200 Subject: [PATCH 00301/11391] arm64: dts: qcom: sdm845-samsung-starqltechn: fix GPIO lookup flags for i2c SDA and SCL The I2C GPIO bus driver enforces the SDA and SCL pins as open-drain outputs but the lookup flags in the DTS don't reflect that triggering warnings from GPIO core. Add the appropriate flags. Reviewed-by: Konrad Dybcio Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20250811-qcom-gpio-lookup-open-drain-v1-3-b5496f80e047@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sdm845-samsung-starqltechn.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-samsung-starqltechn.dts b/arch/arm64/boot/dts/qcom/sdm845-samsung-starqltechn.dts index d686531bf4ea..9076d8eb4d50 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-samsung-starqltechn.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-samsung-starqltechn.dts @@ -145,8 +145,8 @@ rmtfs_mem: rmtfs-mem@fde00000 { i2c21 { compatible = "i2c-gpio"; - sda-gpios = <&tlmm 127 GPIO_ACTIVE_HIGH>; - scl-gpios = <&tlmm 128 GPIO_ACTIVE_HIGH>; + sda-gpios = <&tlmm 127 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + scl-gpios = <&tlmm 128 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; i2c-gpio,delay-us = <2>; pinctrl-0 = <&i2c21_sda_state &i2c21_scl_state>; pinctrl-names = "default"; From 8d2a8e8dc448f218b36b3b9f3790c9c0dfaa2b74 Mon Sep 17 00:00:00 2001 From: George Moussalem Date: Thu, 1 May 2025 13:20:52 +0400 Subject: [PATCH 00302/11391] arm64: dts: qcom: ipq5018: Add SPI nand support Add QPIC SPI NAND support for IPQ5018 SoC. Signed-off-by: George Moussalem Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250501-ipq5018-spi-qpic-snand-v1-2-31e01fbb606f@outlook.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 38 +++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/ipq5018.dtsi b/arch/arm64/boot/dts/qcom/ipq5018.dtsi index 9ce73682e4ae..e223b087b28b 100644 --- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi @@ -436,6 +436,44 @@ blsp1_spi1: spi@78b5000 { status = "disabled"; }; + qpic_bam: dma-controller@7984000 { + compatible = "qcom,bam-v1.7.4", "qcom,bam-v1.7.0"; + reg = <0x07984000 0x1c000>; + + interrupts = ; + + clocks = <&gcc GCC_QPIC_AHB_CLK>; + clock-names = "bam_clk"; + + #dma-cells = <1>; + qcom,ee = <0>; + + status = "disabled"; + }; + + qpic_nand: spi@79b0000 { + compatible = "qcom,ipq5018-snand", "qcom,ipq9574-snand"; + reg = <0x079b0000 0x10000>; + #address-cells = <1>; + #size-cells = <0>; + + clocks = <&gcc GCC_QPIC_CLK>, + <&gcc GCC_QPIC_AHB_CLK>, + <&gcc GCC_QPIC_IO_MACRO_CLK>; + clock-names = "core", + "aon", + "iom"; + + dmas = <&qpic_bam 0>, + <&qpic_bam 1>, + <&qpic_bam 2>; + dma-names = "tx", + "rx", + "cmd"; + + status = "disabled"; + }; + usb: usb@8af8800 { compatible = "qcom,ipq5018-dwc3", "qcom,dwc3"; reg = <0x08af8800 0x400>; From 1a67f85c690658a35cac41c070df33e3e5a72868 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Sun, 25 May 2025 06:53:33 -0300 Subject: [PATCH 00303/11391] dt-bindings: arm: qcom: Add Dell Latitude 7455 Document the X1E80100-based Dell Latitude 7455 laptop. Signed-off-by: Val Packett Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250525095341.12462-3-val@packett.cool Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/arm/qcom.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml index 1b705079c1ae..c8a71a33d358 100644 --- a/Documentation/devicetree/bindings/arm/qcom.yaml +++ b/Documentation/devicetree/bindings/arm/qcom.yaml @@ -1149,6 +1149,7 @@ properties: - enum: - asus,vivobook-s15 - asus,zenbook-a14-ux3407ra + - dell,latitude-7455 - dell,xps13-9345 - hp,elitebook-ultra-g1q - hp,omnibook-x14 From 8def31f8c1e1f3d28e4ee3dcf6818a74c9a9a2f7 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 27 Jul 2025 21:36:53 +0200 Subject: [PATCH 00304/11391] arm64: dts: qcom: sm8650: Sort nodes by unit address Qualcomm DTS uses sorting of MMIO nodes by the unit address, so move few nodes in SM8650 DTSI to fix that. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Neil Armstrong Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250727193652.4029-2-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8650.dtsi | 402 +++++++++++++-------------- 1 file changed, 201 insertions(+), 201 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi index bcafd9cf3eae..34ec162db53d 100644 --- a/arch/arm64/boot/dts/qcom/sm8650.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi @@ -3490,6 +3490,11 @@ &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ACTIVE_ONLY>, }; }; + rng: rng@10c3000 { + compatible = "qcom,sm8650-trng", "qcom,trng"; + reg = <0 0x010c3000 0 0x1000>; + }; + cnoc_main: interconnect@1500000 { compatible = "qcom,sm8650-cnoc-main"; reg = <0 0x01500000 0 0x14080>; @@ -3561,11 +3566,6 @@ mmss_noc: interconnect@1780000 { #interconnect-cells = <2>; }; - rng: rng@10c3000 { - compatible = "qcom,sm8650-trng", "qcom,trng"; - reg = <0 0x010c3000 0 0x1000>; - }; - pcie0: pcie@1c00000 { device_type = "pci"; compatible = "qcom,pcie-sm8650", "qcom,pcie-sm8550"; @@ -3926,38 +3926,6 @@ pcie1_phy: phy@1c0e000 { status = "disabled"; }; - cryptobam: dma-controller@1dc4000 { - compatible = "qcom,bam-v1.7.0"; - reg = <0 0x01dc4000 0 0x28000>; - - interrupts = ; - - #dma-cells = <1>; - - iommus = <&apps_smmu 0x480 0>, - <&apps_smmu 0x481 0>; - - qcom,ee = <0>; - qcom,num-ees = <4>; - num-channels = <20>; - qcom,controlled-remotely; - }; - - crypto: crypto@1dfa000 { - compatible = "qcom,sm8650-qce", "qcom,sm8150-qce", "qcom,qce"; - reg = <0 0x01dfa000 0 0x6000>; - - interconnects = <&aggre2_noc MASTER_CRYPTO QCOM_ICC_TAG_ALWAYS - &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; - interconnect-names = "memory"; - - dmas = <&cryptobam 4>, <&cryptobam 5>; - dma-names = "rx", "tx"; - - iommus = <&apps_smmu 0x480 0>, - <&apps_smmu 0x481 0>; - }; - ufs_mem_phy: phy@1d80000 { compatible = "qcom,sm8650-qmp-ufs-phy"; reg = <0 0x01d80000 0 0x2000>; @@ -4079,6 +4047,38 @@ ice: crypto@1d88000 { clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>; }; + cryptobam: dma-controller@1dc4000 { + compatible = "qcom,bam-v1.7.0"; + reg = <0 0x01dc4000 0 0x28000>; + + interrupts = ; + + #dma-cells = <1>; + + iommus = <&apps_smmu 0x480 0>, + <&apps_smmu 0x481 0>; + + qcom,ee = <0>; + qcom,num-ees = <4>; + num-channels = <20>; + qcom,controlled-remotely; + }; + + crypto: crypto@1dfa000 { + compatible = "qcom,sm8650-qce", "qcom,sm8150-qce", "qcom,qce"; + reg = <0 0x01dfa000 0 0x6000>; + + interconnects = <&aggre2_noc MASTER_CRYPTO QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "memory"; + + dmas = <&cryptobam 4>, <&cryptobam 5>; + dma-names = "rx", "tx"; + + iommus = <&apps_smmu 0x480 0>, + <&apps_smmu 0x481 0>; + }; + tcsr_mutex: hwlock@1f40000 { compatible = "qcom,tcsr-mutex"; reg = <0 0x01f40000 0 0x20000>; @@ -4962,6 +4962,170 @@ opp-202000000 { }; }; + usb_1_hsphy: phy@88e3000 { + compatible = "qcom,sm8650-snps-eusb2-phy", + "qcom,sm8550-snps-eusb2-phy"; + reg = <0 0x088e3000 0 0x154>; + + clocks = <&tcsr TCSR_USB2_CLKREF_EN>; + clock-names = "ref"; + + resets = <&gcc GCC_QUSB2PHY_PRIM_BCR>; + + #phy-cells = <0>; + + status = "disabled"; + }; + + usb_dp_qmpphy: phy@88e8000 { + compatible = "qcom,sm8650-qmp-usb3-dp-phy"; + reg = <0 0x088e8000 0 0x3000>; + + clocks = <&gcc GCC_USB3_PRIM_PHY_AUX_CLK>, + <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>, + <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; + clock-names = "aux", + "ref", + "com_aux", + "usb3_pipe"; + + resets = <&gcc GCC_USB3_PHY_PRIM_BCR>, + <&gcc GCC_USB3_DP_PHY_PRIM_BCR>; + reset-names = "phy", + "common"; + + power-domains = <&gcc USB3_PHY_GDSC>; + + #clock-cells = <1>; + #phy-cells = <1>; + + orientation-switch; + + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + usb_dp_qmpphy_out: endpoint { + }; + }; + + port@1 { + reg = <1>; + + usb_dp_qmpphy_usb_ss_in: endpoint { + remote-endpoint = <&usb_1_dwc3_ss>; + }; + }; + + port@2 { + reg = <2>; + + usb_dp_qmpphy_dp_in: endpoint { + remote-endpoint = <&mdss_dp0_out>; + }; + }; + }; + }; + + usb_1: usb@a600000 { + compatible = "qcom,sm8650-dwc3", "qcom,snps-dwc3"; + reg = <0 0x0a600000 0 0xfc100>; + + interrupts-extended = <&intc GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH 0>, + <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH 0>, + <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH 0>, + <&pdc 14 IRQ_TYPE_EDGE_RISING>, + <&pdc 15 IRQ_TYPE_EDGE_RISING>, + <&pdc 17 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "dwc_usb3", + "pwr_event", + "hs_phy_irq", + "dp_hs_phy_irq", + "dm_hs_phy_irq", + "ss_phy_irq"; + + clocks = <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, + <&gcc GCC_USB30_PRIM_MASTER_CLK>, + <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>, + <&gcc GCC_USB30_PRIM_SLEEP_CLK>, + <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, + <&tcsr TCSR_USB3_CLKREF_EN>; + clock-names = "cfg_noc", + "core", + "iface", + "sleep", + "mock_utmi", + "xo"; + + assigned-clocks = <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, + <&gcc GCC_USB30_PRIM_MASTER_CLK>; + assigned-clock-rates = <19200000>, <200000000>; + + resets = <&gcc GCC_USB30_PRIM_BCR>; + + phys = <&usb_1_hsphy>, + <&usb_dp_qmpphy QMP_USB43DP_USB3_PHY>; + phy-names = "usb2-phy", + "usb3-phy"; + + interconnects = <&aggre1_noc MASTER_USB3_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &config_noc SLAVE_USB3_0 QCOM_ICC_TAG_ACTIVE_ONLY>; + interconnect-names = "usb-ddr", + "apps-usb"; + + iommus = <&apps_smmu 0x40 0>; + + power-domains = <&gcc USB30_PRIM_GDSC>; + required-opps = <&rpmhpd_opp_nom>; + + snps,hird-threshold = /bits/ 8 <0x0>; + snps,usb2-gadget-lpm-disable; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; + snps,dis-u1-entry-quirk; + snps,dis-u2-entry-quirk; + snps,is-utmi-l1-suspend; + snps,usb3_lpm_capable; + snps,usb2-lpm-disable; + snps,has-lpm-erratum; + tx-fifo-resize; + + dma-coherent; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + usb_1_dwc3_hs: endpoint { + }; + }; + + port@1 { + reg = <1>; + + usb_1_dwc3_ss: endpoint { + remote-endpoint = <&usb_dp_qmpphy_usb_ss_in>; + }; + }; + }; + }; + iris: video-codec@aa00000 { compatible = "qcom,sm8650-iris"; reg = <0 0x0aa00000 0 0xf0000>; @@ -5580,170 +5744,6 @@ dispcc: clock-controller@af00000 { #power-domain-cells = <1>; }; - usb_1_hsphy: phy@88e3000 { - compatible = "qcom,sm8650-snps-eusb2-phy", - "qcom,sm8550-snps-eusb2-phy"; - reg = <0 0x088e3000 0 0x154>; - - clocks = <&tcsr TCSR_USB2_CLKREF_EN>; - clock-names = "ref"; - - resets = <&gcc GCC_QUSB2PHY_PRIM_BCR>; - - #phy-cells = <0>; - - status = "disabled"; - }; - - usb_dp_qmpphy: phy@88e8000 { - compatible = "qcom,sm8650-qmp-usb3-dp-phy"; - reg = <0 0x088e8000 0 0x3000>; - - clocks = <&gcc GCC_USB3_PRIM_PHY_AUX_CLK>, - <&rpmhcc RPMH_CXO_CLK>, - <&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>, - <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; - clock-names = "aux", - "ref", - "com_aux", - "usb3_pipe"; - - resets = <&gcc GCC_USB3_PHY_PRIM_BCR>, - <&gcc GCC_USB3_DP_PHY_PRIM_BCR>; - reset-names = "phy", - "common"; - - power-domains = <&gcc USB3_PHY_GDSC>; - - #clock-cells = <1>; - #phy-cells = <1>; - - orientation-switch; - - status = "disabled"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - - usb_dp_qmpphy_out: endpoint { - }; - }; - - port@1 { - reg = <1>; - - usb_dp_qmpphy_usb_ss_in: endpoint { - remote-endpoint = <&usb_1_dwc3_ss>; - }; - }; - - port@2 { - reg = <2>; - - usb_dp_qmpphy_dp_in: endpoint { - remote-endpoint = <&mdss_dp0_out>; - }; - }; - }; - }; - - usb_1: usb@a600000 { - compatible = "qcom,sm8650-dwc3", "qcom,snps-dwc3"; - reg = <0 0x0a600000 0 0xfc100>; - - interrupts-extended = <&intc GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH 0>, - <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH 0>, - <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH 0>, - <&pdc 14 IRQ_TYPE_EDGE_RISING>, - <&pdc 15 IRQ_TYPE_EDGE_RISING>, - <&pdc 17 IRQ_TYPE_LEVEL_HIGH>; - interrupt-names = "dwc_usb3", - "pwr_event", - "hs_phy_irq", - "dp_hs_phy_irq", - "dm_hs_phy_irq", - "ss_phy_irq"; - - clocks = <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, - <&gcc GCC_USB30_PRIM_MASTER_CLK>, - <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>, - <&gcc GCC_USB30_PRIM_SLEEP_CLK>, - <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, - <&tcsr TCSR_USB3_CLKREF_EN>; - clock-names = "cfg_noc", - "core", - "iface", - "sleep", - "mock_utmi", - "xo"; - - assigned-clocks = <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, - <&gcc GCC_USB30_PRIM_MASTER_CLK>; - assigned-clock-rates = <19200000>, <200000000>; - - resets = <&gcc GCC_USB30_PRIM_BCR>; - - phys = <&usb_1_hsphy>, - <&usb_dp_qmpphy QMP_USB43DP_USB3_PHY>; - phy-names = "usb2-phy", - "usb3-phy"; - - interconnects = <&aggre1_noc MASTER_USB3_0 QCOM_ICC_TAG_ALWAYS - &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, - <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY - &config_noc SLAVE_USB3_0 QCOM_ICC_TAG_ACTIVE_ONLY>; - interconnect-names = "usb-ddr", - "apps-usb"; - - iommus = <&apps_smmu 0x40 0>; - - power-domains = <&gcc USB30_PRIM_GDSC>; - required-opps = <&rpmhpd_opp_nom>; - - snps,hird-threshold = /bits/ 8 <0x0>; - snps,usb2-gadget-lpm-disable; - snps,dis_u2_susphy_quirk; - snps,dis_enblslpm_quirk; - snps,dis-u1-entry-quirk; - snps,dis-u2-entry-quirk; - snps,is-utmi-l1-suspend; - snps,usb3_lpm_capable; - snps,usb2-lpm-disable; - snps,has-lpm-erratum; - tx-fifo-resize; - - dma-coherent; - - #address-cells = <1>; - #size-cells = <0>; - - status = "disabled"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - - usb_1_dwc3_hs: endpoint { - }; - }; - - port@1 { - reg = <1>; - - usb_1_dwc3_ss: endpoint { - remote-endpoint = <&usb_dp_qmpphy_usb_ss_in>; - }; - }; - }; - }; - pdc: interrupt-controller@b220000 { compatible = "qcom,sm8650-pdc", "qcom,pdc"; reg = <0 0x0b220000 0 0x30000>, <0 0x174000f0 0 0x64>; From b41dc83f0790fd3488a45b31de0b0c3af7d441fe Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 11 Aug 2025 11:26:29 -0700 Subject: [PATCH 00305/11391] kunit, lib/crypto: Move run_irq_test() to common header Rename run_irq_test() to kunit_run_irq_test() and move it to a public header so that it can be reused by crc_kunit. Link: https://lore.kernel.org/r/20250811182631.376302-2-ebiggers@kernel.org Signed-off-by: Eric Biggers --- include/kunit/run-in-irq-context.h | 129 ++++++++++++++++++++++++++ lib/crypto/tests/hash-test-template.h | 123 +----------------------- 2 files changed, 133 insertions(+), 119 deletions(-) create mode 100644 include/kunit/run-in-irq-context.h diff --git a/include/kunit/run-in-irq-context.h b/include/kunit/run-in-irq-context.h new file mode 100644 index 000000000000..108e96433ea4 --- /dev/null +++ b/include/kunit/run-in-irq-context.h @@ -0,0 +1,129 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Helper function for testing code in interrupt contexts + * + * Copyright 2025 Google LLC + */ +#ifndef _KUNIT_RUN_IN_IRQ_CONTEXT_H +#define _KUNIT_RUN_IN_IRQ_CONTEXT_H + +#include +#include +#include +#include + +#define KUNIT_IRQ_TEST_HRTIMER_INTERVAL us_to_ktime(5) + +struct kunit_irq_test_state { + bool (*func)(void *test_specific_state); + void *test_specific_state; + bool task_func_reported_failure; + bool hardirq_func_reported_failure; + bool softirq_func_reported_failure; + unsigned long hardirq_func_calls; + unsigned long softirq_func_calls; + struct hrtimer timer; + struct work_struct bh_work; +}; + +static enum hrtimer_restart kunit_irq_test_timer_func(struct hrtimer *timer) +{ + struct kunit_irq_test_state *state = + container_of(timer, typeof(*state), timer); + + WARN_ON_ONCE(!in_hardirq()); + state->hardirq_func_calls++; + + if (!state->func(state->test_specific_state)) + state->hardirq_func_reported_failure = true; + + hrtimer_forward_now(&state->timer, KUNIT_IRQ_TEST_HRTIMER_INTERVAL); + queue_work(system_bh_wq, &state->bh_work); + return HRTIMER_RESTART; +} + +static void kunit_irq_test_bh_work_func(struct work_struct *work) +{ + struct kunit_irq_test_state *state = + container_of(work, typeof(*state), bh_work); + + WARN_ON_ONCE(!in_serving_softirq()); + state->softirq_func_calls++; + + if (!state->func(state->test_specific_state)) + state->softirq_func_reported_failure = true; +} + +/* + * Helper function which repeatedly runs the given @func in task, softirq, and + * hardirq context concurrently, and reports a failure to KUnit if any + * invocation of @func in any context returns false. @func is passed + * @test_specific_state as its argument. At most 3 invocations of @func will + * run concurrently: one in each of task, softirq, and hardirq context. + * + * The main purpose of this interrupt context testing is to validate fallback + * code paths that run in contexts where the normal code path cannot be used, + * typically due to the FPU or vector registers already being in-use in kernel + * mode. These code paths aren't covered when the test code is executed only by + * the KUnit test runner thread in task context. The reason for the concurrency + * is because merely using hardirq context is not sufficient to reach a fallback + * code path on some architectures; the hardirq actually has to occur while the + * FPU or vector unit was already in-use in kernel mode. + * + * Another purpose of this testing is to detect issues with the architecture's + * irq_fpu_usable() and kernel_fpu_begin/end() or equivalent functions, + * especially in softirq context when the softirq may have interrupted a task + * already using kernel-mode FPU or vector (if the arch didn't prevent that). + * Crypto functions are often executed in softirqs, so this is important. + */ +static inline void kunit_run_irq_test(struct kunit *test, bool (*func)(void *), + int max_iterations, + void *test_specific_state) +{ + struct kunit_irq_test_state state = { + .func = func, + .test_specific_state = test_specific_state, + }; + unsigned long end_jiffies; + + /* + * Set up a hrtimer (the way we access hardirq context) and a work + * struct for the BH workqueue (the way we access softirq context). + */ + hrtimer_setup_on_stack(&state.timer, kunit_irq_test_timer_func, + CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD); + INIT_WORK_ONSTACK(&state.bh_work, kunit_irq_test_bh_work_func); + + /* Run for up to max_iterations or 1 second, whichever comes first. */ + end_jiffies = jiffies + HZ; + hrtimer_start(&state.timer, KUNIT_IRQ_TEST_HRTIMER_INTERVAL, + HRTIMER_MODE_REL_HARD); + for (int i = 0; i < max_iterations && !time_after(jiffies, end_jiffies); + i++) { + if (!func(test_specific_state)) + state.task_func_reported_failure = true; + } + + /* Cancel the timer and work. */ + hrtimer_cancel(&state.timer); + flush_work(&state.bh_work); + + /* Sanity check: the timer and BH functions should have been run. */ + KUNIT_EXPECT_GT_MSG(test, state.hardirq_func_calls, 0, + "Timer function was not called"); + KUNIT_EXPECT_GT_MSG(test, state.softirq_func_calls, 0, + "BH work function was not called"); + + /* Check for incorrect hash values reported from any context. */ + KUNIT_EXPECT_FALSE_MSG( + test, state.task_func_reported_failure, + "Incorrect hash values reported from task context"); + KUNIT_EXPECT_FALSE_MSG( + test, state.hardirq_func_reported_failure, + "Incorrect hash values reported from hardirq context"); + KUNIT_EXPECT_FALSE_MSG( + test, state.softirq_func_reported_failure, + "Incorrect hash values reported from softirq context"); +} + +#endif /* _KUNIT_RUN_IN_IRQ_CONTEXT_H */ diff --git a/lib/crypto/tests/hash-test-template.h b/lib/crypto/tests/hash-test-template.h index f437a0a9ac6c..61b43e62779f 100644 --- a/lib/crypto/tests/hash-test-template.h +++ b/lib/crypto/tests/hash-test-template.h @@ -5,11 +5,9 @@ * * Copyright 2025 Google LLC */ +#include #include -#include -#include #include -#include /* test_buf is a guarded buffer, i.e. &test_buf[TEST_BUF_LEN] is not mapped. */ #define TEST_BUF_LEN 16384 @@ -319,119 +317,6 @@ static void test_hash_ctx_zeroization(struct kunit *test) "Hash context was not zeroized by finalization"); } -#define IRQ_TEST_HRTIMER_INTERVAL us_to_ktime(5) - -struct hash_irq_test_state { - bool (*func)(void *test_specific_state); - void *test_specific_state; - bool task_func_reported_failure; - bool hardirq_func_reported_failure; - bool softirq_func_reported_failure; - unsigned long hardirq_func_calls; - unsigned long softirq_func_calls; - struct hrtimer timer; - struct work_struct bh_work; -}; - -static enum hrtimer_restart hash_irq_test_timer_func(struct hrtimer *timer) -{ - struct hash_irq_test_state *state = - container_of(timer, typeof(*state), timer); - - WARN_ON_ONCE(!in_hardirq()); - state->hardirq_func_calls++; - - if (!state->func(state->test_specific_state)) - state->hardirq_func_reported_failure = true; - - hrtimer_forward_now(&state->timer, IRQ_TEST_HRTIMER_INTERVAL); - queue_work(system_bh_wq, &state->bh_work); - return HRTIMER_RESTART; -} - -static void hash_irq_test_bh_work_func(struct work_struct *work) -{ - struct hash_irq_test_state *state = - container_of(work, typeof(*state), bh_work); - - WARN_ON_ONCE(!in_serving_softirq()); - state->softirq_func_calls++; - - if (!state->func(state->test_specific_state)) - state->softirq_func_reported_failure = true; -} - -/* - * Helper function which repeatedly runs the given @func in task, softirq, and - * hardirq context concurrently, and reports a failure to KUnit if any - * invocation of @func in any context returns false. @func is passed - * @test_specific_state as its argument. At most 3 invocations of @func will - * run concurrently: one in each of task, softirq, and hardirq context. - * - * The main purpose of this interrupt context testing is to validate fallback - * code paths that run in contexts where the normal code path cannot be used, - * typically due to the FPU or vector registers already being in-use in kernel - * mode. These code paths aren't covered when the test code is executed only by - * the KUnit test runner thread in task context. The reason for the concurrency - * is because merely using hardirq context is not sufficient to reach a fallback - * code path on some architectures; the hardirq actually has to occur while the - * FPU or vector unit was already in-use in kernel mode. - * - * Another purpose of this testing is to detect issues with the architecture's - * irq_fpu_usable() and kernel_fpu_begin/end() or equivalent functions, - * especially in softirq context when the softirq may have interrupted a task - * already using kernel-mode FPU or vector (if the arch didn't prevent that). - * Crypto functions are often executed in softirqs, so this is important. - */ -static void run_irq_test(struct kunit *test, bool (*func)(void *), - int max_iterations, void *test_specific_state) -{ - struct hash_irq_test_state state = { - .func = func, - .test_specific_state = test_specific_state, - }; - unsigned long end_jiffies; - - /* - * Set up a hrtimer (the way we access hardirq context) and a work - * struct for the BH workqueue (the way we access softirq context). - */ - hrtimer_setup_on_stack(&state.timer, hash_irq_test_timer_func, - CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD); - INIT_WORK_ONSTACK(&state.bh_work, hash_irq_test_bh_work_func); - - /* Run for up to max_iterations or 1 second, whichever comes first. */ - end_jiffies = jiffies + HZ; - hrtimer_start(&state.timer, IRQ_TEST_HRTIMER_INTERVAL, - HRTIMER_MODE_REL_HARD); - for (int i = 0; i < max_iterations && !time_after(jiffies, end_jiffies); - i++) { - if (!func(test_specific_state)) - state.task_func_reported_failure = true; - } - - /* Cancel the timer and work. */ - hrtimer_cancel(&state.timer); - flush_work(&state.bh_work); - - /* Sanity check: the timer and BH functions should have been run. */ - KUNIT_EXPECT_GT_MSG(test, state.hardirq_func_calls, 0, - "Timer function was not called"); - KUNIT_EXPECT_GT_MSG(test, state.softirq_func_calls, 0, - "BH work function was not called"); - - /* Check for incorrect hash values reported from any context. */ - KUNIT_EXPECT_FALSE_MSG( - test, state.task_func_reported_failure, - "Incorrect hash values reported from task context"); - KUNIT_EXPECT_FALSE_MSG( - test, state.hardirq_func_reported_failure, - "Incorrect hash values reported from hardirq context"); - KUNIT_EXPECT_FALSE_MSG( - test, state.softirq_func_reported_failure, - "Incorrect hash values reported from softirq context"); -} - #define IRQ_TEST_DATA_LEN 256 #define IRQ_TEST_NUM_BUFFERS 3 /* matches max concurrency level */ @@ -469,7 +354,7 @@ static void test_hash_interrupt_context_1(struct kunit *test) HASH(&test_buf[i * IRQ_TEST_DATA_LEN], IRQ_TEST_DATA_LEN, state.expected_hashes[i]); - run_irq_test(test, hash_irq_test1_func, 100000, &state); + kunit_run_irq_test(test, hash_irq_test1_func, 100000, &state); } struct hash_irq_test2_hash_ctx { @@ -500,7 +385,7 @@ static bool hash_irq_test2_func(void *state_) if (WARN_ON_ONCE(ctx == &state->ctxs[ARRAY_SIZE(state->ctxs)])) { /* * This should never happen, as the number of contexts is equal - * to the maximum concurrency level of run_irq_test(). + * to the maximum concurrency level of kunit_run_irq_test(). */ return false; } @@ -566,7 +451,7 @@ static void test_hash_interrupt_context_2(struct kunit *test) state->update_lens[state->num_steps++] = remaining; state->num_steps += 2; /* for init and final */ - run_irq_test(test, hash_irq_test2_func, 250000, state); + kunit_run_irq_test(test, hash_irq_test2_func, 250000, state); } #define UNKEYED_HASH_KUNIT_CASES \ From 842ec21357f15ff722695dd87daf99823f297185 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 11 Aug 2025 11:26:30 -0700 Subject: [PATCH 00306/11391] lib/crc: crc_kunit: Test CRC computation in interrupt contexts Test that if CRCs are computed in task, softirq, and hardirq context concurrently, then all results are as expected. Implement this using kunit_run_irq_test() which is also used by the lib/crypto/ tests. As with the corresponding lib/crypto/ tests, the purpose of this is to test fallback code paths and to exercise edge cases in the architecture's support for in-kernel FPU/SIMD/vector. Remove the code from crc_test() that sometimes disabled interrupts, as that was just an incomplete attempt to achieve similar test coverage. Link: https://lore.kernel.org/r/20250811182631.376302-3-ebiggers@kernel.org Signed-off-by: Eric Biggers --- lib/crc/tests/crc_kunit.c | 62 +++++++++++++++++++++++++++++++++------ 1 file changed, 53 insertions(+), 9 deletions(-) diff --git a/lib/crc/tests/crc_kunit.c b/lib/crc/tests/crc_kunit.c index f08d985d8860..9a450e25ac81 100644 --- a/lib/crc/tests/crc_kunit.c +++ b/lib/crc/tests/crc_kunit.c @@ -6,6 +6,7 @@ * * Author: Eric Biggers */ +#include #include #include #include @@ -141,6 +142,54 @@ static size_t generate_random_length(size_t max_length) return len % (max_length + 1); } +#define IRQ_TEST_DATA_LEN 512 +#define IRQ_TEST_NUM_BUFFERS 3 /* matches max concurrency level */ + +struct crc_irq_test_state { + const struct crc_variant *v; + u64 initial_crc; + u64 expected_crcs[IRQ_TEST_NUM_BUFFERS]; + atomic_t seqno; +}; + +/* + * Compute the CRC of one of the test messages and verify that it matches the + * expected CRC from @state->expected_crcs. To increase the chance of detecting + * problems, cycle through multiple messages. + */ +static bool crc_irq_test_func(void *state_) +{ + struct crc_irq_test_state *state = state_; + const struct crc_variant *v = state->v; + u32 i = (u32)atomic_inc_return(&state->seqno) % IRQ_TEST_NUM_BUFFERS; + u64 actual_crc = v->func(state->initial_crc, + &test_buffer[i * IRQ_TEST_DATA_LEN], + IRQ_TEST_DATA_LEN); + + return actual_crc == state->expected_crcs[i]; +} + +/* + * Test that if CRCs are computed in task, softirq, and hardirq context + * concurrently, then all results are as expected. + */ +static void crc_interrupt_context_test(struct kunit *test, + const struct crc_variant *v) +{ + struct crc_irq_test_state state = { + .v = v, + .initial_crc = generate_random_initial_crc(v), + }; + + for (int i = 0; i < IRQ_TEST_NUM_BUFFERS; i++) { + state.expected_crcs[i] = crc_ref( + v, state.initial_crc, + &test_buffer[i * IRQ_TEST_DATA_LEN], IRQ_TEST_DATA_LEN); + } + + kunit_run_irq_test(test, crc_irq_test_func, 100000, &state); +} + /* Test that v->func gives the same CRCs as a reference implementation. */ static void crc_test(struct kunit *test, const struct crc_variant *v) { @@ -149,7 +198,6 @@ static void crc_test(struct kunit *test, const struct crc_variant *v) for (i = 0; i < CRC_KUNIT_NUM_TEST_ITERS; i++) { u64 init_crc, expected_crc, actual_crc; size_t len, offset; - bool nosimd; init_crc = generate_random_initial_crc(v); len = generate_random_length(CRC_KUNIT_MAX_LEN); @@ -168,22 +216,18 @@ static void crc_test(struct kunit *test, const struct crc_variant *v) /* Refresh the data occasionally. */ prandom_bytes_state(&rng, &test_buffer[offset], len); - nosimd = rand32() % 8 == 0; - /* * Compute the CRC, and verify that it equals the CRC computed * by a simple bit-at-a-time reference implementation. */ expected_crc = crc_ref(v, init_crc, &test_buffer[offset], len); - if (nosimd) - local_irq_disable(); actual_crc = v->func(init_crc, &test_buffer[offset], len); - if (nosimd) - local_irq_enable(); KUNIT_EXPECT_EQ_MSG(test, expected_crc, actual_crc, - "Wrong result with len=%zu offset=%zu nosimd=%d", - len, offset, nosimd); + "Wrong result with len=%zu offset=%zu", + len, offset); } + + crc_interrupt_context_test(test, v); } static __always_inline void From c2a0c5156a40c40edb0cce80ce11c97ab39c67e3 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 11 Aug 2025 11:26:31 -0700 Subject: [PATCH 00307/11391] lib/crc: Use underlying functions instead of crypto_simd_usable() Since crc_kunit now tests the fallback code paths without using crypto_simd_disabled_for_test, make the CRC code just use the underlying may_use_simd() and irq_fpu_usable() functions directly instead of crypto_simd_usable(). This eliminates an unnecessary layer. Take the opportunity to add likely() and unlikely() annotations as well. Link: https://lore.kernel.org/r/20250811182631.376302-4-ebiggers@kernel.org Signed-off-by: Eric Biggers --- lib/crc/arm/crc-t10dif.h | 6 ++---- lib/crc/arm/crc32.h | 6 ++---- lib/crc/arm64/crc-t10dif.h | 6 ++---- lib/crc/arm64/crc32.h | 11 ++++++----- lib/crc/powerpc/crc-t10dif.h | 5 +++-- lib/crc/powerpc/crc32.h | 5 +++-- lib/crc/x86/crc-pclmul-template.h | 3 +-- lib/crc/x86/crc32.h | 2 +- 8 files changed, 20 insertions(+), 24 deletions(-) diff --git a/lib/crc/arm/crc-t10dif.h b/lib/crc/arm/crc-t10dif.h index 2edf7e9681d0..1a969f4024d4 100644 --- a/lib/crc/arm/crc-t10dif.h +++ b/lib/crc/arm/crc-t10dif.h @@ -5,8 +5,6 @@ * Copyright (C) 2016 Linaro Ltd */ -#include - #include #include @@ -23,7 +21,7 @@ static inline u16 crc_t10dif_arch(u16 crc, const u8 *data, size_t length) { if (length >= CRC_T10DIF_PMULL_CHUNK_SIZE) { if (static_branch_likely(&have_pmull)) { - if (crypto_simd_usable()) { + if (likely(may_use_simd())) { kernel_neon_begin(); crc = crc_t10dif_pmull64(crc, data, length); kernel_neon_end(); @@ -31,7 +29,7 @@ static inline u16 crc_t10dif_arch(u16 crc, const u8 *data, size_t length) } } else if (length > CRC_T10DIF_PMULL_CHUNK_SIZE && static_branch_likely(&have_neon) && - crypto_simd_usable()) { + likely(may_use_simd())) { u8 buf[16] __aligned(16); kernel_neon_begin(); diff --git a/lib/crc/arm/crc32.h b/lib/crc/arm/crc32.h index 018007e162a2..ae71aa60b7a7 100644 --- a/lib/crc/arm/crc32.h +++ b/lib/crc/arm/crc32.h @@ -7,8 +7,6 @@ #include -#include - #include #include #include @@ -34,7 +32,7 @@ static inline u32 crc32_le_scalar(u32 crc, const u8 *p, size_t len) static inline u32 crc32_le_arch(u32 crc, const u8 *p, size_t len) { if (len >= PMULL_MIN_LEN + 15 && - static_branch_likely(&have_pmull) && crypto_simd_usable()) { + static_branch_likely(&have_pmull) && likely(may_use_simd())) { size_t n = -(uintptr_t)p & 15; /* align p to 16-byte boundary */ @@ -63,7 +61,7 @@ static inline u32 crc32c_scalar(u32 crc, const u8 *p, size_t len) static inline u32 crc32c_arch(u32 crc, const u8 *p, size_t len) { if (len >= PMULL_MIN_LEN + 15 && - static_branch_likely(&have_pmull) && crypto_simd_usable()) { + static_branch_likely(&have_pmull) && likely(may_use_simd())) { size_t n = -(uintptr_t)p & 15; /* align p to 16-byte boundary */ diff --git a/lib/crc/arm64/crc-t10dif.h b/lib/crc/arm64/crc-t10dif.h index c4521a7f1ee9..435a990ec43c 100644 --- a/lib/crc/arm64/crc-t10dif.h +++ b/lib/crc/arm64/crc-t10dif.h @@ -7,8 +7,6 @@ #include -#include - #include #include @@ -25,7 +23,7 @@ static inline u16 crc_t10dif_arch(u16 crc, const u8 *data, size_t length) { if (length >= CRC_T10DIF_PMULL_CHUNK_SIZE) { if (static_branch_likely(&have_pmull)) { - if (crypto_simd_usable()) { + if (likely(may_use_simd())) { kernel_neon_begin(); crc = crc_t10dif_pmull_p64(crc, data, length); kernel_neon_end(); @@ -33,7 +31,7 @@ static inline u16 crc_t10dif_arch(u16 crc, const u8 *data, size_t length) } } else if (length > CRC_T10DIF_PMULL_CHUNK_SIZE && static_branch_likely(&have_asimd) && - crypto_simd_usable()) { + likely(may_use_simd())) { u8 buf[16]; kernel_neon_begin(); diff --git a/lib/crc/arm64/crc32.h b/lib/crc/arm64/crc32.h index 6e5dec45f05d..31e649cd40a2 100644 --- a/lib/crc/arm64/crc32.h +++ b/lib/crc/arm64/crc32.h @@ -5,8 +5,6 @@ #include #include -#include - // The minimum input length to consider the 4-way interleaved code path static const size_t min_len = 1024; @@ -23,7 +21,8 @@ static inline u32 crc32_le_arch(u32 crc, const u8 *p, size_t len) if (!alternative_has_cap_likely(ARM64_HAS_CRC32)) return crc32_le_base(crc, p, len); - if (len >= min_len && cpu_have_named_feature(PMULL) && crypto_simd_usable()) { + if (len >= min_len && cpu_have_named_feature(PMULL) && + likely(may_use_simd())) { kernel_neon_begin(); crc = crc32_le_arm64_4way(crc, p, len); kernel_neon_end(); @@ -43,7 +42,8 @@ static inline u32 crc32c_arch(u32 crc, const u8 *p, size_t len) if (!alternative_has_cap_likely(ARM64_HAS_CRC32)) return crc32c_base(crc, p, len); - if (len >= min_len && cpu_have_named_feature(PMULL) && crypto_simd_usable()) { + if (len >= min_len && cpu_have_named_feature(PMULL) && + likely(may_use_simd())) { kernel_neon_begin(); crc = crc32c_le_arm64_4way(crc, p, len); kernel_neon_end(); @@ -63,7 +63,8 @@ static inline u32 crc32_be_arch(u32 crc, const u8 *p, size_t len) if (!alternative_has_cap_likely(ARM64_HAS_CRC32)) return crc32_be_base(crc, p, len); - if (len >= min_len && cpu_have_named_feature(PMULL) && crypto_simd_usable()) { + if (len >= min_len && cpu_have_named_feature(PMULL) && + likely(may_use_simd())) { kernel_neon_begin(); crc = crc32_be_arm64_4way(crc, p, len); kernel_neon_end(); diff --git a/lib/crc/powerpc/crc-t10dif.h b/lib/crc/powerpc/crc-t10dif.h index 59e16804a6ea..e033d5f57bae 100644 --- a/lib/crc/powerpc/crc-t10dif.h +++ b/lib/crc/powerpc/crc-t10dif.h @@ -6,8 +6,8 @@ * [based on crc32c-vpmsum_glue.c] */ +#include #include -#include #include #include #include @@ -29,7 +29,8 @@ static inline u16 crc_t10dif_arch(u16 crci, const u8 *p, size_t len) u32 crc = crci; if (len < (VECTOR_BREAKPOINT + VMX_ALIGN) || - !static_branch_likely(&have_vec_crypto) || !crypto_simd_usable()) + !static_branch_likely(&have_vec_crypto) || + unlikely(!may_use_simd())) return crc_t10dif_generic(crc, p, len); if ((unsigned long)p & VMX_ALIGN_MASK) { diff --git a/lib/crc/powerpc/crc32.h b/lib/crc/powerpc/crc32.h index 811cc2e6ed24..cc8fa3913d4e 100644 --- a/lib/crc/powerpc/crc32.h +++ b/lib/crc/powerpc/crc32.h @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only +#include #include -#include #include #include #include @@ -24,7 +24,8 @@ static inline u32 crc32c_arch(u32 crc, const u8 *p, size_t len) unsigned int tail; if (len < (VECTOR_BREAKPOINT + VMX_ALIGN) || - !static_branch_likely(&have_vec_crypto) || !crypto_simd_usable()) + !static_branch_likely(&have_vec_crypto) || + unlikely(!may_use_simd())) return crc32c_base(crc, p, len); if ((unsigned long)p & VMX_ALIGN_MASK) { diff --git a/lib/crc/x86/crc-pclmul-template.h b/lib/crc/x86/crc-pclmul-template.h index 35c950d7010c..02744831c6fa 100644 --- a/lib/crc/x86/crc-pclmul-template.h +++ b/lib/crc/x86/crc-pclmul-template.h @@ -12,7 +12,6 @@ #include #include -#include #include #include "crc-pclmul-consts.h" @@ -57,7 +56,7 @@ static inline bool have_avx512(void) #define CRC_PCLMUL(crc, p, len, prefix, consts, have_pclmulqdq) \ do { \ if ((len) >= 16 && static_branch_likely(&(have_pclmulqdq)) && \ - crypto_simd_usable()) { \ + likely(irq_fpu_usable())) { \ const void *consts_ptr; \ \ consts_ptr = (consts).fold_across_128_bits_consts; \ diff --git a/lib/crc/x86/crc32.h b/lib/crc/x86/crc32.h index cea2c96d08d0..2c4a5976654a 100644 --- a/lib/crc/x86/crc32.h +++ b/lib/crc/x86/crc32.h @@ -44,7 +44,7 @@ static inline u32 crc32c_arch(u32 crc, const u8 *p, size_t len) return crc32c_base(crc, p, len); if (IS_ENABLED(CONFIG_X86_64) && len >= CRC32C_PCLMUL_BREAKEVEN && - static_branch_likely(&have_pclmulqdq) && crypto_simd_usable()) { + static_branch_likely(&have_pclmulqdq) && likely(irq_fpu_usable())) { /* * Long length, the vector registers are usable, and the CPU is * 64-bit and supports both CRC32 and PCLMULQDQ instructions. From cb69daf085b5974fef2df9789f8c1b35e78e7913 Mon Sep 17 00:00:00 2001 From: Nick Hu Date: Fri, 1 Aug 2025 15:01:12 +0800 Subject: [PATCH 00308/11391] dt-bindings: riscv: Add SiFive vendor extensions description Add description for SiFive vendor extensions "xsfcflushdlone", "xsfpgflushdlone" and "xsfcease". This is used in the SBI implementation [1]. Link: https://lore.kernel.org/opensbi/20250708074940.10904-1-nick.hu@sifive.com/ [1] Signed-off-by: Nick Hu Acked-by: Conor Dooley Signed-off-by: Conor Dooley --- .../devicetree/bindings/riscv/extensions.yaml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml index ede6a58ccf53..5638297759df 100644 --- a/Documentation/devicetree/bindings/riscv/extensions.yaml +++ b/Documentation/devicetree/bindings/riscv/extensions.yaml @@ -663,6 +663,24 @@ properties: https://www.andestech.com/wp-content/uploads/AX45MP-1C-Rev.-5.0.0-Datasheet.pdf # SiFive + - const: xsfcease + description: + SiFive CEASE Instruction Extensions Specification. + See more details in + https://www.sifive.com/document-file/freedom-u740-c000-manual + + - const: xsfcflushdlone + description: + SiFive L1D Cache Flush Instruction Extensions Specification. + See more details in + https://www.sifive.com/document-file/freedom-u740-c000-manual + + - const: xsfpgflushdlone + description: + SiFive PGFLUSH Instruction Extensions for the power management. The + CPU will flush the L1D and enter the cease state after executing + the instruction. + - const: xsfvqmaccdod description: SiFive Int8 Matrix Multiplication Extensions Specification. 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 00309/11391] 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 00310/11391] 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 00311/11391] 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 00312/11391] 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 00313/11391] 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 00314/11391] 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 f93e5882134a314760d47536d93b57fbd32d0da1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 24 Jul 2025 15:24:37 +0200 Subject: [PATCH 00315/11391] dt-bindings: arm: qcom: Drop redundant free-form SoC list The schema and Devicetree specification defines how list of top-level compatibles should be created, thus first paragraph explaining this is completely redundant. The list of SoCs is redundant as well, because the schema lists them. On the other hand, Linux kernel should not be place to store marketing names of some company products, so such list is irrelevant here. Signed-off-by: Krzysztof Kozlowski Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250724132436.77160-2-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- .../devicetree/bindings/arm/qcom.yaml | 95 ------------------- 1 file changed, 95 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml index c8a71a33d358..1df00d9e6de0 100644 --- a/Documentation/devicetree/bindings/arm/qcom.yaml +++ b/Documentation/devicetree/bindings/arm/qcom.yaml @@ -10,101 +10,6 @@ maintainers: - Bjorn Andersson description: | - For devices using the Qualcomm SoC the "compatible" properties consists of - one or several "manufacturer,model" strings, describing the device itself, - followed by one or several "qcom," strings, describing the SoC used in - the device. - - The 'SoC' element must be one of the following strings: - - apq8016 - apq8026 - apq8064 - apq8074 - apq8084 - apq8094 - apq8096 - ipq4018 - ipq4019 - ipq5018 - ipq5332 - ipq5424 - ipq6018 - ipq8064 - ipq8074 - ipq9574 - mdm9615 - msm8226 - msm8660 - msm8916 - msm8917 - msm8926 - msm8929 - msm8939 - msm8953 - msm8956 - msm8960 - msm8974 - msm8974pro - msm8976 - msm8992 - msm8994 - msm8996 - msm8996pro - msm8998 - qcs404 - qcs615 - qcs8300 - qcs8550 - qcm2290 - qcm6490 - qcs9100 - qdu1000 - qrb2210 - qrb4210 - qru1000 - sa8155p - sa8540p - sa8775p - sar2130p - sc7180 - sc7280 - sc8180x - sc8280xp - sda660 - sdm450 - sdm630 - sdm632 - sdm636 - sdm660 - sdm670 - sdm845 - sdx55 - sdx65 - sdx75 - sm4250 - sm4450 - sm6115 - sm6115p - sm6125 - sm6150 - sm6350 - sm6375 - sm7125 - sm7150 - sm7225 - sm7325 - sm8150 - sm8250 - sm8350 - sm8450 - sm8550 - sm8650 - sm8750 - x1e78100 - x1e80100 - x1p42100 - There are many devices in the list below that run the standard ChromeOS bootloader setup and use the open source depthcharge bootloader to boot the OS. These devices use the bootflow explained at From 6facfaff0fe3b4d5903bed6164eb5e60ee6cdb8f Mon Sep 17 00:00:00 2001 From: Qiang Yu Date: Tue, 22 Jul 2025 17:11:50 +0800 Subject: [PATCH 00316/11391] arm64: dts: qcom: x1e80100: add bus topology for PCIe domain 3 Add pcie3_port node to represent the PCIe bridge of PCIe3 so that PCI slot voltage rails can be described under this node in the board's dts. Signed-off-by: Qiang Yu Signed-off-by: Wenbin Yao Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250722091151.1423332-3-quic_wenbyao@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/x1e80100.dtsi | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/x1e80100.dtsi b/arch/arm64/boot/dts/qcom/x1e80100.dtsi index 5e9a8fa3cf96..c9fea040223b 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100.dtsi +++ b/arch/arm64/boot/dts/qcom/x1e80100.dtsi @@ -3306,6 +3306,17 @@ opp-128000000 { opp-peak-kBps = <15753000 1>; }; }; + + pcie3_port: pcie@0 { + device_type = "pci"; + compatible = "pciclass,0604"; + reg = <0x0 0x0 0x0 0x0 0x0>; + bus-range = <0x01 0xff>; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + }; }; pcie3_phy: phy@1be0000 { From df758a868dbc90cae98044d52a9d753575f50cfa Mon Sep 17 00:00:00 2001 From: Qiang Yu Date: Tue, 22 Jul 2025 17:11:51 +0800 Subject: [PATCH 00317/11391] arm64: dts: qcom: x1e80100-qcp: enable pcie3 x8 slot for X1E80100-QCP Add perst, wake and clkreq sideband signals and required regulators in PCIe3 controller and PHY device tree node. Describe the voltage rails of the x8 PCI slots for PCIe3 port. Signed-off-by: Qiang Yu Signed-off-by: Wenbin Yao Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250722091151.1423332-4-quic_wenbyao@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/x1e80100-qcp.dts | 118 ++++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts b/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts index 4dfba835af6a..71c44e37a44b 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts +++ b/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts @@ -318,6 +318,48 @@ vreg_wcn_3p3: regulator-wcn-3p3 { regulator-boot-on; }; + vreg_pcie_12v: regulator-pcie-12v { + compatible = "regulator-fixed"; + + regulator-name = "VREG_PCIE_12V"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + + gpio = <&pm8550ve_8_gpios 8 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-0 = <&pcie_x8_12v>; + pinctrl-names = "default"; + }; + + vreg_pcie_3v3_aux: regulator-pcie-3v3-aux { + compatible = "regulator-fixed"; + + regulator-name = "VREG_PCIE_3P3_AUX"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + gpio = <&pmc8380_3_gpios 8 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-0 = <&pm_sde7_aux_3p3_en>; + pinctrl-names = "default"; + }; + + vreg_pcie_3v3: regulator-pcie-3v3 { + compatible = "regulator-fixed"; + + regulator-name = "VREG_PCIE_3P3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + gpio = <&pmc8380_3_gpios 6 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-0 = <&pm_sde7_main_3p3_en>; + pinctrl-names = "default"; +}; + usb-1-ss0-sbu-mux { compatible = "onnn,fsusb42", "gpio-sbu-mux"; @@ -908,6 +950,59 @@ &mdss_dp3_phy { status = "okay"; }; +&pm8550ve_8_gpios { + pcie_x8_12v: pcie-12v-default-state { + pins = "gpio8"; + function = "normal"; + output-enable; + output-high; + bias-pull-down; + power-source = <0>; + }; +}; + +&pmc8380_3_gpios { + pm_sde7_aux_3p3_en: pcie-aux-3p3-default-state { + pins = "gpio8"; + function = "normal"; + output-enable; + output-high; + bias-pull-down; + power-source = <0>; + }; + + pm_sde7_main_3p3_en: pcie-main-3p3-default-state { + pins = "gpio6"; + function = "normal"; + output-enable; + output-high; + bias-pull-down; + power-source = <0>; + }; +}; + +&pcie3 { + pinctrl-names = "default"; + pinctrl-0 = <&pcie3_default>; + perst-gpios = <&tlmm 143 GPIO_ACTIVE_LOW>; + wake-gpios = <&tlmm 145 GPIO_ACTIVE_LOW>; + + status = "okay"; +}; + +&pcie3_phy { + vdda-phy-supply = <&vreg_l3c_0p8>; + vdda-pll-supply = <&vreg_l3e_1p2>; + + status = "okay"; +}; + +&pcie3_port { + vpcie12v-supply = <&vreg_pcie_12v>; + vpcie3v3-supply = <&vreg_pcie_3v3>; + vpcie3v3aux-supply = <&vreg_pcie_3v3_aux>; +}; + &pcie4 { perst-gpios = <&tlmm 146 GPIO_ACTIVE_LOW>; wake-gpios = <&tlmm 148 GPIO_ACTIVE_LOW>; @@ -1119,6 +1214,29 @@ nvme_reg_en: nvme-reg-en-state { bias-disable; }; + pcie3_default: pcie3-default-state { + clkreq-n-pins { + pins = "gpio144"; + function = "pcie3_clk"; + drive-strength = <2>; + bias-pull-up; + }; + + perst-n-pins { + pins = "gpio143"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + wake-n-pins { + pins = "gpio145"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + pcie4_default: pcie4-default-state { clkreq-n-pins { pins = "gpio147"; From bebacd802b51fae87e04a0f2b6eeb66ac259c14e Mon Sep 17 00:00:00 2001 From: Raviteja Laggyshetty Date: Tue, 22 Jul 2025 05:50:39 +0000 Subject: [PATCH 00318/11391] arm64: dts: qcom: qcs8300: Add EPSS l3 interconnect provider node and CPUCP OPP tables to scale DDR/L3 Add Epoch Subsystem (EPSS) L3 interconnect provider node and OPP tables required to scale DDR and L3 per freq-domain on QCS8300 platform. As QCS8300 and SA8775P SoCs have same EPSS hardware, added SA8775P compatible as fallback for QCS8300 EPSS device node. Reviewed-by: Konrad Dybcio Co-developed-by: Imran Shaik Signed-off-by: Imran Shaik Signed-off-by: Raviteja Laggyshetty Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250722055039.135140-2-raviteja.laggyshetty@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/qcs8300.dtsi | 301 ++++++++++++++++++++++++++ 1 file changed, 301 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs8300.dtsi b/arch/arm64/boot/dts/qcom/qcs8300.dtsi index 7ada029c32c1..7d38ddd2cc9e 100644 --- a/arch/arm64/boot/dts/qcom/qcs8300.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs8300.dtsi @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -53,6 +54,11 @@ cpu0: cpu@0 { capacity-dmips-mhz = <1946>; dynamic-power-coefficient = <472>; qcom,freq-domain = <&cpufreq_hw 0>; + operating-points-v2 = <&cpu0_opp_table>; + interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>, + <&epss_l3_cl0 MASTER_EPSS_L3_APPS + &epss_l3_cl0 SLAVE_EPSS_L3_SHARED>; l2_0: l2-cache { compatible = "cache"; @@ -73,6 +79,11 @@ cpu1: cpu@100 { capacity-dmips-mhz = <1946>; dynamic-power-coefficient = <472>; qcom,freq-domain = <&cpufreq_hw 0>; + operating-points-v2 = <&cpu0_opp_table>; + interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>, + <&epss_l3_cl0 MASTER_EPSS_L3_APPS + &epss_l3_cl0 SLAVE_EPSS_L3_SHARED>; l2_1: l2-cache { compatible = "cache"; @@ -93,6 +104,11 @@ cpu2: cpu@200 { capacity-dmips-mhz = <1946>; dynamic-power-coefficient = <507>; qcom,freq-domain = <&cpufreq_hw 2>; + operating-points-v2 = <&cpu2_opp_table>; + interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>, + <&epss_l3_cl0 MASTER_EPSS_L3_APPS + &epss_l3_cl0 SLAVE_EPSS_L3_SHARED>; l2_2: l2-cache { compatible = "cache"; @@ -113,6 +129,11 @@ cpu3: cpu@300 { capacity-dmips-mhz = <1946>; dynamic-power-coefficient = <507>; qcom,freq-domain = <&cpufreq_hw 2>; + operating-points-v2 = <&cpu2_opp_table>; + interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>, + <&epss_l3_cl0 MASTER_EPSS_L3_APPS + &epss_l3_cl0 SLAVE_EPSS_L3_SHARED>; l2_3: l2-cache { compatible = "cache"; @@ -133,6 +154,11 @@ cpu4: cpu@10000 { capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; qcom,freq-domain = <&cpufreq_hw 1>; + operating-points-v2 = <&cpu4_opp_table>; + interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>, + <&epss_l3_cl1 MASTER_EPSS_L3_APPS + &epss_l3_cl1 SLAVE_EPSS_L3_SHARED>; l2_4: l2-cache { compatible = "cache"; @@ -153,6 +179,11 @@ cpu5: cpu@10100 { capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; qcom,freq-domain = <&cpufreq_hw 1>; + operating-points-v2 = <&cpu4_opp_table>; + interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>, + <&epss_l3_cl1 MASTER_EPSS_L3_APPS + &epss_l3_cl1 SLAVE_EPSS_L3_SHARED>; l2_5: l2-cache { compatible = "cache"; @@ -173,6 +204,11 @@ cpu6: cpu@10200 { capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; qcom,freq-domain = <&cpufreq_hw 1>; + operating-points-v2 = <&cpu4_opp_table>; + interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>, + <&epss_l3_cl1 MASTER_EPSS_L3_APPS + &epss_l3_cl1 SLAVE_EPSS_L3_SHARED>; l2_6: l2-cache { compatible = "cache"; @@ -193,6 +229,11 @@ cpu7: cpu@10300 { capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; qcom,freq-domain = <&cpufreq_hw 1>; + operating-points-v2 = <&cpu4_opp_table>; + interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>, + <&epss_l3_cl1 MASTER_EPSS_L3_APPS + &epss_l3_cl1 SLAVE_EPSS_L3_SHARED>; l2_7: l2-cache { compatible = "cache"; @@ -323,6 +364,248 @@ system_sleep: domain-sleep { }; }; + cpu0_opp_table: opp-table-cpu0 { + compatible = "operating-points-v2"; + opp-shared; + + opp-902400000 { + opp-hz = /bits/ 64 <902400000>; + opp-peak-kBps = <(681600 * 4) (921600 * 32)>; + }; + + opp-1017600000 { + opp-hz = /bits/ 64 <1017600000>; + opp-peak-kBps = <(1017600 * 4) (921600 * 32)>; + }; + + opp-1190400000 { + opp-hz = /bits/ 64 <1190400000>; + opp-peak-kBps = <(1708800 * 4) (921600 * 32)>; + }; + + opp-1267200000 { + opp-hz = /bits/ 64 <1267200000>; + opp-peak-kBps = <(2092800 * 4) (998400 * 32)>; + }; + + opp-1344000000 { + opp-hz = /bits/ 64 <1344000000>; + opp-peak-kBps = <(2092800 * 4) (1075200 * 32)>; + }; + + opp-1420800000 { + opp-hz = /bits/ 64 <1420800000>; + opp-peak-kBps = <(2092800 * 4) (1152000 * 32)>; + }; + + opp-1497600000 { + opp-hz = /bits/ 64 <1497600000>; + opp-peak-kBps = <(2092800 * 4) (1228800 * 32)>; + }; + + opp-1574400000 { + opp-hz = /bits/ 64 <1574400000>; + opp-peak-kBps = <(2736000 * 4) (1324800 * 32)>; + }; + + opp-1670400000 { + opp-hz = /bits/ 64 <1670400000>; + opp-peak-kBps = <(2736000 * 4) (1401600 * 32)>; + }; + + opp-1747200000 { + opp-hz = /bits/ 64 <1747200000>; + opp-peak-kBps = <(2736000 * 4) (1401600 * 32)>; + }; + + opp-1824000000 { + opp-hz = /bits/ 64 <1824000000>; + opp-peak-kBps = <(2736000 * 4) (1478400 * 32)>; + }; + + opp-1900800000 { + opp-hz = /bits/ 64 <1900800000>; + opp-peak-kBps = <(2736000 * 4) (1478400 * 32)>; + }; + + opp-1977600000 { + opp-hz = /bits/ 64 <1977600000>; + opp-peak-kBps = <(3196800 * 4) (1555200 * 32)>; + }; + + opp-2054400000 { + opp-hz = /bits/ 64 <2054400000>; + opp-peak-kBps = <(3196800 * 4) (1555200 * 32)>; + }; + + opp-2112000000 { + opp-hz = /bits/ 64 <2112000000>; + opp-peak-kBps = <(3196800 * 4) (1612800 * 32)>; + }; + + }; + + cpu2_opp_table: opp-table-cpu2 { + compatible = "operating-points-v2"; + opp-shared; + + opp-940800000 { + opp-hz = /bits/ 64 <940800000>; + opp-peak-kBps = <(681600 * 4) (921600 * 32)>; + }; + + opp-1094400000 { + opp-hz = /bits/ 64 <1094400000>; + opp-peak-kBps = <(1017600 * 4) (921600 * 32)>; + }; + + opp-1267200000 { + opp-hz = /bits/ 64 <1267200000>; + opp-peak-kBps = <(1708800 * 4) (921600 * 32)>; + }; + + opp-1344000000 { + opp-hz = /bits/ 64 <1344000000>; + opp-peak-kBps = <(2092800 * 4) (998400 * 32)>; + }; + + opp-1420800000 { + opp-hz = /bits/ 64 <1420800000>; + opp-peak-kBps = <(2092800 * 4) (998400 * 32)>; + }; + + opp-1497600000 { + opp-hz = /bits/ 64 <1497600000>; + opp-peak-kBps = <(2092800 * 4) (1075200 * 32)>; + }; + + opp-1574400000 { + opp-hz = /bits/ 64 <1574400000>; + opp-peak-kBps = <(2092800 * 4) (1152000 * 32)>; + }; + + opp-1632000000 { + opp-hz = /bits/ 64 <1632000000>; + opp-peak-kBps = <(2092800 * 4) (1228800 * 32)>; + }; + + opp-1708800000 { + opp-hz = /bits/ 64 <1708800000>; + opp-peak-kBps = <(2736000 * 4) (1324800 * 32)>; + }; + + opp-1804800000 { + opp-hz = /bits/ 64 <1804800000>; + opp-peak-kBps = <(2736000 * 4) (1324800 * 32)>; + }; + + opp-1900800000 { + opp-hz = /bits/ 64 <1900800000>; + opp-peak-kBps = <(2736000 * 4) (1324800 * 32)>; + }; + + opp-1977600000 { + opp-hz = /bits/ 64 <1977600000>; + opp-peak-kBps = <(2736000 * 4) (1401600 * 32)>; + }; + + opp-2054400000 { + opp-hz = /bits/ 64 <2054400000>; + opp-peak-kBps = <(2736000 * 4) (1478400 * 32)>; + }; + + opp-2131200000 { + opp-hz = /bits/ 64 <2131200000>; + opp-peak-kBps = <(3196800 * 4) (1555200 * 32)>; + }; + + opp-2208000000 { + opp-hz = /bits/ 64 <2208000000>; + opp-peak-kBps = <(3196800 * 4) (1555200 * 32)>; + }; + + opp-2284800000 { + opp-hz = /bits/ 64 <2284800000>; + opp-peak-kBps = <(3196800 * 4) (1612800 * 32)>; + }; + + opp-2361600000 { + opp-hz = /bits/ 64 <2361600000>; + opp-peak-kBps = <(3196800 * 4) (1612800 * 32)>; + }; + + }; + + cpu4_opp_table: opp-table-cpu4 { + compatible = "operating-points-v2"; + opp-shared; + + opp-844800000 { + opp-hz = /bits/ 64 <844800000>; + opp-peak-kBps = <(681600 * 4) (921600 * 32)>; + }; + + opp-1113600000 { + opp-hz = /bits/ 64 <1113600000>; + opp-peak-kBps = <(1708800 * 4) (921600 * 32)>; + }; + + opp-1209600000 { + opp-hz = /bits/ 64 <1209600000>; + opp-peak-kBps = <(2092800 * 4) (998400 * 32)>; + }; + + opp-1305600000 { + opp-hz = /bits/ 64 <1305600000>; + opp-peak-kBps = <(2092800 * 4) (1075200 * 32)>; + }; + + opp-1382400000 { + opp-hz = /bits/ 64 <1382400000>; + opp-peak-kBps = <(2092800 * 4) (1152000 * 32)>; + }; + + opp-1459200000 { + opp-hz = /bits/ 64 <1459200000>; + opp-peak-kBps = <(2092800 * 4) (1228800 * 32)>; + }; + + opp-1497600000 { + opp-hz = /bits/ 64 <1497600000>; + opp-peak-kBps = <(2736000 * 4) (1324800 * 32)>; + }; + + opp-1574400000 { + opp-hz = /bits/ 64 <1574400000>; + opp-peak-kBps = <(2736000 * 4) (1324800 * 32)>; + }; + + opp-1651200000 { + opp-hz = /bits/ 64 <1651200000>; + opp-peak-kBps = <(2736000 * 4) (1324800 * 32)>; + }; + + opp-1728000000 { + opp-hz = /bits/ 64 <1728000000>; + opp-peak-kBps = <(2736000 * 4) (1401600 * 32)>; + }; + + opp-1804800000 { + opp-hz = /bits/ 64 <1804800000>; + opp-peak-kBps = <(2736000 * 4) (1478400 * 32)>; + }; + + opp-1881600000 { + opp-hz = /bits/ 64 <1881600000>; + opp-peak-kBps = <(3196800 * 4) (1555200 * 32)>; + }; + + opp-1958400000 { + opp-hz = /bits/ 64 <1958400000>; + opp-peak-kBps = <(3196800 * 4) (1612800 * 32)>; + }; + }; + dummy_eud: dummy-sink { compatible = "arm,coresight-dummy-sink"; @@ -5433,6 +5716,15 @@ rpmhpd_opp_turbo_l1: opp-9 { }; }; + epss_l3_cl0: interconnect@18590000 { + compatible = "qcom,qcs8300-epss-l3", "qcom,sa8775p-epss-l3", + "qcom,epss-l3"; + reg = <0x0 0x18590000 0x0 0x1000>; + clocks = <&rpmhcc RPMH_CXO_CLK>, <&gcc GCC_GPLL0>; + clock-names = "xo", "alternate"; + #interconnect-cells = <1>; + }; + cpufreq_hw: cpufreq@18591000 { compatible = "qcom,qcs8300-cpufreq-epss", "qcom,cpufreq-epss"; reg = <0x0 0x18591000 0x0 0x1000>, @@ -5455,6 +5747,15 @@ cpufreq_hw: cpufreq@18591000 { #freq-domain-cells = <1>; }; + epss_l3_cl1: interconnect@18592000 { + compatible = "qcom,qcs8300-epss-l3", "qcom,sa8775p-epss-l3", + "qcom,epss-l3"; + reg = <0x0 0x18592000 0x0 0x1000>; + clocks = <&rpmhcc RPMH_CXO_CLK>, <&gcc GCC_GPLL0>; + clock-names = "xo", "alternate"; + #interconnect-cells = <1>; + }; + remoteproc_gpdsp: remoteproc@20c00000 { compatible = "qcom,qcs8300-gpdsp-pas", "qcom,sa8775p-gpdsp0-pas"; reg = <0x0 0x20c00000 0x0 0x10000>; From bf258fdaa2bcbafa04bf1ad646e8ed42e13033cb Mon Sep 17 00:00:00 2001 From: George Moussalem Date: Mon, 21 Jul 2025 10:30:46 +0400 Subject: [PATCH 00319/11391] arm64: dts: qcom: ipq5018: add PRNG node PRNG inside of IPQ5018 is already supported, so let's add the node for it. Signed-off-by: George Moussalem Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250721-ipq5018-prng-v1-1-474310e0575d@outlook.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/ipq5018.dtsi b/arch/arm64/boot/dts/qcom/ipq5018.dtsi index e223b087b28b..7363bb6dcd68 100644 --- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi @@ -301,6 +301,14 @@ tsens_s4_p2: s4-p2@254 { }; }; + prng: rng@e3000 { + compatible = "qcom,prng-ee"; + reg = <0x000e3000 0x1000>; + clocks = <&gcc GCC_PRNG_AHB_CLK>; + clock-names = "core"; + status = "disabled"; + }; + tsens: thermal-sensor@4a9000 { compatible = "qcom,ipq5018-tsens", "qcom,tsens-v1"; reg = <0x004a9000 0x1000>, From ed5789ba7c2ce548f01ebbdbd7488dd9cccc4513 Mon Sep 17 00:00:00 2001 From: George Moussalem Date: Mon, 21 Jul 2025 10:23:15 +0400 Subject: [PATCH 00320/11391] arm64: dts: qcom: ipq5018: Add crypto nodes IPQ5018 uses Qualcomm QCE crypto engine v5.1 which is already supported. So let's add the dts nodes for its DMA v1.7.4 and QCE itself. Reviewed-by: Konrad Dybcio Signed-off-by: George Moussalem Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250721-ipq5018-crypto-v3-1-b9cd9b0ef147@outlook.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 30 +++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/ipq5018.dtsi b/arch/arm64/boot/dts/qcom/ipq5018.dtsi index 7363bb6dcd68..08bea072cf11 100644 --- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi @@ -348,6 +348,36 @@ tsens: thermal-sensor@4a9000 { #thermal-sensor-cells = <1>; }; + cryptobam: dma-controller@704000 { + compatible = "qcom,bam-v1.7.4", "qcom,bam-v1.7.0"; + reg = <0x00704000 0x20000>; + interrupts = ; + + clocks = <&gcc GCC_CRYPTO_AHB_CLK>; + clock-names = "bam_clk"; + + #dma-cells = <1>; + qcom,ee = <1>; + qcom,controlled-remotely; + }; + + crypto: crypto@73a000 { + compatible = "qcom,crypto-v5.1"; + reg = <0x0073a000 0x6000>; + + clocks = <&gcc GCC_CRYPTO_AHB_CLK>, + <&gcc GCC_CRYPTO_AXI_CLK>, + <&gcc GCC_CRYPTO_CLK>; + clock-names = "iface", + "bus", + "core"; + + dmas = <&cryptobam 2>, + <&cryptobam 3>; + dma-names = "rx", + "tx"; + }; + tlmm: pinctrl@1000000 { compatible = "qcom,ipq5018-tlmm"; reg = <0x01000000 0x300000>; From c006b249c54441dd8a3a493c7c87158f441f8178 Mon Sep 17 00:00:00 2001 From: George Moussalem Date: Mon, 21 Jul 2025 10:04:35 +0400 Subject: [PATCH 00321/11391] arm64: dts: ipq5018: Add CMN PLL node Add CMN PLL node for enabling output clocks to the networking hardware blocks on IPQ5018 devices. The reference clock of CMN PLL is routed from XO to the CMN PLL through the internal WiFi block. .XO (48 MHZ) --> WiFi (multiplier/divider)--> 96 MHZ to CMN PLL. Reviewed-by: Konrad Dybcio Signed-off-by: George Moussalem Link: https://lore.kernel.org/r/20250721-ipq5018-cmn-pll-v5-1-4cbf3479af65@outlook.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 33 +++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/ipq5018.dtsi b/arch/arm64/boot/dts/qcom/ipq5018.dtsi index 08bea072cf11..fc1054301c03 100644 --- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi @@ -2,12 +2,13 @@ /* * IPQ5018 SoC device tree source * - * Copyright (c) 2023 The Linux Foundation. All rights reserved. + * Copyright (c) 2023-2025 The Linux Foundation. All rights reserved. */ #include -#include #include +#include +#include #include #include @@ -29,6 +30,14 @@ gephy_tx_clk: gephy-tx-clk { #clock-cells = <0>; }; + ref_96mhz_clk: ref-96mhz-clk { + compatible = "fixed-factor-clock"; + clocks = <&xo_clk>; + #clock-cells = <0>; + clock-div = <1>; + clock-mult = <2>; + }; + sleep_clk: sleep-clk { compatible = "fixed-clock"; #clock-cells = <0>; @@ -38,6 +47,12 @@ xo_board_clk: xo-board-clk { compatible = "fixed-clock"; #clock-cells = <0>; }; + + xo_clk: xo-clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <48000000>; + }; }; cpus { @@ -229,6 +244,20 @@ mdio1: mdio@90000 { status = "disabled"; }; + cmn_pll: clock-controller@9b000 { + compatible = "qcom,ipq5018-cmn-pll"; + reg = <0x0009b000 0x800>; + clocks = <&ref_96mhz_clk>, + <&gcc GCC_CMN_BLK_AHB_CLK>, + <&gcc GCC_CMN_BLK_SYS_CLK>; + clock-names = "ref", + "ahb", + "sys"; + #clock-cells = <1>; + assigned-clocks = <&cmn_pll IPQ5018_CMN_PLL_CLK>; + assigned-clock-rates-u64 = /bits/ 64 <9600000000>; + }; + qfprom: qfprom@a0000 { compatible = "qcom,ipq5018-qfprom", "qcom,qfprom"; reg = <0x000a0000 0x1000>; From 5ca3d42384a66bcb66f91d75da16ec9e9f053aab Mon Sep 17 00:00:00 2001 From: George Moussalem Date: Mon, 21 Jul 2025 10:04:36 +0400 Subject: [PATCH 00322/11391] arm64: dts: qcom: Update IPQ5018 xo_board_clk to use fixed factor clock The xo_board_clk is fixed to 24 MHZ, which is routed from WiFi output clock 96 MHZ (also being the reference clock of CMN PLL) divided by 4 to the analog block routing channel. Update the xo_board_clk nodes in the board DTS files to use clock-div/clock-mult accordingly. Reviewed-by: Konrad Dybcio Signed-off-by: George Moussalem Link: https://lore.kernel.org/r/20250721-ipq5018-cmn-pll-v5-2-4cbf3479af65@outlook.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/ipq5018-rdp432-c2.dts | 3 ++- arch/arm64/boot/dts/qcom/ipq5018-tplink-archer-ax55-v1.dts | 3 ++- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/ipq5018-rdp432-c2.dts b/arch/arm64/boot/dts/qcom/ipq5018-rdp432-c2.dts index 43def95e9275..df3cbb7c79c4 100644 --- a/arch/arm64/boot/dts/qcom/ipq5018-rdp432-c2.dts +++ b/arch/arm64/boot/dts/qcom/ipq5018-rdp432-c2.dts @@ -120,5 +120,6 @@ &usbphy0 { }; &xo_board_clk { - clock-frequency = <24000000>; + clock-div = <4>; + clock-mult = <1>; }; diff --git a/arch/arm64/boot/dts/qcom/ipq5018-tplink-archer-ax55-v1.dts b/arch/arm64/boot/dts/qcom/ipq5018-tplink-archer-ax55-v1.dts index 5bb021cb29cd..7a25af57749c 100644 --- a/arch/arm64/boot/dts/qcom/ipq5018-tplink-archer-ax55-v1.dts +++ b/arch/arm64/boot/dts/qcom/ipq5018-tplink-archer-ax55-v1.dts @@ -124,5 +124,6 @@ uart_pins: uart-pins-state { }; &xo_board_clk { - clock-frequency = <24000000>; + clock-div = <4>; + clock-mult = <1>; }; diff --git a/arch/arm64/boot/dts/qcom/ipq5018.dtsi b/arch/arm64/boot/dts/qcom/ipq5018.dtsi index fc1054301c03..4ddb56d63f8f 100644 --- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi @@ -44,7 +44,8 @@ sleep_clk: sleep-clk { }; xo_board_clk: xo-board-clk { - compatible = "fixed-clock"; + compatible = "fixed-factor-clock"; + clocks = <&ref_96mhz_clk>; #clock-cells = <0>; }; From 84f3849d0526b22589dd5b4a5634ed4235a6ccf9 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Thu, 17 Jul 2025 16:10:57 +0530 Subject: [PATCH 00323/11391] arm64: dts: qcom: qcs6490-rb3gen2: Add missing clkreq pinctrl property Add the missing clkreq pinctrl entry to the PCIe1 node. This ensures proper configuration of the CLKREQ# signal, which is needed for proper functioning of PCIe ASPM. Signed-off-by: Krishna Chaitanya Chundru Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250717-clkreq-v1-1-5a82c7e8e891@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts index 5fbcd48f2e2d..8f15be633946 100644 --- a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts +++ b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts @@ -811,7 +811,7 @@ &mdss_edp_phy { &pcie1 { perst-gpios = <&tlmm 2 GPIO_ACTIVE_LOW>; - pinctrl-0 = <&pcie1_reset_n>, <&pcie1_wake_n>; + pinctrl-0 = <&pcie1_reset_n>, <&pcie1_wake_n>, <&pcie1_clkreq_n>; pinctrl-names = "default"; iommu-map = <0x0 &apps_smmu 0x1c80 0x1>, From fba47ba8c8a8ffa9d8ad1836396837a998bb5153 Mon Sep 17 00:00:00 2001 From: Ziyue Zhang Date: Thu, 17 Jul 2025 15:27:46 +0800 Subject: [PATCH 00324/11391] arm64: dts: qcom: qcs615: Set LDO12A regulator to HPM to avoid boot hang MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On certain platforms (e.g., QCS615), consumers of LDO12A—such as PCIe, UFS, and eMMC—may draw more than 10mA of current during boot. This can exceed the regulator's limit in Low Power Mode (LPM), triggering current limit protection and causing the system to hang. To address this, there are two possible approaches: a) Set the regulator's initial mode to High Performance Mode (HPM) in the device tree. b) Keep the default LPM setting and have each consumer driver explicitly set its current load. Since some regulators are shared among multiple consumers, and setting the current must be coordinated across all of them, we will initially adopt option a by setting the regulator to HPM. We can later migrate to option b when the timing is appropriate and all consumer drivers are ready. Signed-off-by: Ziyue Zhang Signed-off-by: Tingguo Cheng Link: https://lore.kernel.org/r/20250717072746.987298-1-quic_ziyuzhan@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/qcs615-ride.dts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/qcs615-ride.dts b/arch/arm64/boot/dts/qcom/qcs615-ride.dts index 36978fdfe3dd..59582d3dc4c4 100644 --- a/arch/arm64/boot/dts/qcom/qcs615-ride.dts +++ b/arch/arm64/boot/dts/qcom/qcs615-ride.dts @@ -246,10 +246,7 @@ vreg_l12a: ldo12 { regulator-name = "vreg_l12a"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1890000>; - regulator-initial-mode = ; - regulator-allow-set-load; - regulator-allowed-modes = ; + regulator-initial-mode = ; }; vreg_l13a: ldo13 { From a6c4d92fcc74b4402d1ecdf6f4a7304a37a69ada Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Thu, 17 Jul 2025 08:54:46 +0200 Subject: [PATCH 00325/11391] dt-bindings: soc: qcom,rpmh-rsc: Remove double colon from description No double colon is necessary in the description. Fix it. Reported-by: Rob Herring Closes: https://lore.kernel.org/lkml/20250625150458.GA1182597-robh@kernel.org/ Signed-off-by: Luca Weiss Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250717-bindings-double-colon-v1-3-c04abc180fcd@fairphone.com Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/soc/qcom/qcom,rpmh-rsc.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,rpmh-rsc.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,rpmh-rsc.yaml index 036562eb5140..26d9bc773ec5 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,rpmh-rsc.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,rpmh-rsc.yaml @@ -28,7 +28,7 @@ description: | SLEEP - Triggered by F/W WAKE - Triggered by F/W CONTROL - Triggered by F/W - See also:: + See also: The order in which they are described in the DT, should match the hardware configuration. From 474aa14da0e160f2f3fb002b64b8363ae91f9590 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 16 Jul 2025 18:24:13 +0200 Subject: [PATCH 00326/11391] dt-bindings: arm: qcom-soc: Document new Milos and Glymur SoCs Extend the schema enforcing correct SoC-block naming to cover Milos (compatibles already accepted by some maintainers for next release) and Glymur (posted on mailing lists [1]) SoCs. Link: https://lore.kernel.org/linux-devicetree/20250716152017.4070029-1-pankaj.patil@oss.qualcomm.com/ [1] Signed-off-by: Krzysztof Kozlowski Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250716162412.27471-2-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/arm/qcom-soc.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/arm/qcom-soc.yaml b/Documentation/devicetree/bindings/arm/qcom-soc.yaml index a77d68dcad4e..27261039d56f 100644 --- a/Documentation/devicetree/bindings/arm/qcom-soc.yaml +++ b/Documentation/devicetree/bindings/arm/qcom-soc.yaml @@ -23,7 +23,9 @@ description: | select: properties: compatible: - pattern: "^qcom,.*(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sar|sc|sd[amx]|sm|x1[ep])[0-9]+.*$" + oneOf: + - pattern: "^qcom,.*(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sar|sc|sd[amx]|sm|x1[ep])[0-9]+.*$" + - pattern: "^qcom,.*(glymur|milos).*$" required: - compatible @@ -34,6 +36,7 @@ properties: - pattern: "^qcom,(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm|x1[ep])[0-9]+(pro)?-.*$" - pattern: "^qcom,sar[0-9]+[a-z]?-.*$" - pattern: "^qcom,(sa|sc)8[0-9]+[a-z][a-z]?-.*$" + - pattern: "^qcom,(glymur|milos)-.*$" # Legacy namings - variations of existing patterns/compatibles are OK, # but do not add completely new entries to these: From 92d05aceadbd799b416ad08bf2f741a096bf3e56 Mon Sep 17 00:00:00 2001 From: Arseniy Velikanov Date: Wed, 16 Jul 2025 18:10:39 +0400 Subject: [PATCH 00327/11391] arm64: dts: qcom: sm8250-xiaomi-pipa: Drop nonexistent pm8009 pmic PM8009 was erroneously added since this device doesn't actually have it. It triggers a big critical error at boot, so we're drop it. Fixes: 264beb3cbd0d ("arm64: dts: qcom: sm8250-xiaomi-pipa: Add initial device tree") Reviewed-by: Luka Panio Signed-off-by: Arseniy Velikanov Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250716141041.24507-1-me@adomerle.pw Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/sm8250-xiaomi-pipa.dts | 58 ------------------- 1 file changed, 58 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8250-xiaomi-pipa.dts b/arch/arm64/boot/dts/qcom/sm8250-xiaomi-pipa.dts index 668078ea4f04..a4c8b778ae46 100644 --- a/arch/arm64/boot/dts/qcom/sm8250-xiaomi-pipa.dts +++ b/arch/arm64/boot/dts/qcom/sm8250-xiaomi-pipa.dts @@ -12,7 +12,6 @@ #include "pm8150.dtsi" #include "pm8150b.dtsi" #include "pm8150l.dtsi" -#include "pm8009.dtsi" /* * Delete following upstream (sm8250.dtsi) reserved @@ -406,63 +405,6 @@ vreg_l11c_3p0: ldo11 { regulator-initial-mode = ; }; }; - - regulators-2 { - compatible = "qcom,pm8009-rpmh-regulators"; - qcom,pmic-id = "f"; - - vdd-s1-supply = <&vph_pwr>; - vdd-s2-supply = <&vreg_bob>; - vdd-l2-supply = <&vreg_s8c_1p35>; - vdd-l5-l6-supply = <&vreg_bob>; - vdd-l7-supply = <&vreg_s4a_1p8>; - - vreg_s1f_1p2: smps1 { - regulator-name = "vreg_s1f_1p2"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1300000>; - regulator-initial-mode = ; - }; - - vreg_s2f_0p5: smps2 { - regulator-name = "vreg_s2f_0p5"; - regulator-min-microvolt = <512000>; - regulator-max-microvolt = <1100000>; - regulator-initial-mode = ; - }; - - /* L1 is unused. */ - - vreg_l2f_1p3: ldo2 { - regulator-name = "vreg_l2f_1p3"; - regulator-min-microvolt = <1056000>; - regulator-max-microvolt = <1200000>; - regulator-initial-mode = ; - }; - - /* L3 & L4 are unused. */ - - vreg_l5f_2p8: ldo5 { - regulator-name = "vreg_l5f_2p85"; - regulator-min-microvolt = <2800000>; - regulator-max-microvolt = <3000000>; - regulator-initial-mode = ; - }; - - vreg_l6f_2p8: ldo6 { - regulator-name = "vreg_l6f_2p8"; - regulator-min-microvolt = <2800000>; - regulator-max-microvolt = <3000000>; - regulator-initial-mode = ; - }; - - vreg_l7f_1p8: ldo7 { - regulator-name = "vreg_l7f_1p8"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-initial-mode = ; - }; - }; }; &cdsp { From 56197c8737b88d300cda97cd71b64b8a93cf6f70 Mon Sep 17 00:00:00 2001 From: Arseniy Velikanov Date: Wed, 16 Jul 2025 18:10:40 +0400 Subject: [PATCH 00328/11391] arm64: dts: qcom: sm8250-xiaomi-pipa: Drop unused bq27z561 It looks like the fuel gauge is not connected to the battery, it reports nonsense info. Downstream kernel uses pmic fg. Reviewed-by: Luka Panio Signed-off-by: Arseniy Velikanov Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250716141041.24507-2-me@adomerle.pw Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/sm8250-xiaomi-pipa.dts | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8250-xiaomi-pipa.dts b/arch/arm64/boot/dts/qcom/sm8250-xiaomi-pipa.dts index a4c8b778ae46..c2d0f0254776 100644 --- a/arch/arm64/boot/dts/qcom/sm8250-xiaomi-pipa.dts +++ b/arch/arm64/boot/dts/qcom/sm8250-xiaomi-pipa.dts @@ -437,17 +437,6 @@ zap-shader { }; }; -&i2c0 { - clock-frequency = <400000>; - status = "okay"; - - fuel-gauge@55 { - compatible = "ti,bq27z561"; - reg = <0x55>; - monitored-battery = <&battery_r>; - }; -}; - &i2c11 { clock-frequency = <400000>; status = "okay"; @@ -465,17 +454,6 @@ backlight: backlight@11 { }; }; -&i2c13 { - clock-frequency = <400000>; - status = "okay"; - - fuel-gauge@55 { - compatible = "ti,bq27z561"; - reg = <0x55>; - monitored-battery = <&battery_l>; - }; -}; - &pcie0 { status = "okay"; }; From e2ec684f82536d62e0d60663ed3689455a9b0b9f Mon Sep 17 00:00:00 2001 From: Arseniy Velikanov Date: Wed, 16 Jul 2025 18:10:41 +0400 Subject: [PATCH 00329/11391] arm64: dts: sm8250-xiaomi-pipa: Update battery info Added max design microvolt. Merged battery info into one node, since pmic fuel-gauge uses mixed info about dual-cell battery. Reviewed-by: Luka Panio Signed-off-by: Arseniy Velikanov Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250716141041.24507-3-me@adomerle.pw Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8250-xiaomi-pipa.dts | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8250-xiaomi-pipa.dts b/arch/arm64/boot/dts/qcom/sm8250-xiaomi-pipa.dts index c2d0f0254776..4ad24974c09f 100644 --- a/arch/arm64/boot/dts/qcom/sm8250-xiaomi-pipa.dts +++ b/arch/arm64/boot/dts/qcom/sm8250-xiaomi-pipa.dts @@ -49,18 +49,12 @@ framebuffer: framebuffer@9c000000 { }; }; - battery_l: battery-l { + battery: battery { compatible = "simple-battery"; - voltage-min-design-microvolt = <3870000>; - energy-full-design-microwatt-hours = <16700000>; - charge-full-design-microamp-hours = <4420000>; - }; - - battery_r: battery-r { - compatible = "simple-battery"; - voltage-min-design-microvolt = <3870000>; - energy-full-design-microwatt-hours = <16700000>; - charge-full-design-microamp-hours = <4420000>; + charge-full-design-microamp-hours = <8840000>; + energy-full-design-microwatt-hours = <34300000>; + voltage-min-design-microvolt = <3400000>; + voltage-max-design-microvolt = <4370000>; }; bl_vddpos_5p5: bl-vddpos-regulator { From bc6776fab8455762089274d469a67d104e3b96ae Mon Sep 17 00:00:00 2001 From: Shivnandan Kumar Date: Wed, 16 Jul 2025 14:25:47 +0200 Subject: [PATCH 00330/11391] arm64: dts: qcom: sm8750: Add BWMONs Add the CPU BWMONs for SM8750 SoCs. Notably, the one related to cluster0 requires that it's mapped with the nE memory attribute. This is specific to a single instance, on this platform only and should not be mimicked elsewhere. Signed-off-by: Shivnandan Kumar [konrad: add nonposted-mmio where necessary, re-sort nodes] Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250716-8750_cpubwmon-v4-2-12212098e90f@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8750.dtsi | 76 ++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8750.dtsi b/arch/arm64/boot/dts/qcom/sm8750.dtsi index 4643705021c6..79ca262f5811 100644 --- a/arch/arm64/boot/dts/qcom/sm8750.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8750.dtsi @@ -3617,6 +3617,82 @@ frame@1680d000 { }; }; + /* cluster0 */ + pmu@240b3400 { + compatible = "qcom,sm8750-cpu-bwmon", "qcom,sdm845-bwmon"; + reg = <0x0 0x240b3400 0x0 0x600>; + + interrupts = ; + + interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>; + + operating-points-v2 = <&cpu_bwmon_opp_table>; + + nonposted-mmio; + + cpu_bwmon_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-0 { + opp-peak-kBps = <800000>; + }; + + opp-1 { + opp-peak-kBps = <2188000>; + }; + + opp-2 { + opp-peak-kBps = <5414400>; + }; + + opp-3 { + opp-peak-kBps = <6220800>; + }; + + opp-4 { + opp-peak-kBps = <6835200>; + }; + + opp-5 { + opp-peak-kBps = <8371200>; + }; + + opp-6 { + opp-peak-kBps = <10944000>; + }; + + opp-7 { + opp-peak-kBps = <12748800>; + }; + + opp-8 { + opp-peak-kBps = <14745600>; + }; + + opp-9 { + opp-peak-kBps = <16896000>; + }; + + opp-10 { + opp-peak-kBps = <19046400>; + }; + }; + }; + + /* cluster1 */ + pmu@240b7400 { + compatible = "qcom,sm8750-cpu-bwmon", "qcom,sdm845-bwmon"; + reg = <0x0 0x240b7400 0x0 0x600>; + + interrupts = ; + + interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>; + + operating-points-v2 = <&cpu_bwmon_opp_table>; + }; + gem_noc: interconnect@24100000 { compatible = "qcom,sm8750-gem-noc"; reg = <0x0 0x24100000 0x0 0x14b080>; From e5bc887413e513a2cb658370dd09fa9e1702fb3b Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Wed, 6 Aug 2025 17:17:07 -0400 Subject: [PATCH 00331/11391] lsm: use lsm_blob_alloc() in lsm_bdev_alloc() Convert the lsm_bdev_alloc() function to use the lsm_blob_alloc() helper like all of the other LSM security blob allocators. Reviewed-by: Casey Schaufler Acked-by: Serge Hallyn Signed-off-by: Paul Moore --- security/security.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/security/security.c b/security/security.c index ad163f06bf7a..a88ebfca3224 100644 --- a/security/security.c +++ b/security/security.c @@ -823,16 +823,8 @@ static int lsm_msg_msg_alloc(struct msg_msg *mp) */ static int lsm_bdev_alloc(struct block_device *bdev) { - if (blob_sizes.lbs_bdev == 0) { - bdev->bd_security = NULL; - return 0; - } - - bdev->bd_security = kzalloc(blob_sizes.lbs_bdev, GFP_KERNEL); - if (!bdev->bd_security) - return -ENOMEM; - - return 0; + return lsm_blob_alloc(&bdev->bd_security, blob_sizes.lbs_bdev, + GFP_KERNEL); } /** From 5816bf4273edb32716a88c796e0b04f0e12962eb Mon Sep 17 00:00:00 2001 From: Blaise Boscaccy Date: Tue, 22 Jul 2025 14:21:34 -0700 Subject: [PATCH 00332/11391] lsm,selinux: Add LSM blob support for BPF objects This patch introduces LSM blob support for BPF maps, programs, and tokens to enable LSM stacking and multiplexing of LSM modules that govern BPF objects. Additionally, the existing BPF hooks used by SELinux have been updated to utilize the new blob infrastructure, removing the assumption of exclusive ownership of the security pointer. Signed-off-by: Blaise Boscaccy [PM: dropped local variable init, style fixes] Signed-off-by: Paul Moore --- include/linux/lsm_hooks.h | 3 ++ security/security.c | 86 +++++++++++++++++++++++++++++-- security/selinux/hooks.c | 56 ++++---------------- security/selinux/include/objsec.h | 20 +++++++ 4 files changed, 116 insertions(+), 49 deletions(-) diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 090d1d3e19fe..79ec5a2bdcca 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -116,6 +116,9 @@ struct lsm_blob_sizes { int lbs_xattr_count; /* number of xattr slots in new_xattrs array */ int lbs_tun_dev; int lbs_bdev; + int lbs_bpf_map; + int lbs_bpf_prog; + int lbs_bpf_token; }; /* diff --git a/security/security.c b/security/security.c index a88ebfca3224..ca126b02d2fe 100644 --- a/security/security.c +++ b/security/security.c @@ -283,6 +283,9 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed) lsm_set_blob_size(&needed->lbs_xattr_count, &blob_sizes.lbs_xattr_count); lsm_set_blob_size(&needed->lbs_bdev, &blob_sizes.lbs_bdev); + lsm_set_blob_size(&needed->lbs_bpf_map, &blob_sizes.lbs_bpf_map); + lsm_set_blob_size(&needed->lbs_bpf_prog, &blob_sizes.lbs_bpf_prog); + lsm_set_blob_size(&needed->lbs_bpf_token, &blob_sizes.lbs_bpf_token); } /* Prepare LSM for initialization. */ @@ -480,6 +483,9 @@ static void __init ordered_lsm_init(void) init_debug("tun device blob size = %d\n", blob_sizes.lbs_tun_dev); init_debug("xattr slots = %d\n", blob_sizes.lbs_xattr_count); init_debug("bdev blob size = %d\n", blob_sizes.lbs_bdev); + init_debug("bpf map blob size = %d\n", blob_sizes.lbs_bpf_map); + init_debug("bpf prog blob size = %d\n", blob_sizes.lbs_bpf_prog); + init_debug("bpf token blob size = %d\n", blob_sizes.lbs_bpf_token); /* * Create any kmem_caches needed for blobs @@ -827,6 +833,47 @@ static int lsm_bdev_alloc(struct block_device *bdev) GFP_KERNEL); } +#ifdef CONFIG_BPF_SYSCALL +/** + * lsm_bpf_map_alloc - allocate a composite bpf_map blob + * @map: the bpf_map that needs a blob + * + * Allocate the bpf_map blob for all the modules + * + * Returns 0, or -ENOMEM if memory can't be allocated. + */ +static int lsm_bpf_map_alloc(struct bpf_map *map) +{ + return lsm_blob_alloc(&map->security, blob_sizes.lbs_bpf_map, GFP_KERNEL); +} + +/** + * lsm_bpf_prog_alloc - allocate a composite bpf_prog blob + * @prog: the bpf_prog that needs a blob + * + * Allocate the bpf_prog blob for all the modules + * + * Returns 0, or -ENOMEM if memory can't be allocated. + */ +static int lsm_bpf_prog_alloc(struct bpf_prog *prog) +{ + return lsm_blob_alloc(&prog->aux->security, blob_sizes.lbs_bpf_prog, GFP_KERNEL); +} + +/** + * lsm_bpf_token_alloc - allocate a composite bpf_token blob + * @token: the bpf_token that needs a blob + * + * Allocate the bpf_token blob for all the modules + * + * Returns 0, or -ENOMEM if memory can't be allocated. + */ +static int lsm_bpf_token_alloc(struct bpf_token *token) +{ + return lsm_blob_alloc(&token->security, blob_sizes.lbs_bpf_token, GFP_KERNEL); +} +#endif /* CONFIG_BPF_SYSCALL */ + /** * lsm_early_task - during initialization allocate a composite task blob * @task: the task that needs a blob @@ -5706,7 +5753,16 @@ int security_bpf_prog(struct bpf_prog *prog) int security_bpf_map_create(struct bpf_map *map, union bpf_attr *attr, struct bpf_token *token, bool kernel) { - return call_int_hook(bpf_map_create, map, attr, token, kernel); + int rc; + + rc = lsm_bpf_map_alloc(map); + if (unlikely(rc)) + return rc; + + rc = call_int_hook(bpf_map_create, map, attr, token, kernel); + if (unlikely(rc)) + security_bpf_map_free(map); + return rc; } /** @@ -5725,7 +5781,16 @@ int security_bpf_map_create(struct bpf_map *map, union bpf_attr *attr, int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, struct bpf_token *token, bool kernel) { - return call_int_hook(bpf_prog_load, prog, attr, token, kernel); + int rc; + + rc = lsm_bpf_prog_alloc(prog); + if (unlikely(rc)) + return rc; + + rc = call_int_hook(bpf_prog_load, prog, attr, token, kernel); + if (unlikely(rc)) + security_bpf_prog_free(prog); + return rc; } /** @@ -5742,7 +5807,16 @@ int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, int security_bpf_token_create(struct bpf_token *token, union bpf_attr *attr, const struct path *path) { - return call_int_hook(bpf_token_create, token, attr, path); + int rc; + + rc = lsm_bpf_token_alloc(token); + if (unlikely(rc)) + return rc; + + rc = call_int_hook(bpf_token_create, token, attr, path); + if (unlikely(rc)) + security_bpf_token_free(token); + return rc; } /** @@ -5786,6 +5860,8 @@ int security_bpf_token_capable(const struct bpf_token *token, int cap) void security_bpf_map_free(struct bpf_map *map) { call_void_hook(bpf_map_free, map); + kfree(map->security); + map->security = NULL; } /** @@ -5797,6 +5873,8 @@ void security_bpf_map_free(struct bpf_map *map) void security_bpf_prog_free(struct bpf_prog *prog) { call_void_hook(bpf_prog_free, prog); + kfree(prog->aux->security); + prog->aux->security = NULL; } /** @@ -5808,6 +5886,8 @@ void security_bpf_prog_free(struct bpf_prog *prog) void security_bpf_token_free(struct bpf_token *token) { call_void_hook(bpf_token_free, token); + kfree(token->security); + token->security = NULL; } #endif /* CONFIG_BPF_SYSCALL */ diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index c95a5874bf7d..4da5e792b42e 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -7062,14 +7062,14 @@ static int bpf_fd_pass(const struct file *file, u32 sid) if (file->f_op == &bpf_map_fops) { map = file->private_data; - bpfsec = map->security; + bpfsec = selinux_bpf_map_security(map); ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF, bpf_map_fmode_to_av(file->f_mode), NULL); if (ret) return ret; } else if (file->f_op == &bpf_prog_fops) { prog = file->private_data; - bpfsec = prog->aux->security; + bpfsec = selinux_bpf_prog_security(prog); ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF, BPF__PROG_RUN, NULL); if (ret) @@ -7083,7 +7083,7 @@ static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode) u32 sid = current_sid(); struct bpf_security_struct *bpfsec; - bpfsec = map->security; + bpfsec = selinux_bpf_map_security(map); return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF, bpf_map_fmode_to_av(fmode), NULL); } @@ -7093,7 +7093,7 @@ static int selinux_bpf_prog(struct bpf_prog *prog) u32 sid = current_sid(); struct bpf_security_struct *bpfsec; - bpfsec = prog->aux->security; + bpfsec = selinux_bpf_prog_security(prog); return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF, BPF__PROG_RUN, NULL); } @@ -7103,69 +7103,33 @@ static int selinux_bpf_map_create(struct bpf_map *map, union bpf_attr *attr, { struct bpf_security_struct *bpfsec; - bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL); - if (!bpfsec) - return -ENOMEM; - + bpfsec = selinux_bpf_map_security(map); bpfsec->sid = current_sid(); - map->security = bpfsec; return 0; } -static void selinux_bpf_map_free(struct bpf_map *map) -{ - struct bpf_security_struct *bpfsec = map->security; - - map->security = NULL; - kfree(bpfsec); -} - static int selinux_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, struct bpf_token *token, bool kernel) { struct bpf_security_struct *bpfsec; - bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL); - if (!bpfsec) - return -ENOMEM; - + bpfsec = selinux_bpf_prog_security(prog); bpfsec->sid = current_sid(); - prog->aux->security = bpfsec; return 0; } -static void selinux_bpf_prog_free(struct bpf_prog *prog) -{ - struct bpf_security_struct *bpfsec = prog->aux->security; - - prog->aux->security = NULL; - kfree(bpfsec); -} - static int selinux_bpf_token_create(struct bpf_token *token, union bpf_attr *attr, const struct path *path) { struct bpf_security_struct *bpfsec; - bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL); - if (!bpfsec) - return -ENOMEM; - + bpfsec = selinux_bpf_token_security(token); bpfsec->sid = current_sid(); - token->security = bpfsec; return 0; } - -static void selinux_bpf_token_free(struct bpf_token *token) -{ - struct bpf_security_struct *bpfsec = token->security; - - token->security = NULL; - kfree(bpfsec); -} #endif struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = { @@ -7183,6 +7147,9 @@ struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = { .lbs_xattr_count = SELINUX_INODE_INIT_XATTRS, .lbs_tun_dev = sizeof(struct tun_security_struct), .lbs_ib = sizeof(struct ib_security_struct), + .lbs_bpf_map = sizeof(struct bpf_security_struct), + .lbs_bpf_prog = sizeof(struct bpf_security_struct), + .lbs_bpf_token = sizeof(struct bpf_security_struct), }; #ifdef CONFIG_PERF_EVENTS @@ -7536,9 +7503,6 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = { LSM_HOOK_INIT(bpf, selinux_bpf), LSM_HOOK_INIT(bpf_map, selinux_bpf_map), LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog), - LSM_HOOK_INIT(bpf_map_free, selinux_bpf_map_free), - LSM_HOOK_INIT(bpf_prog_free, selinux_bpf_prog_free), - LSM_HOOK_INIT(bpf_token_free, selinux_bpf_token_free), #endif #ifdef CONFIG_PERF_EVENTS diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 1d7ac59015a1..2d5139c6d45b 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -26,6 +26,7 @@ #include #include #include +#include #include "flask.h" #include "avc.h" @@ -245,4 +246,23 @@ selinux_perf_event(void *perf_event) return perf_event + selinux_blob_sizes.lbs_perf_event; } +#ifdef CONFIG_BPF_SYSCALL +static inline struct bpf_security_struct * +selinux_bpf_map_security(struct bpf_map *map) +{ + return map->security + selinux_blob_sizes.lbs_bpf_map; +} + +static inline struct bpf_security_struct * +selinux_bpf_prog_security(struct bpf_prog *prog) +{ + return prog->aux->security + selinux_blob_sizes.lbs_bpf_prog; +} + +static inline struct bpf_security_struct * +selinux_bpf_token_security(struct bpf_token *token) +{ + return token->security + selinux_blob_sizes.lbs_bpf_token; +} +#endif /* CONFIG_BPF_SYSCALL */ #endif /* _SELINUX_OBJSEC_H_ */ From 5e4ca587f56319c3c9800b9d1a97443b9c364a15 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Wed, 16 Jul 2025 12:16:07 +0200 Subject: [PATCH 00333/11391] arm64: dts: qcom: Remove sdm845-cheza boards Cheza was a prototype board, used mainly by the ChromeOS folks, whose former efforts on making linux-arm-msm better we greatly appreciate. There are close to zero known-working devices at this point in time (see the link below) and it was never productized. Remove it to ease maintenance burden. Link: https://lore.kernel.org/linux-arm-msm/5567e441-055d-443a-b117-ec16b53dc059@oss.qualcomm.com/ Signed-off-by: Konrad Dybcio Reviewed-by: Krzysztof Kozlowski Reviewed-by: Douglas Anderson Link: https://lore.kernel.org/r/20250716-topic-goodnight_cheza-v2-1-6fa8d3261813@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- MAINTAINERS | 1 - arch/arm64/boot/dts/qcom/Makefile | 3 - arch/arm64/boot/dts/qcom/sdm845-cheza-r1.dts | 238 ---- arch/arm64/boot/dts/qcom/sdm845-cheza-r2.dts | 238 ---- arch/arm64/boot/dts/qcom/sdm845-cheza-r3.dts | 174 --- arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi | 1330 ------------------ 6 files changed, 1984 deletions(-) delete mode 100644 arch/arm64/boot/dts/qcom/sdm845-cheza-r1.dts delete mode 100644 arch/arm64/boot/dts/qcom/sdm845-cheza-r2.dts delete mode 100644 arch/arm64/boot/dts/qcom/sdm845-cheza-r3.dts delete mode 100644 arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi diff --git a/MAINTAINERS b/MAINTAINERS index fe168477caa4..9a06a729af0c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3109,7 +3109,6 @@ ARM/QUALCOMM CHROMEBOOK SUPPORT R: cros-qcom-dts-watchers@chromium.org F: arch/arm64/boot/dts/qcom/sc7180* F: arch/arm64/boot/dts/qcom/sc7280* -F: arch/arm64/boot/dts/qcom/sdm845-cheza* ARM/QUALCOMM MAILING LIST L: linux-arm-msm@vger.kernel.org diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index dcc0f6382f51..94a84770b080 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -232,9 +232,6 @@ dtb-$(CONFIG_ARCH_QCOM) += sdm632-motorola-ocean.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm636-sony-xperia-ganges-mermaid.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm660-xiaomi-lavender.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm670-google-sargo.dtb -dtb-$(CONFIG_ARCH_QCOM) += sdm845-cheza-r1.dtb -dtb-$(CONFIG_ARCH_QCOM) += sdm845-cheza-r2.dtb -dtb-$(CONFIG_ARCH_QCOM) += sdm845-cheza-r3.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm845-db845c.dtb sdm845-db845c-navigation-mezzanine-dtbs := sdm845-db845c.dtb sdm845-db845c-navigation-mezzanine.dtbo diff --git a/arch/arm64/boot/dts/qcom/sdm845-cheza-r1.dts b/arch/arm64/boot/dts/qcom/sdm845-cheza-r1.dts deleted file mode 100644 index bd7c25bb8d35..000000000000 --- a/arch/arm64/boot/dts/qcom/sdm845-cheza-r1.dts +++ /dev/null @@ -1,238 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -/* - * Google Cheza board device tree source - * - * Copyright 2018 Google LLC. - */ - -/dts-v1/; - -#include "sdm845-cheza.dtsi" - -/ { - model = "Google Cheza (rev1)"; - compatible = "google,cheza-rev1", "qcom,sdm845"; - - /* - * FIXED REGULATORS (not in sdm845-cheza.dtsi) - parents above children - */ - - /* - * NOTE: Technically pp3500_a is not the exact same signal as - * pp3500_a_vbob (there's a load switch between them and the EC can - * control pp3500_a via "en_pp3300_a"), but from the AP's point of - * view they are the same. - */ - pp3500_a: - pp3500_a_vbob: pp3500-a-vbob-regulator { - compatible = "regulator-fixed"; - regulator-name = "vreg_bob"; - - /* - * Comes on automatically when pp5000_ldo comes on, which - * comes on automatically when ppvar_sys comes on - */ - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <3500000>; - regulator-max-microvolt = <3500000>; - - vin-supply = <&ppvar_sys>; - }; - - pp3300_dx_edp: pp3300-dx-edp-regulator { - /* Yes, it's really 3.5 despite the name of the signal */ - regulator-min-microvolt = <3500000>; - regulator-max-microvolt = <3500000>; - - vin-supply = <&pp3500_a>; - }; -}; - -/* FIXED REGULATOR OVERRIDES (modifications to sdm845-cheza.dtsi) */ - -/* - * L19 and L28 technically go to 3.3V, but most boards have old AOP firmware - * that limits them to 3.0, and trying to run at 3.3V with that old firmware - * prevents the system from booting. - */ -&src_pp3000_l19a { - regulator-min-microvolt = <3008000>; - regulator-max-microvolt = <3008000>; -}; - -&src_pp3300_l22a { - /delete-property/regulator-boot-on; - /delete-property/regulator-always-on; -}; - -&src_pp3300_l28a { - regulator-min-microvolt = <3008000>; - regulator-max-microvolt = <3008000>; -}; - -&src_vreg_bob { - regulator-min-microvolt = <3500000>; - regulator-max-microvolt = <3500000>; - vin-supply = <&pp3500_a_vbob>; -}; - -/* - * NON-REGULATOR OVERRIDES - * (modifications to sdm845-cheza.dtsi) - alphabetized by dtsi label - */ - -/* PINCTRL - board-specific pinctrl */ - -&tlmm { - gpio-line-names = "AP_SPI_FP_MISO", - "AP_SPI_FP_MOSI", - "AP_SPI_FP_CLK", - "AP_SPI_FP_CS_L", - "UART_AP_TX_DBG_RX", - "UART_DBG_TX_AP_RX", - "", - "FP_RST_L", - "FCAM_EN", - "", - "EDP_BRIJ_IRQ", - "EC_IN_RW_ODL", - "", - "RCAM_MCLK", - "FCAM_MCLK", - "", - "RCAM_EN", - "CCI0_SDA", - "CCI0_SCL", - "CCI1_SDA", - "CCI1_SCL", - "FCAM_RST_L", - "", - "PEN_RST_L", - "PEN_IRQ_L", - "", - "RCAM_VSYNC", - "ESIM_MISO", - "ESIM_MOSI", - "ESIM_CLK", - "ESIM_CS_L", - "AP_PEN_1V8_SDA", - "AP_PEN_1V8_SCL", - "AP_TS_I2C_SDA", - "AP_TS_I2C_SCL", - "RCAM_RST_L", - "", - "AP_EDP_BKLTEN", - "AP_BRD_ID1", - "BOOT_CONFIG_4", - "AMP_IRQ_L", - "EDP_BRIJ_I2C_SDA", - "EDP_BRIJ_I2C_SCL", - "EN_PP3300_DX_EDP", - "SD_CD_ODL", - "BT_UART_RTS", - "BT_UART_CTS", - "BT_UART_RXD", - "BT_UART_TXD", - "AMP_I2C_SDA", - "AMP_I2C_SCL", - "AP_BRD_ID3", - "", - "AP_EC_SPI_CLK", - "AP_EC_SPI_CS_L", - "AP_EC_SPI_MISO", - "AP_EC_SPI_MOSI", - "FORCED_USB_BOOT", - "AMP_BCLK", - "AMP_LRCLK", - "AMP_DOUT", - "AMP_DIN", - "AP_BRD_ID2", - "PEN_PDCT_L", - "HP_MCLK", - "HP_BCLK", - "HP_LRCLK", - "HP_DOUT", - "HP_DIN", - "", - "", - "", - "", - "BT_SLIMBUS_DATA", - "BT_SLIMBUS_CLK", - "AMP_RESET_L", - "", - "FCAM_VSYNC", - "", - "AP_SKU_ID1", - "EC_WOV_BCLK", - "EC_WOV_LRCLK", - "EC_WOV_DOUT", - "", - "", - "AP_H1_SPI_MISO", - "AP_H1_SPI_MOSI", - "AP_H1_SPI_CLK", - "AP_H1_SPI_CS_L", - "", - "AP_SPI_CS0_L", - "AP_SPI_MOSI", - "AP_SPI_MISO", - "", - "", - "AP_SPI_CLK", - "", - "RFFE6_CLK", - "RFFE6_DATA", - "BOOT_CONFIG_1", - "BOOT_CONFIG_2", - "BOOT_CONFIG_0", - "EDP_BRIJ_EN", - "", - "USB_HS_TX_EN", - "UIM2_DATA", - "UIM2_CLK", - "UIM2_RST", - "UIM2_PRESENT", - "UIM1_DATA", - "UIM1_CLK", - "UIM1_RST", - "", - "AP_SKU_ID2", - "SDM_GRFC_8", - "SDM_GRFC_9", - "AP_RST_REQ", - "HP_IRQ", - "TS_RESET_L", - "PEN_EJECT_ODL", - "HUB_RST_L", - "FP_TO_AP_IRQ", - "AP_EC_INT_L", - "", - "", - "TS_INT_L", - "AP_SUSPEND_L", - "SDM_GRFC_3", - "", - "H1_AP_INT_ODL", - "QLINK_REQ", - "QLINK_EN", - "SDM_GRFC_2", - "BOOT_CONFIG_3", - "WMSS_RESET_L", - "SDM_GRFC_0", - "SDM_GRFC_1", - "RFFE3_DATA", - "RFFE3_CLK", - "RFFE4_DATA", - "RFFE4_CLK", - "RFFE5_DATA", - "RFFE5_CLK", - "GNSS_EN", - "WCI2_LTE_COEX_RXD", - "WCI2_LTE_COEX_TXD", - "AP_RAM_ID1", - "AP_RAM_ID2", - "RFFE1_DATA", - "RFFE1_CLK"; -}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-cheza-r2.dts b/arch/arm64/boot/dts/qcom/sdm845-cheza-r2.dts deleted file mode 100644 index 2b7230594ecb..000000000000 --- a/arch/arm64/boot/dts/qcom/sdm845-cheza-r2.dts +++ /dev/null @@ -1,238 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -/* - * Google Cheza board device tree source - * - * Copyright 2018 Google LLC. - */ - -/dts-v1/; - -#include "sdm845-cheza.dtsi" - -/ { - model = "Google Cheza (rev2)"; - compatible = "google,cheza-rev2", "qcom,sdm845"; - - /* - * FIXED REGULATORS (not in sdm845-cheza.dtsi) - parents above children - */ - - /* - * NOTE: Technically pp3500_a is not the exact same signal as - * pp3500_a_vbob (there's a load switch between them and the EC can - * control pp3500_a via "en_pp3300_a"), but from the AP's point of - * view they are the same. - */ - pp3500_a: - pp3500_a_vbob: pp3500-a-vbob-regulator { - compatible = "regulator-fixed"; - regulator-name = "vreg_bob"; - - /* - * Comes on automatically when pp5000_ldo comes on, which - * comes on automatically when ppvar_sys comes on - */ - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <3500000>; - regulator-max-microvolt = <3500000>; - - vin-supply = <&ppvar_sys>; - }; - - pp3300_dx_edp: pp3300-dx-edp-regulator { - /* Yes, it's really 3.5 despite the name of the signal */ - regulator-min-microvolt = <3500000>; - regulator-max-microvolt = <3500000>; - - vin-supply = <&pp3500_a>; - }; -}; - -/* FIXED REGULATOR OVERRIDES (modifications to sdm845-cheza.dtsi) */ - -/* - * L19 and L28 technically go to 3.3V, but most boards have old AOP firmware - * that limits them to 3.0, and trying to run at 3.3V with that old firmware - * prevents the system from booting. - */ -&src_pp3000_l19a { - regulator-min-microvolt = <3008000>; - regulator-max-microvolt = <3008000>; -}; - -&src_pp3300_l22a { - /delete-property/regulator-boot-on; - /delete-property/regulator-always-on; -}; - -&src_pp3300_l28a { - regulator-min-microvolt = <3008000>; - regulator-max-microvolt = <3008000>; -}; - -&src_vreg_bob { - regulator-min-microvolt = <3500000>; - regulator-max-microvolt = <3500000>; - vin-supply = <&pp3500_a_vbob>; -}; - -/* - * NON-REGULATOR OVERRIDES - * (modifications to sdm845-cheza.dtsi) - alphabetized by dtsi label - */ - -/* PINCTRL - board-specific pinctrl */ - -&tlmm { - gpio-line-names = "AP_SPI_FP_MISO", - "AP_SPI_FP_MOSI", - "AP_SPI_FP_CLK", - "AP_SPI_FP_CS_L", - "UART_AP_TX_DBG_RX", - "UART_DBG_TX_AP_RX", - "BRIJ_SUSPEND", - "FP_RST_L", - "FCAM_EN", - "", - "EDP_BRIJ_IRQ", - "EC_IN_RW_ODL", - "", - "RCAM_MCLK", - "FCAM_MCLK", - "", - "RCAM_EN", - "CCI0_SDA", - "CCI0_SCL", - "CCI1_SDA", - "CCI1_SCL", - "FCAM_RST_L", - "FPMCU_BOOT0", - "PEN_RST_L", - "PEN_IRQ_L", - "FPMCU_SEL_OD", - "RCAM_VSYNC", - "ESIM_MISO", - "ESIM_MOSI", - "ESIM_CLK", - "ESIM_CS_L", - "AP_PEN_1V8_SDA", - "AP_PEN_1V8_SCL", - "AP_TS_I2C_SDA", - "AP_TS_I2C_SCL", - "RCAM_RST_L", - "", - "AP_EDP_BKLTEN", - "AP_BRD_ID1", - "BOOT_CONFIG_4", - "AMP_IRQ_L", - "EDP_BRIJ_I2C_SDA", - "EDP_BRIJ_I2C_SCL", - "EN_PP3300_DX_EDP", - "SD_CD_ODL", - "BT_UART_RTS", - "BT_UART_CTS", - "BT_UART_RXD", - "BT_UART_TXD", - "AMP_I2C_SDA", - "AMP_I2C_SCL", - "AP_BRD_ID3", - "", - "AP_EC_SPI_CLK", - "AP_EC_SPI_CS_L", - "AP_EC_SPI_MISO", - "AP_EC_SPI_MOSI", - "FORCED_USB_BOOT", - "AMP_BCLK", - "AMP_LRCLK", - "AMP_DOUT", - "AMP_DIN", - "AP_BRD_ID2", - "PEN_PDCT_L", - "HP_MCLK", - "HP_BCLK", - "HP_LRCLK", - "HP_DOUT", - "HP_DIN", - "", - "", - "", - "", - "BT_SLIMBUS_DATA", - "BT_SLIMBUS_CLK", - "AMP_RESET_L", - "", - "FCAM_VSYNC", - "", - "AP_SKU_ID1", - "EC_WOV_BCLK", - "EC_WOV_LRCLK", - "EC_WOV_DOUT", - "", - "", - "AP_H1_SPI_MISO", - "AP_H1_SPI_MOSI", - "AP_H1_SPI_CLK", - "AP_H1_SPI_CS_L", - "", - "AP_SPI_CS0_L", - "AP_SPI_MOSI", - "AP_SPI_MISO", - "", - "", - "AP_SPI_CLK", - "", - "RFFE6_CLK", - "RFFE6_DATA", - "BOOT_CONFIG_1", - "BOOT_CONFIG_2", - "BOOT_CONFIG_0", - "EDP_BRIJ_EN", - "", - "USB_HS_TX_EN", - "UIM2_DATA", - "UIM2_CLK", - "UIM2_RST", - "UIM2_PRESENT", - "UIM1_DATA", - "UIM1_CLK", - "UIM1_RST", - "", - "AP_SKU_ID2", - "SDM_GRFC_8", - "SDM_GRFC_9", - "AP_RST_REQ", - "HP_IRQ", - "TS_RESET_L", - "PEN_EJECT_ODL", - "HUB_RST_L", - "FP_TO_AP_IRQ", - "AP_EC_INT_L", - "", - "", - "TS_INT_L", - "AP_SUSPEND_L", - "SDM_GRFC_3", - "", - "H1_AP_INT_ODL", - "QLINK_REQ", - "QLINK_EN", - "SDM_GRFC_2", - "BOOT_CONFIG_3", - "WMSS_RESET_L", - "SDM_GRFC_0", - "SDM_GRFC_1", - "RFFE3_DATA", - "RFFE3_CLK", - "RFFE4_DATA", - "RFFE4_CLK", - "RFFE5_DATA", - "RFFE5_CLK", - "GNSS_EN", - "WCI2_LTE_COEX_RXD", - "WCI2_LTE_COEX_TXD", - "AP_RAM_ID1", - "AP_RAM_ID2", - "RFFE1_DATA", - "RFFE1_CLK"; -}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-cheza-r3.dts b/arch/arm64/boot/dts/qcom/sdm845-cheza-r3.dts deleted file mode 100644 index 1ba67be08f81..000000000000 --- a/arch/arm64/boot/dts/qcom/sdm845-cheza-r3.dts +++ /dev/null @@ -1,174 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -/* - * Google Cheza board device tree source - * - * Copyright 2018 Google LLC. - */ - -/dts-v1/; - -#include "sdm845-cheza.dtsi" - -/ { - model = "Google Cheza (rev3+)"; - compatible = "google,cheza", "qcom,sdm845"; -}; - -/* PINCTRL - board-specific pinctrl */ - -&tlmm { - gpio-line-names = "AP_SPI_FP_MISO", - "AP_SPI_FP_MOSI", - "AP_SPI_FP_CLK", - "AP_SPI_FP_CS_L", - "UART_AP_TX_DBG_RX", - "UART_DBG_TX_AP_RX", - "BRIJ_SUSPEND", - "FP_RST_L", - "FCAM_EN", - "", - "EDP_BRIJ_IRQ", - "EC_IN_RW_ODL", - "", - "RCAM_MCLK", - "FCAM_MCLK", - "", - "RCAM_EN", - "CCI0_SDA", - "CCI0_SCL", - "CCI1_SDA", - "CCI1_SCL", - "FCAM_RST_L", - "FPMCU_BOOT0", - "PEN_RST_L", - "PEN_IRQ_L", - "FPMCU_SEL_OD", - "RCAM_VSYNC", - "ESIM_MISO", - "ESIM_MOSI", - "ESIM_CLK", - "ESIM_CS_L", - "AP_PEN_1V8_SDA", - "AP_PEN_1V8_SCL", - "AP_TS_I2C_SDA", - "AP_TS_I2C_SCL", - "RCAM_RST_L", - "", - "AP_EDP_BKLTEN", - "AP_BRD_ID0", - "BOOT_CONFIG_4", - "AMP_IRQ_L", - "EDP_BRIJ_I2C_SDA", - "EDP_BRIJ_I2C_SCL", - "EN_PP3300_DX_EDP", - "SD_CD_ODL", - "BT_UART_RTS", - "BT_UART_CTS", - "BT_UART_RXD", - "BT_UART_TXD", - "AMP_I2C_SDA", - "AMP_I2C_SCL", - "AP_BRD_ID2", - "", - "AP_EC_SPI_CLK", - "AP_EC_SPI_CS_L", - "AP_EC_SPI_MISO", - "AP_EC_SPI_MOSI", - "FORCED_USB_BOOT", - "AMP_BCLK", - "AMP_LRCLK", - "AMP_DOUT", - "AMP_DIN", - "AP_BRD_ID1", - "PEN_PDCT_L", - "HP_MCLK", - "HP_BCLK", - "HP_LRCLK", - "HP_DOUT", - "HP_DIN", - "", - "", - "", - "", - "BT_SLIMBUS_DATA", - "BT_SLIMBUS_CLK", - "AMP_RESET_L", - "", - "FCAM_VSYNC", - "", - "AP_SKU_ID0", - "EC_WOV_BCLK", - "EC_WOV_LRCLK", - "EC_WOV_DOUT", - "", - "", - "AP_H1_SPI_MISO", - "AP_H1_SPI_MOSI", - "AP_H1_SPI_CLK", - "AP_H1_SPI_CS_L", - "", - "AP_SPI_CS0_L", - "AP_SPI_MOSI", - "AP_SPI_MISO", - "", - "", - "AP_SPI_CLK", - "", - "RFFE6_CLK", - "RFFE6_DATA", - "BOOT_CONFIG_1", - "BOOT_CONFIG_2", - "BOOT_CONFIG_0", - "EDP_BRIJ_EN", - "", - "USB_HS_TX_EN", - "UIM2_DATA", - "UIM2_CLK", - "UIM2_RST", - "UIM2_PRESENT", - "UIM1_DATA", - "UIM1_CLK", - "UIM1_RST", - "", - "AP_SKU_ID1", - "SDM_GRFC_8", - "SDM_GRFC_9", - "AP_RST_REQ", - "HP_IRQ", - "TS_RESET_L", - "PEN_EJECT_ODL", - "HUB_RST_L", - "FP_TO_AP_IRQ", - "AP_EC_INT_L", - "", - "", - "TS_INT_L", - "AP_SUSPEND_L", - "SDM_GRFC_3", - /* - * AP_FLASH_WP_L is crossystem ABI. Rev3 schematics - * call it BIOS_FLASH_WP_R_L. - */ - "AP_FLASH_WP_L", - "H1_AP_INT_ODL", - "QLINK_REQ", - "QLINK_EN", - "SDM_GRFC_2", - "BOOT_CONFIG_3", - "WMSS_RESET_L", - "SDM_GRFC_0", - "SDM_GRFC_1", - "RFFE3_DATA", - "RFFE3_CLK", - "RFFE4_DATA", - "RFFE4_CLK", - "RFFE5_DATA", - "RFFE5_CLK", - "GNSS_EN", - "WCI2_LTE_COEX_RXD", - "WCI2_LTE_COEX_TXD", - "AP_RAM_ID0", - "AP_RAM_ID1", - "RFFE1_DATA", - "RFFE1_CLK"; -}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi b/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi deleted file mode 100644 index b7e514f81f92..000000000000 --- a/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi +++ /dev/null @@ -1,1330 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -/* - * Google Cheza device tree source (common between revisions) - * - * Copyright 2018 Google LLC. - */ - -#include -#include -#include "sdm845.dtsi" - -/* PMICs depend on spmi_bus label and so must come after SoC */ -#include "pm8005.dtsi" -#include "pm8998.dtsi" - -/ { - aliases { - bluetooth0 = &bluetooth; - serial1 = &uart6; - serial0 = &uart9; - wifi0 = &wifi; - }; - - chosen { - stdout-path = "serial0:115200n8"; - }; - - backlight: backlight { - compatible = "pwm-backlight"; - pwms = <&cros_ec_pwm 0>; - enable-gpios = <&tlmm 37 GPIO_ACTIVE_HIGH>; - power-supply = <&ppvar_sys>; - pinctrl-names = "default"; - pinctrl-0 = <&ap_edp_bklten>; - }; - - /* FIXED REGULATORS - parents above children */ - - /* This is the top level supply and variable voltage */ - ppvar_sys: ppvar-sys-regulator { - compatible = "regulator-fixed"; - regulator-name = "ppvar_sys"; - regulator-always-on; - regulator-boot-on; - }; - - /* This divides ppvar_sys by 2, so voltage is variable */ - src_vph_pwr: src-vph-pwr-regulator { - compatible = "regulator-fixed"; - regulator-name = "src_vph_pwr"; - - /* EC turns on with switchcap_on_l; always on for AP */ - regulator-always-on; - regulator-boot-on; - - vin-supply = <&ppvar_sys>; - }; - - pp5000_a: pp5000-a-regulator { - compatible = "regulator-fixed"; - regulator-name = "pp5000_a"; - - /* EC turns on with en_pp5000_a; always on for AP */ - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - - vin-supply = <&ppvar_sys>; - }; - - src_vreg_bob: src-vreg-bob-regulator { - compatible = "regulator-fixed"; - regulator-name = "src_vreg_bob"; - - /* EC turns on with vbob_en; always on for AP */ - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <3600000>; - regulator-max-microvolt = <3600000>; - - vin-supply = <&ppvar_sys>; - }; - - pp3300_dx_edp: pp3300-dx-edp-regulator { - compatible = "regulator-fixed"; - regulator-name = "pp3300_dx_edp"; - - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - - gpio = <&tlmm 43 GPIO_ACTIVE_HIGH>; - enable-active-high; - pinctrl-names = "default"; - pinctrl-0 = <&en_pp3300_dx_edp>; - }; - - /* - * Apparently RPMh does not provide support for PM8998 S4 because it - * is always-on; model it as a fixed regulator. - */ - src_pp1800_s4a: pm8998-smps4 { - compatible = "regulator-fixed"; - regulator-name = "src_pp1800_s4a"; - - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - - regulator-always-on; - regulator-boot-on; - - vin-supply = <&src_vph_pwr>; - }; - - /* BOARD-SPECIFIC TOP LEVEL NODES */ - - gpio-keys { - compatible = "gpio-keys"; - pinctrl-names = "default"; - pinctrl-0 = <&pen_eject_odl>; - - switch-pen-insert { - label = "Pen Insert"; - /* Insert = low, eject = high */ - gpios = <&tlmm 119 GPIO_ACTIVE_LOW>; - linux,code = ; - linux,input-type = ; - wakeup-source; - }; - }; - - panel: panel { - compatible = "innolux,p120zdg-bf1"; - power-supply = <&pp3300_dx_edp>; - backlight = <&backlight>; - no-hpd; - - panel_in: port { - panel_in_edp: endpoint { - remote-endpoint = <&sn65dsi86_out>; - }; - }; - }; -}; - -&cpufreq_hw { - /delete-property/ interrupts-extended; /* reference to lmh_cluster[01] */ -}; - -&psci { - /delete-node/ power-domain-cpu0; - /delete-node/ power-domain-cpu1; - /delete-node/ power-domain-cpu2; - /delete-node/ power-domain-cpu3; - /delete-node/ power-domain-cpu4; - /delete-node/ power-domain-cpu5; - /delete-node/ power-domain-cpu6; - /delete-node/ power-domain-cpu7; - /delete-node/ power-domain-cluster; -}; - -&cpus { - /delete-node/ domain-idle-states; -}; - -&cpu_idle_states { - little_cpu_sleep_0: cpu-sleep-0-0 { - compatible = "arm,idle-state"; - idle-state-name = "little-power-down"; - arm,psci-suspend-param = <0x40000003>; - entry-latency-us = <350>; - exit-latency-us = <461>; - min-residency-us = <1890>; - local-timer-stop; - }; - - little_cpu_sleep_1: cpu-sleep-0-1 { - compatible = "arm,idle-state"; - idle-state-name = "little-rail-power-down"; - arm,psci-suspend-param = <0x40000004>; - entry-latency-us = <360>; - exit-latency-us = <531>; - min-residency-us = <3934>; - local-timer-stop; - }; - - big_cpu_sleep_0: cpu-sleep-1-0 { - compatible = "arm,idle-state"; - idle-state-name = "big-power-down"; - arm,psci-suspend-param = <0x40000003>; - entry-latency-us = <264>; - exit-latency-us = <621>; - min-residency-us = <952>; - local-timer-stop; - }; - - big_cpu_sleep_1: cpu-sleep-1-1 { - compatible = "arm,idle-state"; - idle-state-name = "big-rail-power-down"; - arm,psci-suspend-param = <0x40000004>; - entry-latency-us = <702>; - exit-latency-us = <1061>; - min-residency-us = <4488>; - local-timer-stop; - }; - - cluster_sleep_0: cluster-sleep-0 { - compatible = "arm,idle-state"; - idle-state-name = "cluster-power-down"; - arm,psci-suspend-param = <0x400000F4>; - entry-latency-us = <3263>; - exit-latency-us = <6562>; - min-residency-us = <9987>; - local-timer-stop; - }; -}; - -&cpu0 { - /delete-property/ power-domains; - /delete-property/ power-domain-names; - cpu-idle-states = <&little_cpu_sleep_0 - &little_cpu_sleep_1 - &cluster_sleep_0>; -}; - -&cpu1 { - /delete-property/ power-domains; - /delete-property/ power-domain-names; - cpu-idle-states = <&little_cpu_sleep_0 - &little_cpu_sleep_1 - &cluster_sleep_0>; -}; - -&cpu2 { - /delete-property/ power-domains; - /delete-property/ power-domain-names; - cpu-idle-states = <&little_cpu_sleep_0 - &little_cpu_sleep_1 - &cluster_sleep_0>; -}; - -&cpu3 { - /delete-property/ power-domains; - /delete-property/ power-domain-names; - cpu-idle-states = <&little_cpu_sleep_0 - &little_cpu_sleep_1 - &cluster_sleep_0>; -}; - -&cpu4 { - /delete-property/ power-domains; - /delete-property/ power-domain-names; - cpu-idle-states = <&big_cpu_sleep_0 - &big_cpu_sleep_1 - &cluster_sleep_0>; -}; - -&cpu5 { - /delete-property/ power-domains; - /delete-property/ power-domain-names; - cpu-idle-states = <&big_cpu_sleep_0 - &big_cpu_sleep_1 - &cluster_sleep_0>; -}; - -&cpu6 { - /delete-property/ power-domains; - /delete-property/ power-domain-names; - cpu-idle-states = <&big_cpu_sleep_0 - &big_cpu_sleep_1 - &cluster_sleep_0>; -}; - -&cpu7 { - /delete-property/ power-domains; - /delete-property/ power-domain-names; - cpu-idle-states = <&big_cpu_sleep_0 - &big_cpu_sleep_1 - &cluster_sleep_0>; -}; - -&lmh_cluster0 { - status = "disabled"; -}; - -&lmh_cluster1 { - status = "disabled"; -}; - -/* - * Reserved memory changes - * - * Putting this all together (out of order with the rest of the file) to keep - * all modifications to the memory map (from sdm845.dtsi) in one place. - */ - -/* - * Our mpss_region is 8MB bigger than the default one and that conflicts - * with venus_mem and cdsp_mem. - * - * For venus_mem we'll delete and re-create at a different address. - * - * cdsp_mem isn't used on cheza right now so we won't bother re-creating it; but - * that also means we need to delete cdsp_pas. - */ -/delete-node/ &venus_mem; -/delete-node/ &cdsp_mem; -/delete-node/ &cdsp_pas; -/delete-node/ &gpu_mem; - -/* Increase the size from 120 MB to 128 MB */ -&mpss_region { - reg = <0 0x8e000000 0 0x8000000>; -}; - -/* Increase the size from 2MB to 8MB */ -&rmtfs_mem { - reg = <0 0x88f00000 0 0x800000>; -}; - -/ { - reserved-memory { - venus_mem: memory@96000000 { - reg = <0 0x96000000 0 0x500000>; - no-map; - }; - }; -}; - -&qspi { - status = "okay"; - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&qspi_clk>, <&qspi_cs0>, <&qspi_data0>, <&qspi_data1>; - pinctrl-1 = <&qspi_sleep>; - - flash@0 { - compatible = "jedec,spi-nor"; - reg = <0>; - - /* - * In theory chip supports up to 104 MHz and controller up - * to 80 MHz, but above 25 MHz wasn't reliable so we'll use - * that for now. b:117440651 - */ - spi-max-frequency = <25000000>; - spi-tx-bus-width = <2>; - spi-rx-bus-width = <2>; - }; -}; - - -&apps_rsc { - /delete-property/ power-domains; - - regulators-0 { - compatible = "qcom,pm8998-rpmh-regulators"; - qcom,pmic-id = "a"; - - vdd-s1-supply = <&src_vph_pwr>; - vdd-s2-supply = <&src_vph_pwr>; - vdd-s3-supply = <&src_vph_pwr>; - vdd-s4-supply = <&src_vph_pwr>; - vdd-s5-supply = <&src_vph_pwr>; - vdd-s6-supply = <&src_vph_pwr>; - vdd-s7-supply = <&src_vph_pwr>; - vdd-s8-supply = <&src_vph_pwr>; - vdd-s9-supply = <&src_vph_pwr>; - vdd-s10-supply = <&src_vph_pwr>; - vdd-s11-supply = <&src_vph_pwr>; - vdd-s12-supply = <&src_vph_pwr>; - vdd-s13-supply = <&src_vph_pwr>; - vdd-l1-l27-supply = <&src_pp1025_s7a>; - vdd-l2-l8-l17-supply = <&src_pp1350_s3a>; - vdd-l3-l11-supply = <&src_pp1025_s7a>; - vdd-l4-l5-supply = <&src_pp1025_s7a>; - vdd-l6-supply = <&src_vph_pwr>; - vdd-l7-l12-l14-l15-supply = <&src_pp2040_s5a>; - vdd-l9-supply = <&src_pp2040_s5a>; - vdd-l10-l23-l25-supply = <&src_vreg_bob>; - vdd-l13-l19-l21-supply = <&src_vreg_bob>; - vdd-l16-l28-supply = <&src_vreg_bob>; - vdd-l18-l22-supply = <&src_vreg_bob>; - vdd-l20-l24-supply = <&src_vreg_bob>; - vdd-l26-supply = <&src_pp1350_s3a>; - vin-lvs-1-2-supply = <&src_pp1800_s4a>; - - src_pp1125_s2a: smps2 { - regulator-min-microvolt = <1100000>; - regulator-max-microvolt = <1100000>; - }; - - src_pp1350_s3a: smps3 { - regulator-min-microvolt = <1352000>; - regulator-max-microvolt = <1352000>; - }; - - src_pp2040_s5a: smps5 { - regulator-min-microvolt = <1904000>; - regulator-max-microvolt = <2040000>; - }; - - src_pp1025_s7a: smps7 { - regulator-min-microvolt = <900000>; - regulator-max-microvolt = <1028000>; - }; - - vdd_qusb_hs0: - vdda_hp_pcie_core: - vdda_mipi_csi0_0p9: - vdda_mipi_csi1_0p9: - vdda_mipi_csi2_0p9: - vdda_mipi_dsi0_pll: - vdda_mipi_dsi1_pll: - vdda_qlink_lv: - vdda_qlink_lv_ck: - vdda_qrefs_0p875: - vdda_pcie_core: - vdda_pll_cc_ebi01: - vdda_pll_cc_ebi23: - vdda_sp_sensor: - vdda_ufs1_core: - vdda_ufs2_core: - vdda_usb1_ss_core: - vdda_usb2_ss_core: - src_pp875_l1a: ldo1 { - regulator-min-microvolt = <880000>; - regulator-max-microvolt = <880000>; - regulator-initial-mode = ; - }; - - vddpx_10: - src_pp1200_l2a: ldo2 { - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; - regulator-initial-mode = ; - - /* TODO: why??? */ - regulator-always-on; - }; - - pp1000_l3a_sdr845: ldo3 { - regulator-min-microvolt = <1000000>; - regulator-max-microvolt = <1000000>; - regulator-initial-mode = ; - }; - - vdd_wcss_cx: - vdd_wcss_mx: - vdda_wcss_pll: - src_pp800_l5a: ldo5 { - regulator-min-microvolt = <800000>; - regulator-max-microvolt = <800000>; - regulator-initial-mode = ; - }; - - vddpx_13: - src_pp1800_l6a: ldo6 { - regulator-min-microvolt = <1856000>; - regulator-max-microvolt = <1856000>; - regulator-initial-mode = ; - }; - - pp1800_l7a_wcn3990: ldo7 { - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-initial-mode = ; - }; - - src_pp1200_l8a: ldo8 { - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1248000>; - regulator-initial-mode = ; - }; - - pp1800_dx_pen: - src_pp1800_l9a: ldo9 { - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-initial-mode = ; - }; - - src_pp1800_l10a: ldo10 { - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-initial-mode = ; - }; - - pp1000_l11a_sdr845: ldo11 { - regulator-min-microvolt = <1000000>; - regulator-max-microvolt = <1048000>; - regulator-initial-mode = ; - }; - - vdd_qfprom: - vdd_qfprom_sp: - vdda_apc1_cs_1p8: - vdda_gfx_cs_1p8: - vdda_qrefs_1p8: - vdda_qusb_hs0_1p8: - vddpx_11: - src_pp1800_l12a: ldo12 { - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-initial-mode = ; - }; - - vddpx_2: - src_pp2950_l13a: ldo13 { - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <2960000>; - regulator-initial-mode = ; - }; - - src_pp1800_l14a: ldo14 { - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-initial-mode = ; - }; - - src_pp1800_l15a: ldo15 { - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-initial-mode = ; - }; - - pp2700_l16a: ldo16 { - regulator-min-microvolt = <2704000>; - regulator-max-microvolt = <2704000>; - regulator-initial-mode = ; - }; - - src_pp1300_l17a: ldo17 { - regulator-min-microvolt = <1304000>; - regulator-max-microvolt = <1304000>; - regulator-initial-mode = ; - }; - - pp2700_l18a: ldo18 { - regulator-min-microvolt = <2704000>; - regulator-max-microvolt = <2960000>; - regulator-initial-mode = ; - }; - - /* - * NOTE: this rail should have been called - * src_pp3300_l19a in the schematic - */ - src_pp3000_l19a: ldo19 { - regulator-min-microvolt = <3304000>; - regulator-max-microvolt = <3304000>; - - regulator-initial-mode = ; - }; - - src_pp2950_l20a: ldo20 { - regulator-min-microvolt = <2704000>; - regulator-max-microvolt = <2960000>; - regulator-initial-mode = ; - }; - - src_pp2950_l21a: ldo21 { - regulator-min-microvolt = <2704000>; - regulator-max-microvolt = <2960000>; - regulator-initial-mode = ; - }; - - pp3300_hub: - src_pp3300_l22a: ldo22 { - regulator-min-microvolt = <3304000>; - regulator-max-microvolt = <3304000>; - regulator-initial-mode = ; - /* - * HACK: Should add a usb hub node and driver - * to turn this on and off at suspend/resume time - */ - regulator-boot-on; - regulator-always-on; - }; - - pp3300_l23a_ch1_wcn3990: ldo23 { - regulator-min-microvolt = <3000000>; - regulator-max-microvolt = <3312000>; - regulator-initial-mode = ; - }; - - vdda_qusb_hs0_3p1: - src_pp3075_l24a: ldo24 { - regulator-min-microvolt = <3088000>; - regulator-max-microvolt = <3088000>; - regulator-initial-mode = ; - }; - - pp3300_l25a_ch0_wcn3990: ldo25 { - regulator-min-microvolt = <3304000>; - regulator-max-microvolt = <3304000>; - regulator-initial-mode = ; - }; - - pp1200_hub: - vdda_hp_pcie_1p2: - vdda_hv_ebi0: - vdda_hv_ebi1: - vdda_hv_ebi2: - vdda_hv_ebi3: - vdda_mipi_csi_1p25: - vdda_mipi_dsi0_1p2: - vdda_mipi_dsi1_1p2: - vdda_pcie_1p2: - vdda_ufs1_1p2: - vdda_ufs2_1p2: - vdda_usb1_ss_1p2: - vdda_usb2_ss_1p2: - src_pp1200_l26a: ldo26 { - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; - regulator-initial-mode = ; - }; - - pp3300_dx_pen: - src_pp3300_l28a: ldo28 { - regulator-min-microvolt = <3304000>; - regulator-max-microvolt = <3304000>; - regulator-initial-mode = ; - }; - - src_pp1800_lvs1: lvs1 { - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - }; - - src_pp1800_lvs2: lvs2 { - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - }; - }; - - regulators-1 { - compatible = "qcom,pm8005-rpmh-regulators"; - qcom,pmic-id = "c"; - - vdd-s1-supply = <&src_vph_pwr>; - vdd-s2-supply = <&src_vph_pwr>; - vdd-s3-supply = <&src_vph_pwr>; - vdd-s4-supply = <&src_vph_pwr>; - - src_pp600_s3c: smps3 { - regulator-min-microvolt = <600000>; - regulator-max-microvolt = <600000>; - }; - }; -}; - -edp_brij_i2c: &i2c3 { - status = "okay"; - clock-frequency = <400000>; - - sn65dsi86_bridge: bridge@2d { - compatible = "ti,sn65dsi86"; - reg = <0x2d>; - pinctrl-names = "default"; - pinctrl-0 = <&edp_brij_en &edp_brij_irq>; - - interrupt-parent = <&tlmm>; - interrupts = <10 IRQ_TYPE_LEVEL_HIGH>; - - enable-gpios = <&tlmm 102 GPIO_ACTIVE_HIGH>; - - vpll-supply = <&src_pp1800_s4a>; - vccio-supply = <&src_pp1800_s4a>; - vcca-supply = <&src_pp1200_l2a>; - vcc-supply = <&src_pp1200_l2a>; - - clocks = <&rpmhcc RPMH_LN_BB_CLK2>; - clock-names = "refclk"; - - no-hpd; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - sn65dsi86_in: endpoint { - remote-endpoint = <&mdss_dsi0_out>; - }; - }; - - port@1 { - reg = <1>; - sn65dsi86_out: endpoint { - remote-endpoint = <&panel_in_edp>; - }; - }; - }; - }; -}; - -ap_pen_1v8: &i2c11 { - status = "okay"; - clock-frequency = <400000>; - - digitizer@9 { - compatible = "wacom,w9013", "hid-over-i2c"; - reg = <0x9>; - pinctrl-names = "default"; - pinctrl-0 = <&pen_irq_l>, <&pen_pdct_l>, <&pen_rst_l>; - - vdd-supply = <&pp3300_dx_pen>; - vddl-supply = <&pp1800_dx_pen>; - post-power-on-delay-ms = <100>; - - interrupt-parent = <&tlmm>; - interrupts = <24 IRQ_TYPE_LEVEL_LOW>; - - hid-descr-addr = <0x1>; - }; -}; - -amp_i2c: &i2c12 { - status = "okay"; - clock-frequency = <400000>; -}; - -ap_ts_i2c: &i2c14 { - status = "okay"; - clock-frequency = <400000>; - - touchscreen@10 { - compatible = "elan,ekth3500"; - reg = <0x10>; - pinctrl-names = "default"; - pinctrl-0 = <&ts_int_l &ts_reset_l>; - - interrupt-parent = <&tlmm>; - interrupts = <125 IRQ_TYPE_LEVEL_LOW>; - - vcc33-supply = <&src_pp3300_l28a>; - - reset-gpios = <&tlmm 118 GPIO_ACTIVE_LOW>; - }; -}; - -&gpu { - status = "okay"; -}; - -&ipa { - qcom,gsi-loader = "modem"; - status = "okay"; -}; - -&lpasscc { - status = "okay"; -}; - -&mdss { - status = "okay"; -}; - -&mdss_dsi0 { - status = "okay"; - vdda-supply = <&vdda_mipi_dsi0_1p2>; - - ports { - port@1 { - endpoint { - remote-endpoint = <&sn65dsi86_in>; - data-lanes = <0 1 2 3>; - }; - }; - }; -}; - -&mdss_dsi0_phy { - status = "okay"; - vdds-supply = <&vdda_mipi_dsi0_pll>; -}; - -/* - * Cheza fw does not properly program the GPU aperture to allow the - * GPU to update the SMMU pagetables for context switches. Work - * around this by dropping the "qcom,adreno-smmu" compat string. - */ -&adreno_smmu { - compatible = "qcom,sdm845-smmu-v2", "qcom,smmu-v2"; -}; - -&mss_pil { - status = "okay"; - - iommus = <&apps_smmu 0x781 0x0>, - <&apps_smmu 0x724 0x3>; -}; - -&pm8998_pwrkey { - status = "disabled"; -}; - -&qupv3_id_0 { - status = "okay"; - iommus = <&apps_smmu 0x0 0x3>; -}; - -&qupv3_id_1 { - status = "okay"; - iommus = <&apps_smmu 0x6c0 0x3>; -}; - -&sdhc_2 { - status = "okay"; - - pinctrl-names = "default"; - pinctrl-0 = <&sdc2_clk &sdc2_cmd &sdc2_data &sd_cd_odl>; - - vmmc-supply = <&src_pp2950_l21a>; - vqmmc-supply = <&vddpx_2>; - - cd-gpios = <&tlmm 44 GPIO_ACTIVE_LOW>; -}; - -&spi0 { - status = "okay"; -}; - -&spi5 { - status = "okay"; - - tpm@0 { - compatible = "google,cr50"; - reg = <0>; - pinctrl-names = "default"; - pinctrl-0 = <&h1_ap_int_odl>; - spi-max-frequency = <800000>; - interrupt-parent = <&tlmm>; - interrupts = <129 IRQ_TYPE_EDGE_RISING>; - }; -}; - -&spi10 { - status = "okay"; - - cros_ec: ec@0 { - compatible = "google,cros-ec-spi"; - reg = <0>; - interrupt-parent = <&tlmm>; - interrupts = <122 IRQ_TYPE_LEVEL_LOW>; - pinctrl-names = "default"; - pinctrl-0 = <&ec_ap_int_l>; - spi-max-frequency = <3000000>; - wakeup-source; - - cros_ec_pwm: pwm { - compatible = "google,cros-ec-pwm"; - #pwm-cells = <1>; - }; - - i2c_tunnel: i2c-tunnel { - compatible = "google,cros-ec-i2c-tunnel"; - google,remote-bus = <0>; - #address-cells = <1>; - #size-cells = <0>; - }; - }; -}; - -#include -#include - -&uart6 { - status = "okay"; - - pinctrl-0 = <&qup_uart6_4pin>; - - bluetooth: bluetooth { - compatible = "qcom,wcn3990-bt"; - vddio-supply = <&src_pp1800_s4a>; - vddxo-supply = <&pp1800_l7a_wcn3990>; - vddrf-supply = <&src_pp1300_l17a>; - vddch0-supply = <&pp3300_l25a_ch0_wcn3990>; - max-speed = <3200000>; - }; -}; - -&uart9 { - status = "okay"; -}; - -&ufs_mem_hc { - status = "okay"; - - reset-gpios = <&tlmm 150 GPIO_ACTIVE_LOW>; - - vcc-supply = <&src_pp2950_l20a>; - vcc-max-microamp = <600000>; -}; - -&ufs_mem_phy { - status = "okay"; - - vdda-phy-supply = <&vdda_ufs1_core>; - vdda-pll-supply = <&vdda_ufs1_1p2>; -}; - -&usb_1 { - status = "okay"; - - /* We'll use this as USB 2.0 only */ - qcom,select-utmi-as-pipe-clk; -}; - -&usb_1_dwc3 { - /* - * The hardware design intends this port to be hooked up in peripheral - * mode, so we'll hardcode it here. Some details: - * - SDM845 expects only a single Type C connector so it has only one - * native Type C port but cheza has two Type C connectors. - * - The only source of DP is the single native Type C port. - * - On cheza we want to be able to hook DP up to _either_ of the - * two Type C connectors and want to be able to achieve 4 lanes of DP. - * - When you configure a Type C port for 4 lanes of DP you lose USB3. - * - In order to make everything work, the native Type C port is always - * configured as 4-lanes DP so it's always available. - * - The extra USB3 port on SDM845 goes to a USB 3 hub which is then - * sent to the two Type C connectors. - * - The extra USB2 lines from the native Type C port are always - * setup as "peripheral" so that we can mux them over to one connector - * or the other if someone needs the connector configured as a gadget - * (but they only get USB2 speeds). - * - * All the hardware muxes would allow us to hook things up in different - * ways to some potential benefit for static configurations (you could - * achieve extra USB2 bandwidth by using two different ports for the - * two connectors or possibly even get USB3 peripheral mode), but in - * each case you end up forcing to disconnect/reconnect an in-use - * USB session in some cases depending on what you hotplug into the - * other connector. Thus hardcoding this as peripheral makes sense. - */ - dr_mode = "peripheral"; - - /* - * We always need the high speed pins as 4-lanes DP in case someone - * hotplugs a DP peripheral. Thus limit this port to a max of high - * speed. - */ - maximum-speed = "high-speed"; - - /* - * We don't need the usb3-phy since we run in highspeed mode always, so - * re-define these properties removing the superspeed USB PHY reference. - */ - phys = <&usb_1_hsphy>; - phy-names = "usb2-phy"; -}; - -&usb_1_hsphy { - status = "okay"; - - vdd-supply = <&vdda_usb1_ss_core>; - vdda-pll-supply = <&vdda_qusb_hs0_1p8>; - vdda-phy-dpdm-supply = <&vdda_qusb_hs0_3p1>; - - qcom,imp-res-offset-value = <8>; - qcom,hstx-trim-value = ; - qcom,preemphasis-level = ; - qcom,preemphasis-width = ; -}; - -&usb_2 { - status = "okay"; -}; - -&usb_2_dwc3 { - /* We have this hooked up to a hub and we always use in host mode */ - dr_mode = "host"; -}; - -&usb_2_hsphy { - status = "okay"; - - vdd-supply = <&vdda_usb2_ss_core>; - vdda-pll-supply = <&vdda_qusb_hs0_1p8>; - vdda-phy-dpdm-supply = <&vdda_qusb_hs0_3p1>; - - qcom,imp-res-offset-value = <8>; - qcom,hstx-trim-value = ; -}; - -&usb_2_qmpphy { - status = "okay"; - - vdda-phy-supply = <&vdda_usb2_ss_1p2>; - vdda-pll-supply = <&vdda_usb2_ss_core>; -}; - -&wifi { - status = "okay"; - - vdd-0.8-cx-mx-supply = <&src_pp800_l5a >; - vdd-1.8-xo-supply = <&pp1800_l7a_wcn3990>; - vdd-1.3-rfa-supply = <&src_pp1300_l17a>; - vdd-3.3-ch0-supply = <&pp3300_l25a_ch0_wcn3990>; -}; - -/* PINCTRL - additions to nodes defined in sdm845.dtsi */ - -&qspi_cs0 { - bias-disable; /* External pullup */ -}; - -&qspi_clk { - bias-disable; /* Rely on Cr50 internal pulldown */ -}; - -&qspi_data0 { - bias-disable; /* Rely on Cr50 internal pulldown */ -}; - -&qspi_data1 { - bias-pull-down; -}; - -&qup_i2c3_default { - drive-strength = <2>; - - /* Has external pullup */ - bias-disable; -}; - -&qup_i2c11_default { - drive-strength = <2>; - - /* Has external pullup */ - bias-disable; -}; - -&qup_i2c12_default { - drive-strength = <2>; - - /* Has external pullup */ - bias-disable; -}; - -&qup_i2c14_default { - drive-strength = <2>; - - /* Has external pullup */ - bias-disable; -}; - -&qup_spi0_default { - drive-strength = <2>; - bias-disable; -}; - -&qup_spi5_default { - drive-strength = <2>; - bias-disable; -}; - -&qup_spi10_default { - drive-strength = <2>; - bias-disable; -}; - -&qup_uart9_rx { - drive-strength = <2>; - bias-pull-up; -}; - -&qup_uart9_tx { - drive-strength = <2>; - bias-disable; -}; - -/* PINCTRL - board-specific pinctrl */ -&pm8005_gpios { - gpio-line-names = "", - "", - "SLB", - ""; -}; - -&pm8998_adc { - channel@4d { - reg = ; - label = "sdm_temp"; - }; - - channel@4e { - reg = ; - label = "quiet_temp"; - }; - - channel@4f { - reg = ; - label = "lte_temp_1"; - }; - - channel@50 { - reg = ; - label = "lte_temp_2"; - }; - - channel@51 { - reg = ; - label = "charger_temp"; - }; -}; - -&pm8998_gpios { - gpio-line-names = "", - "", - "SW_CTRL", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "CFG_OPT1", - "WCSS_PWR_REQ", - "", - "CFG_OPT2", - "SLB"; -}; - -&tlmm { - /* - * pinctrl settings for pins that have no real owners. - */ - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&bios_flash_wp_r_l>, - <&ap_suspend_l_deassert>; - - pinctrl-1 = <&bios_flash_wp_r_l>, - <&ap_suspend_l_assert>; - - /* - * Hogs prevent usermode from changing the value. A GPIO can be both - * here and in the pinctrl section. - */ - ap-suspend-l-hog { - gpio-hog; - gpios = <126 GPIO_ACTIVE_LOW>; - output-low; - }; - - ap_edp_bklten: ap-edp-bklten-state { - pins = "gpio37"; - function = "gpio"; - drive-strength = <2>; - bias-disable; - }; - - bios_flash_wp_r_l: bios-flash-wp-r-l-state { - pins = "gpio128"; - function = "gpio"; - bias-disable; - }; - - ec_ap_int_l: ec-ap-int-l-state { - pins = "gpio122"; - function = "gpio"; - bias-pull-up; - }; - - edp_brij_en: edp-brij-en-state { - pins = "gpio102"; - function = "gpio"; - drive-strength = <2>; - bias-disable; - }; - - edp_brij_irq: edp-brij-irq-state { - pins = "gpio10"; - function = "gpio"; - drive-strength = <2>; - bias-pull-down; - }; - - en_pp3300_dx_edp: en-pp3300-dx-edp-state { - pins = "gpio43"; - function = "gpio"; - drive-strength = <2>; - bias-disable; - }; - - h1_ap_int_odl: h1-ap-int-odl-state { - pins = "gpio129"; - function = "gpio"; - bias-pull-up; - }; - - pen_eject_odl: pen-eject-odl-state { - pins = "gpio119"; - function = "gpio"; - bias-pull-up; - }; - - pen_irq_l: pen-irq-l-state { - pins = "gpio24"; - function = "gpio"; - - /* Has external pullup */ - bias-disable; - }; - - pen_pdct_l: pen-pdct-l-state { - pins = "gpio63"; - function = "gpio"; - - /* Has external pullup */ - bias-disable; - }; - - pen_rst_l: pen-rst-l-state { - pins = "gpio23"; - function = "gpio"; - bias-disable; - drive-strength = <2>; - - /* - * The pen driver doesn't currently support - * driving this reset line. By specifying - * output-high here we're relying on the fact - * that this pin has a default pulldown at boot - * (which makes sure the pen was in reset if it - * was powered) and then we set it high here to - * take it out of reset. Better would be if the - * pen driver could control this and we could - * remove "output-high" here. - */ - output-high; - }; - - qspi_sleep: qspi-sleep-state { - pins = "gpio90", "gpio91", "gpio92", "gpio95"; - - /* - * When we're not actively transferring we want pins as GPIOs - * with output disabled so that the quad SPI IP block stops - * driving them. We rely on the normal pulls configured in - * the active state and don't redefine them here. Also note - * that we don't need the reverse (output-enable) in the - * normal mode since the "output-enable" only matters for - * GPIO function. - */ - function = "gpio"; - output-disable; - }; - - sdc2_clk: sdc2-clk-state { - pins = "sdc2_clk"; - bias-disable; - - /* - * It seems that mmc_test reports errors if drive - * strength is not 16. - */ - drive-strength = <16>; - }; - - sdc2_cmd: sdc2-cmd-state { - pins = "sdc2_cmd"; - bias-pull-up; - drive-strength = <16>; - }; - - sdc2_data: sdc2-data-state { - pins = "sdc2_data"; - bias-pull-up; - drive-strength = <16>; - }; - - sd_cd_odl: sd-cd-odl-state { - pins = "gpio44"; - function = "gpio"; - bias-pull-up; - }; - - ts_int_l: ts-int-l-state { - pins = "gpio125"; - function = "gpio"; - bias-pull-up; - }; - - ts_reset_l: ts-reset-l-state { - pins = "gpio118"; - function = "gpio"; - bias-disable; - drive-strength = <2>; - }; - - ap_suspend_l_assert: ap-suspend-l-assert-state { - pins = "gpio126"; - function = "gpio"; - bias-disable; - drive-strength = <2>; - output-low; - }; - - ap_suspend_l_deassert: ap-suspend-l-deassert-state { - pins = "gpio126"; - function = "gpio"; - bias-disable; - drive-strength = <2>; - output-high; - }; -}; - -&venus { - status = "okay"; - - video-firmware { - iommus = <&apps_smmu 0x10b2 0x0>; - }; -}; From bae72efa3ca6674ff99668b00290376babae10f5 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Wed, 16 Jul 2025 12:16:08 +0200 Subject: [PATCH 00334/11391] dt-bindings: arm: qcom: Remove sdm845-cheza Cheza was a prototype board, used mainly by the ChromeOS folks. Almost no working devices are known to exist, and the small amount of remaining ones are not in use anymore. Remove the compatible strings reserved for it, as, quite frankly, Cheza is no more. Signed-off-by: Konrad Dybcio Reviewed-by: Krzysztof Kozlowski Reviewed-by: Douglas Anderson Link: https://lore.kernel.org/r/20250716-topic-goodnight_cheza-v2-2-6fa8d3261813@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/arm/qcom.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml index 1df00d9e6de0..b5acb0d26346 100644 --- a/Documentation/devicetree/bindings/arm/qcom.yaml +++ b/Documentation/devicetree/bindings/arm/qcom.yaml @@ -884,9 +884,6 @@ properties: - items: - enum: - - google,cheza - - google,cheza-rev1 - - google,cheza-rev2 - lenovo,yoga-c630 - lg,judyln - lg,judyp From 43b8556e82f38cc2e7a66c9dd44d1104be4fe73c Mon Sep 17 00:00:00 2001 From: Sayali Lokhande Date: Wed, 16 Jul 2025 14:21:24 +0530 Subject: [PATCH 00335/11391] arm64: dts: qcom: qcs8300: Add eMMC support Add eMMC support for qcs8300 board. Signed-off-by: Sayali Lokhande Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250716085125.27169-2-quic_sayalil@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/qcs8300.dtsi | 113 ++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs8300.dtsi b/arch/arm64/boot/dts/qcom/qcs8300.dtsi index 7d38ddd2cc9e..3cf1d4bc7e4a 100644 --- a/arch/arm64/boot/dts/qcom/qcs8300.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs8300.dtsi @@ -4120,6 +4120,69 @@ cti@6900000 { clock-names = "apb_pclk"; }; + sdhc_1: mmc@87c4000 { + compatible = "qcom,qcs8300-sdhci", "qcom,sdhci-msm-v5"; + reg = <0x0 0x087c4000 0x0 0x1000>, + <0x0 0x087c5000 0x0 0x1000>; + reg-names = "hc", + "cqhci"; + + interrupts = , + ; + interrupt-names = "hc_irq", + "pwr_irq"; + + clocks = <&gcc GCC_SDCC1_AHB_CLK>, + <&gcc GCC_SDCC1_APPS_CLK>, + <&rpmhcc RPMH_CXO_CLK>; + clock-names = "iface", + "core", + "xo"; + + resets = <&gcc GCC_SDCC1_BCR>; + + power-domains = <&rpmhpd RPMHPD_CX>; + operating-points-v2 = <&sdhc1_opp_table>; + iommus = <&apps_smmu 0x0 0x0>; + interconnects = <&aggre1_noc MASTER_SDC QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &config_noc SLAVE_SDC1 QCOM_ICC_TAG_ACTIVE_ONLY>; + interconnect-names = "sdhc-ddr", + "cpu-sdhc"; + + qcom,dll-config = <0x000f64ee>; + qcom,ddr-config = <0x80040868>; + supports-cqe; + dma-coherent; + + status = "disabled"; + + sdhc1_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-50000000 { + opp-hz = /bits/ 64 <50000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-100000000 { + opp-hz = /bits/ 64 <100000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-384000000 { + opp-hz = /bits/ 64 <384000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + usb_1_hsphy: phy@8904000 { compatible = "qcom,qcs8300-usb-hs-phy", "qcom,usb-snps-hs-7nm-phy"; @@ -5325,6 +5388,56 @@ qup_uart16_rx: qup-uart16-rx-state { pins = "gpio13"; function = "qup2_se0"; }; + + sdc1_state_on: sdc1-on-state { + clk-pins { + pins = "sdc1_clk"; + drive-strength = <16>; + bias-disable; + }; + + cmd-pins { + pins = "sdc1_cmd"; + drive-strength = <10>; + bias-pull-up; + }; + + data-pins { + pins = "sdc1_data"; + drive-strength = <10>; + bias-pull-up; + }; + + rclk-pins { + pins = "sdc1_rclk"; + bias-pull-down; + }; + }; + + sdc1_state_off: sdc1-off-state { + clk-pins { + pins = "sdc1_clk"; + drive-strength = <2>; + bias-bus-hold; + }; + + cmd-pins { + pins = "sdc1_cmd"; + drive-strength = <2>; + bias-bus-hold; + }; + + data-pins { + pins = "sdc1_data"; + drive-strength = <2>; + bias-bus-hold; + }; + + rclk-pins { + pins = "sdc1_rclk"; + bias-bus-hold; + }; + }; }; sram: sram@146d8000 { From d81448d49cb26d9255479c7c74de03a257b5c528 Mon Sep 17 00:00:00 2001 From: Sayali Lokhande Date: Wed, 16 Jul 2025 14:21:25 +0530 Subject: [PATCH 00336/11391] arm64: dts: qcom: qcs8300-ride: Enable SDHC1 node Enable sdhc1 support for qcs8300 ride platform. Signed-off-by: Sayali Lokhande Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250716085125.27169-3-quic_sayalil@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/qcs8300-ride.dts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs8300-ride.dts b/arch/arm64/boot/dts/qcom/qcs8300-ride.dts index 8c166ead912c..9c37a0f5ba25 100644 --- a/arch/arm64/boot/dts/qcom/qcs8300-ride.dts +++ b/arch/arm64/boot/dts/qcom/qcs8300-ride.dts @@ -17,6 +17,7 @@ / { aliases { serial0 = &uart7; + mmc0 = &sdhc_1; }; chosen { @@ -332,6 +333,26 @@ &serdes0 { status = "okay"; }; +&sdhc_1 { + pinctrl-0 = <&sdc1_state_on>; + pinctrl-1 = <&sdc1_state_off>; + pinctrl-names = "default", "sleep"; + + bus-width = <8>; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + mmc-hs400-1_8v; + mmc-hs400-enhanced-strobe; + vmmc-supply = <&vreg_l8a>; + vqmmc-supply = <&vreg_s4a>; + + non-removable; + no-sd; + no-sdio; + + status = "okay"; +}; + &tlmm { ethernet0_default: ethernet0-default-state { ethernet0_mdc: ethernet0-mdc-pins { From f578e5f0b8b5f81e19e5f97a95e9cadf4e9c699d Mon Sep 17 00:00:00 2001 From: Krishna Kurapati Date: Tue, 15 Jul 2025 10:57:38 +0530 Subject: [PATCH 00337/11391] arm64: dts: qcom: sm8450-qrd: add pmic glink node Add the pmic glink node linked with the DWC3 USB controller switched to OTG mode and tagged with usb-role-switch. Signed-off-by: Krishna Kurapati Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250715052739.3831549-2-krishna.kurapati@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8450-qrd.dts | 51 ++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8450-qrd.dts b/arch/arm64/boot/dts/qcom/sm8450-qrd.dts index 8c39fbcaad80..56db5f79f59d 100644 --- a/arch/arm64/boot/dts/qcom/sm8450-qrd.dts +++ b/arch/arm64/boot/dts/qcom/sm8450-qrd.dts @@ -28,6 +28,49 @@ chosen { stdout-path = "serial0:115200n8"; }; + pmic-glink { + compatible = "qcom,sm8450-pmic-glink", "qcom,pmic-glink"; + #address-cells = <1>; + #size-cells = <0>; + orientation-gpios = <&tlmm 91 GPIO_ACTIVE_HIGH>; + + connector@0 { + compatible = "usb-c-connector"; + reg = <0>; + power-role = "dual"; + data-role = "dual"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + pmic_glink_hs_in: endpoint { + remote-endpoint = <&usb_1_dwc3_hs>; + }; + }; + + port@1 { + reg = <1>; + + pmic_glink_ss_in: endpoint { + remote-endpoint = <&usb_1_qmpphy_out>; + }; + }; + + port@2 { + reg = <2>; + + pmic_glink_sbu: endpoint { + }; + }; + + }; + }; + }; + vph_pwr: vph-pwr-regulator { compatible = "regulator-fixed"; regulator-name = "vph_pwr"; @@ -461,8 +504,8 @@ &usb_1 { status = "okay"; }; -&usb_1_dwc3 { - dr_mode = "peripheral"; +&usb_1_dwc3_hs { + remote-endpoint = <&pmic_glink_hs_in>; }; &usb_1_hsphy { @@ -487,3 +530,7 @@ &usb_1_qmpphy { vdda-phy-supply = <&vreg_l6b_1p2>; vdda-pll-supply = <&vreg_l1b_0p91>; }; + +&usb_1_qmpphy_out { + remote-endpoint = <&pmic_glink_ss_in>; +}; From c5a87e3a6b3ed051466a20cb954be1c138199c56 Mon Sep 17 00:00:00 2001 From: Krishna Kurapati Date: Tue, 15 Jul 2025 10:57:39 +0530 Subject: [PATCH 00338/11391] arm64: dts: qcom: sm8450: Flatten usb controller node Flatten usb controller node and update to using latest bindings and flattened driver approach. Reviewed-by: Konrad Dybcio Signed-off-by: Krishna Kurapati Link: https://lore.kernel.org/r/20250715052739.3831549-3-krishna.kurapati@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8450-hdk.dts | 5 -- .../dts/qcom/sm8450-sony-xperia-nagara.dtsi | 5 +- arch/arm64/boot/dts/qcom/sm8450.dtsi | 57 +++++++++---------- 3 files changed, 27 insertions(+), 40 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8450-hdk.dts b/arch/arm64/boot/dts/qcom/sm8450-hdk.dts index 2ff40a120aad..0c6aa7ddf432 100644 --- a/arch/arm64/boot/dts/qcom/sm8450-hdk.dts +++ b/arch/arm64/boot/dts/qcom/sm8450-hdk.dts @@ -1199,11 +1199,6 @@ &usb_1 { status = "okay"; }; -&usb_1_dwc3 { - dr_mode = "otg"; - usb-role-switch; -}; - &usb_1_dwc3_hs { remote-endpoint = <&pmic_glink_hs_in>; }; diff --git a/arch/arm64/boot/dts/qcom/sm8450-sony-xperia-nagara.dtsi b/arch/arm64/boot/dts/qcom/sm8450-sony-xperia-nagara.dtsi index cc1335a07a35..6bd315e10992 100644 --- a/arch/arm64/boot/dts/qcom/sm8450-sony-xperia-nagara.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8450-sony-xperia-nagara.dtsi @@ -781,11 +781,8 @@ &uart7 { }; &usb_1 { - status = "okay"; -}; - -&usb_1_dwc3 { dr_mode = "peripheral"; + status = "okay"; }; &usb_1_hsphy { diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi index 33574ad706b9..2baef6869ed7 100644 --- a/arch/arm64/boot/dts/qcom/sm8450.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi @@ -5418,12 +5418,9 @@ opp-202000000 { }; usb_1: usb@a6f8800 { - compatible = "qcom,sm8450-dwc3", "qcom,dwc3"; - reg = <0 0x0a6f8800 0 0x400>; + compatible = "qcom,sm8450-dwc3", "qcom,snps-dwc3"; + reg = <0 0x0a600000 0 0xfc100>; status = "disabled"; - #address-cells = <2>; - #size-cells = <2>; - ranges; clocks = <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, <&gcc GCC_USB30_PRIM_MASTER_CLK>, @@ -5442,12 +5439,14 @@ usb_1: usb@a6f8800 { <&gcc GCC_USB30_PRIM_MASTER_CLK>; assigned-clock-rates = <19200000>, <200000000>; - interrupts-extended = <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>, + interrupts-extended = <&intc GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>, + <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>, <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, <&pdc 14 IRQ_TYPE_EDGE_BOTH>, <&pdc 15 IRQ_TYPE_EDGE_BOTH>, <&pdc 17 IRQ_TYPE_LEVEL_HIGH>; - interrupt-names = "pwr_event", + interrupt-names = "dwc_usb3", + "pwr_event", "hs_phy_irq", "dp_hs_phy_irq", "dm_hs_phy_irq", @@ -5461,36 +5460,32 @@ usb_1: usb@a6f8800 { <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_USB3_0 0>; interconnect-names = "usb-ddr", "apps-usb"; - usb_1_dwc3: usb@a600000 { - compatible = "snps,dwc3"; - reg = <0 0x0a600000 0 0xcd00>; - interrupts = ; - iommus = <&apps_smmu 0x0 0x0>; - snps,dis_u2_susphy_quirk; - snps,dis_u3_susphy_quirk; - snps,dis_enblslpm_quirk; - snps,dis-u1-entry-quirk; - snps,dis-u2-entry-quirk; - phys = <&usb_1_hsphy>, <&usb_1_qmpphy QMP_USB43DP_USB3_PHY>; - phy-names = "usb2-phy", "usb3-phy"; + iommus = <&apps_smmu 0x0 0x0>; + snps,dis_u2_susphy_quirk; + snps,dis_u3_susphy_quirk; + snps,dis_enblslpm_quirk; + snps,dis-u1-entry-quirk; + snps,dis-u2-entry-quirk; + phys = <&usb_1_hsphy>, <&usb_1_qmpphy QMP_USB43DP_USB3_PHY>; + phy-names = "usb2-phy", "usb3-phy"; + usb-role-switch; - ports { - #address-cells = <1>; - #size-cells = <0>; + ports { + #address-cells = <1>; + #size-cells = <0>; - port@0 { - reg = <0>; + port@0 { + reg = <0>; - usb_1_dwc3_hs: endpoint { - }; + usb_1_dwc3_hs: endpoint { }; + }; - port@1 { - reg = <1>; + port@1 { + reg = <1>; - usb_1_dwc3_ss: endpoint { - remote-endpoint = <&usb_1_qmpphy_usb_ss_in>; - }; + usb_1_dwc3_ss: endpoint { + remote-endpoint = <&usb_1_qmpphy_usb_ss_in>; }; }; }; From ad9abc9ba4046360f23a410f74ef78e646c08aa1 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Mon, 14 Jul 2025 13:48:15 +0200 Subject: [PATCH 00339/11391] arm64: dts: qcom: x1e80100-crd: Add USB multiport fingerprint reader The X1E80100 CRD has a Goodix fingerprint reader connected to the USB multiport controller on eUSB6. All other ports (including USB super-speed pins) are unused. Set it up in the device tree together with the NXP PTN3222 repeater. Signed-off-by: Stephan Gerhold Reviewed-by: Johan Hovold Tested-by: Johan Hovold Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250714-x1e80100-crd-fp-v2-1-3246eb02b679@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/x1-crd.dtsi | 64 ++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/x1-crd.dtsi b/arch/arm64/boot/dts/qcom/x1-crd.dtsi index c9f0d5052670..730b27c878fc 100644 --- a/arch/arm64/boot/dts/qcom/x1-crd.dtsi +++ b/arch/arm64/boot/dts/qcom/x1-crd.dtsi @@ -1016,6 +1016,27 @@ retimer_ss0_con_sbu_out: endpoint { }; }; +&i2c5 { + clock-frequency = <400000>; + + status = "okay"; + + eusb6_repeater: redriver@4f { + compatible = "nxp,ptn3222"; + reg = <0x4f>; + + vdd1v8-supply = <&vreg_l4b_1p8>; + vdd3v3-supply = <&vreg_l13b_3p0>; + + reset-gpios = <&tlmm 184 GPIO_ACTIVE_LOW>; + + pinctrl-0 = <&eusb6_reset_n>; + pinctrl-names = "default"; + + #phy-cells = <0>; + }; +}; + &i2c7 { clock-frequency = <400000>; @@ -1466,6 +1487,14 @@ edp_reg_en: edp-reg-en-state { bias-disable; }; + eusb6_reset_n: eusb6-reset-n-state { + pins = "gpio184"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + output-low; + }; + hall_int_n_default: hall-int-n-state { pins = "gpio92"; function = "gpio"; @@ -1747,3 +1776,38 @@ &usb_1_ss2_dwc3_hs { &usb_1_ss2_qmpphy_out { remote-endpoint = <&retimer_ss2_ss_in>; }; + +&usb_mp { + /* Only second port is used with USB 2.0 maximum speed */ + status = "okay"; +}; + +&usb_mp_hsphy0 { + vdd-supply = <&vreg_l2e_0p8>; + vdda12-supply = <&vreg_l3e_1p2>; + + status = "okay"; +}; + +&usb_mp_hsphy1 { + vdd-supply = <&vreg_l2e_0p8>; + vdda12-supply = <&vreg_l3e_1p2>; + + phys = <&eusb6_repeater>; + + status = "okay"; +}; + +&usb_mp_qmpphy0 { + vdda-phy-supply = <&vreg_l3e_1p2>; + vdda-pll-supply = <&vreg_l3c_0p8>; + + status = "okay"; +}; + +&usb_mp_qmpphy1 { + vdda-phy-supply = <&vreg_l3e_1p2>; + vdda-pll-supply = <&vreg_l3c_0p8>; + + status = "okay"; +}; From 5433560caa5e7e677a8d4310bbec08312be765b4 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 10 Jul 2025 20:47:08 +0300 Subject: [PATCH 00340/11391] arm64: dts: qcom: sdm845-db845c-navigation-mezzanine: Replace clock-frequency in camera sensor node The clock-frequency for camera sensors has been deprecated in favour of the assigned-clocks and assigned-clock-rates properties. Replace it in the device tree. Signed-off-by: Laurent Pinchart Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250710174808.5361-13-laurent.pinchart@ideasonboard.com Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/sdm845-db845c-navigation-mezzanine.dtso | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c-navigation-mezzanine.dtso b/arch/arm64/boot/dts/qcom/sdm845-db845c-navigation-mezzanine.dtso index 51f1a4883ab8..dbe1911d8e47 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-db845c-navigation-mezzanine.dtso +++ b/arch/arm64/boot/dts/qcom/sdm845-db845c-navigation-mezzanine.dtso @@ -44,7 +44,8 @@ camera@10 { clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; clock-names = "xvclk"; - clock-frequency = <19200000>; + assigned-clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + assigned-clock-rates = <19200000>; /* * The &vreg_s4a_1p8 trace is powered on as a, From 3a99873d8b9f6c1ec027987fff7b32eab9273316 Mon Sep 17 00:00:00 2001 From: Antony Kurniawan Soemardi Date: Sun, 22 Jun 2025 18:26:47 +0000 Subject: [PATCH 00341/11391] dt-bindings: arm: qcom: add Sony Xperia SP Document the Sony Xperia SP (huashan), which uses the MSM8960T SoC. The MSM8960T is a variant of the MSM8960 featuring an upgraded GPU (Adreno 320 instead of Adreno 225) and a slightly overclocked CPU (1.7GHz instead of 1.5GHz). Signed-off-by: Antony Kurniawan Soemardi Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250623-msm8960-sdcard-v2-4-340a5e8f7df0@smankusors.com Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/arm/qcom.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml index ae43b3556580..b9e8defc7ffe 100644 --- a/Documentation/devicetree/bindings/arm/qcom.yaml +++ b/Documentation/devicetree/bindings/arm/qcom.yaml @@ -203,6 +203,12 @@ properties: - samsung,expressatt - const: qcom,msm8960 + - items: + - enum: + - sony,huashan + - const: qcom,msm8960t + - const: qcom,msm8960 + - items: - enum: - lge,hammerhead From d2f146b3dfbcc2550b9c805b49dab53b4babf2e8 Mon Sep 17 00:00:00 2001 From: Antony Kurniawan Soemardi Date: Sun, 22 Jun 2025 18:26:50 +0000 Subject: [PATCH 00342/11391] ARM: dts: qcom: add device tree for Sony Xperia SP Add initial device tree support for the Sony Xperia SP (codename: sony-huashan), a smartphone based on the Qualcomm MSM8960T SoC. There are two variants of the Xperia SP, one without LTE and one with LTE. This device tree should work for both variants, though it has only been tested on the non-LTE variant. The following are currently supported: - Serial console support via gsbi8 - GPIO keys for volume up/down buttons - PM8921 keypad with camera focus/capture keys - eMMC (sdcc1) and micro SD card (sdcc3) support - USB OTG support Other hardware features are not yet implemented. Booting notes: Booting a kernel requires using the Sony ELF boot image format, which embeds the kernel, ramdisk, RPM firmware, and cmdline. This can be created using the `mkelf` tool. For example: python2 mkelf.py -o boot.img \ kernel+dtb@0x80208000 \ ramdisk.img@0x81900000 \ RPM.bin@0x00020000,rpm \ cmdline.txt@cmdline The resulting `boot.img` can then be flashed via fastboot. A detailed guide, including an alternative method, is available at: https://wiki.postmarketos.org/wiki/Sony_Xperia_SP_(sony-huashan) Signed-off-by: Antony Kurniawan Soemardi Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250623-msm8960-sdcard-v2-5-340a5e8f7df0@smankusors.com Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/Makefile | 1 + .../dts/qcom/qcom-msm8960-sony-huashan.dts | 361 ++++++++++++++++++ 2 files changed, 362 insertions(+) create mode 100644 arch/arm/boot/dts/qcom/qcom-msm8960-sony-huashan.dts diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index e875b5d25e84..c7873dcef154 100644 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -43,6 +43,7 @@ dtb-$(CONFIG_ARCH_QCOM) += \ qcom-msm8926-samsung-matisselte.dtb \ qcom-msm8960-cdp.dtb \ qcom-msm8960-samsung-expressatt.dtb \ + qcom-msm8960-sony-huashan.dtb \ qcom-msm8974-lge-nexus5-hammerhead.dtb \ qcom-msm8974-samsung-hlte.dtb \ qcom-msm8974-sony-xperia-rhine-amami.dtb \ diff --git a/arch/arm/boot/dts/qcom/qcom-msm8960-sony-huashan.dts b/arch/arm/boot/dts/qcom/qcom-msm8960-sony-huashan.dts new file mode 100644 index 000000000000..f2f59fc8b9b6 --- /dev/null +++ b/arch/arm/boot/dts/qcom/qcom-msm8960-sony-huashan.dts @@ -0,0 +1,361 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025, Antony Kurniawan Soemardi + */ +#include +#include +#include +#include + +#include "qcom-msm8960.dtsi" +#include "pm8921.dtsi" + +/ { + model = "Sony Xperia SP"; + compatible = "sony,huashan", "qcom,msm8960t", "qcom,msm8960"; + chassis-type = "handset"; + + aliases { + serial0 = &gsbi8_serial; + mmc0 = &sdcc1; /* SDCC1 eMMC slot */ + mmc1 = &sdcc3; /* SDCC3 SD card slot */ + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + gpio-keys { + compatible = "gpio-keys"; + + key-volume-up { + label = "Volume Up"; + gpios = <&pm8921_gpio 21 GPIO_ACTIVE_LOW>; + debounce-interval = <10>; + linux,code = ; + }; + + key-volume-down { + label = "Volume Down"; + gpios = <&pm8921_gpio 20 GPIO_ACTIVE_LOW>; + debounce-interval = <10>; + linux,code = ; + }; + }; +}; + +&gsbi8 { + qcom,mode = ; + status = "okay"; +}; + +&gsbi8_serial { + status = "okay"; +}; + +&pm8921 { + interrupts-extended = <&msmgpio 104 IRQ_TYPE_LEVEL_LOW>; +}; + +&pm8921_gpio { + keypad_default_state: keypad-default-state { + keypad-sense-pins { + pins = "gpio1", "gpio2", "gpio3", "gpio4", "gpio5"; + function = PMIC_GPIO_FUNC_NORMAL; + bias-pull-up; + input-enable; + power-source = ; + qcom,drive-strength = ; + qcom,pull-up-strength = ; + }; + + keypad-drive-pins { + pins = "gpio9", "gpio10"; + function = PMIC_GPIO_FUNC_FUNC1; + bias-disable; + drive-open-drain; + output-low; + power-source = ; + qcom,drive-strength = ; + }; + }; +}; + +&pm8921_keypad { + linux,keymap = < + MATRIX_KEY(1, 0, KEY_CAMERA_FOCUS) + MATRIX_KEY(1, 1, KEY_CAMERA) + >; + keypad,num-rows = <2>; + keypad,num-columns = <5>; + + pinctrl-0 = <&keypad_default_state>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&rpm { + regulators { + compatible = "qcom,rpm-pm8921-regulators"; + vin_lvs1_3_6-supply = <&pm8921_s4>; + vin_lvs2-supply = <&pm8921_s4>; + vin_lvs4_5_7-supply = <&pm8921_s4>; + vdd_ncp-supply = <&pm8921_l6>; + vdd_l1_l2_l12_l18-supply = <&pm8921_s4>; + vdd_l21_l23_l29-supply = <&pm8921_s8>; + vdd_l24-supply = <&pm8921_s1>; + vdd_l25-supply = <&pm8921_s1>; + vdd_l26-supply = <&pm8921_s7>; + vdd_l27-supply = <&pm8921_s7>; + vdd_l28-supply = <&pm8921_s7>; + vdd_l29-supply = <&pm8921_s8>; + + /* Buck SMPS */ + pm8921_s1: s1 { + regulator-always-on; + regulator-min-microvolt = <1225000>; + regulator-max-microvolt = <1225000>; + qcom,switch-mode-frequency = <3200000>; + bias-pull-down; + }; + + pm8921_s2: s2 { + regulator-min-microvolt = <1300000>; + regulator-max-microvolt = <1300000>; + qcom,switch-mode-frequency = <1600000>; + bias-pull-down; + }; + + pm8921_s3: s3 { + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1150000>; + qcom,switch-mode-frequency = <4800000>; + bias-pull-down; + }; + + pm8921_s4: s4 { + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,switch-mode-frequency = <1600000>; + bias-pull-down; + qcom,force-mode = ; + }; + + pm8921_s7: s7 { + regulator-min-microvolt = <1150000>; + regulator-max-microvolt = <1150000>; + qcom,switch-mode-frequency = <3200000>; + bias-pull-down; + }; + + pm8921_s8: s8 { + regulator-always-on; + regulator-min-microvolt = <2050000>; + regulator-max-microvolt = <2050000>; + qcom,switch-mode-frequency = <1600000>; + bias-pull-down; + }; + + /* PMOS LDO */ + pm8921_l1: l1 { + regulator-always-on; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + bias-pull-down; + }; + + pm8921_l2: l2 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + bias-pull-down; + }; + + pm8921_l3: l3 { + regulator-min-microvolt = <3075000>; + regulator-max-microvolt = <3075000>; + bias-pull-down; + }; + + pm8921_l4: l4 { + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + bias-pull-down; + }; + + pm8921_l5: l5 { + regulator-min-microvolt = <2950000>; + regulator-max-microvolt = <2950000>; + bias-pull-down; + }; + + pm8921_l6: l6 { + regulator-min-microvolt = <2950000>; + regulator-max-microvolt = <2950000>; + bias-pull-down; + }; + + pm8921_l7: l7 { + regulator-always-on; + regulator-min-microvolt = <1850000>; + regulator-max-microvolt = <2950000>; + bias-pull-down; + }; + + pm8921_l8: l8 { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3000000>; + bias-pull-down; + }; + + pm8921_l9: l9 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + bias-pull-down; + }; + + pm8921_l10: l10 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + bias-pull-down; + }; + + pm8921_l11: l11 { + regulator-min-microvolt = <2600000>; + regulator-max-microvolt = <3000000>; + bias-pull-down; + }; + + pm8921_l12: l12 { + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1200000>; + bias-pull-down; + }; + + pm8921_l14: l14 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + bias-pull-down; + }; + + pm8921_l15: l15 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2950000>; + bias-pull-down; + }; + + pm8921_l16: l16 { + regulator-min-microvolt = <2600000>; + regulator-max-microvolt = <3000000>; + bias-pull-down; + }; + + pm8921_l17: l17 { + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3000000>; + bias-pull-down; + }; + + pm8921_l18: l18 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + bias-pull-down; + }; + + pm8921_l21: l21 { + regulator-min-microvolt = <1900000>; + regulator-max-microvolt = <1900000>; + bias-pull-down; + }; + + pm8921_l22: l22 { + regulator-min-microvolt = <2750000>; + regulator-max-microvolt = <2750000>; + bias-pull-down; + }; + + pm8921_l23: l23 { + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + bias-pull-down; + }; + + pm8921_l24: l24 { + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <1150000>; + bias-pull-down; + }; + + pm8921_l25: l25 { + regulator-always-on; + regulator-min-microvolt = <1225000>; + regulator-max-microvolt = <1225000>; + bias-pull-down; + }; + + /* Low Voltage Switch */ + pm8921_lvs1: lvs1 { + bias-pull-down; + }; + + pm8921_lvs2: lvs2 { + bias-pull-down; + }; + + pm8921_lvs3: lvs3 { + bias-pull-down; + }; + + pm8921_lvs4: lvs4 { + bias-pull-down; + }; + + pm8921_lvs5: lvs5 { + bias-pull-down; + }; + + pm8921_lvs6: lvs6 { + bias-pull-down; + }; + + pm8921_lvs7: lvs7 { + bias-pull-down; + }; + + pm8921_ncp: ncp { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,switch-mode-frequency = <1600000>; + }; + }; +}; + +&sdcc1 { + vmmc-supply = <&pm8921_l5>; + status = "okay"; +}; + +&sdcc3 { + vmmc-supply = <&pm8921_l6>; + vqmmc-supply = <&pm8921_l7>; + + pinctrl-0 = <&sdcc3_default_state>; + pinctrl-1 = <&sdcc3_sleep_state>; + pinctrl-names = "default", "sleep"; + + status = "okay"; +}; + +&usb_hs1_phy { + v3p3-supply = <&pm8921_l3>; + v1p8-supply = <&pm8921_l4>; +}; + +&usb1 { + dr_mode = "otg"; + status = "okay"; +}; From 3f9e5d74d1943a9f98c814970b709098a1108845 Mon Sep 17 00:00:00 2001 From: Shinjo Park Date: Fri, 13 Jun 2025 21:42:53 +0200 Subject: [PATCH 00343/11391] ARM: dts: qcom: pm8921: add vibrator device node Use the same definition as pm8058.dtsi. Since vibrator is used only by some devices, disable it by default and let it be enabled explicitly. Signed-off-by: Shinjo Park Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250613194253.20080-1-peremen@gmail.com Signed-off-by: Bjorn Andersson --- arch/arm/boot/dts/qcom/pm8921.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/boot/dts/qcom/pm8921.dtsi b/arch/arm/boot/dts/qcom/pm8921.dtsi index 058962af3005..535cb6a2543f 100644 --- a/arch/arm/boot/dts/qcom/pm8921.dtsi +++ b/arch/arm/boot/dts/qcom/pm8921.dtsi @@ -17,6 +17,12 @@ pwrkey@1c { pull-up; }; + pm8921_vibrator: vibrator@4a { + compatible = "qcom,pm8921-vib"; + reg = <0x4a>; + status = "disabled"; + }; + pm8921_mpps: mpps@50 { compatible = "qcom,pm8921-mpp", "qcom,ssbi-mpp"; From fdf913d0c44f330e83905e7f1ab738dc63b2b82c Mon Sep 17 00:00:00 2001 From: Adam Honse Date: Wed, 18 Jun 2025 23:45:44 +0200 Subject: [PATCH 00344/11391] ARM: dts: qcom: msm8974-samsung-hlte: Add touchkey support Add support for the touchkeys on the Samsung Galaxy Note 3 (hlte). Signed-off-by: Adam Honse Signed-off-by: Luca Weiss Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250618-hlte-touchkey-v2-1-2cf188b57e31@lucaweiss.eu Signed-off-by: Bjorn Andersson --- .../dts/qcom/qcom-msm8974-samsung-hlte.dts | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974-samsung-hlte.dts b/arch/arm/boot/dts/qcom/qcom-msm8974-samsung-hlte.dts index 903bb4d12513..b7a1367d3470 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974-samsung-hlte.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8974-samsung-hlte.dts @@ -50,6 +50,34 @@ key-volume-up { }; }; + i2c-touchkey { + compatible = "i2c-gpio"; + + sda-gpios = <&tlmm 95 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + scl-gpios = <&tlmm 96 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + + pinctrl-0 = <&i2c_touchkey_pins>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + touchkey@20 { + compatible = "cypress,midas-touchkey"; + reg = <0x20>; + + interrupts-extended = <&pm8941_gpios 29 IRQ_TYPE_EDGE_FALLING>; + + pinctrl-0 = <&touchkey_pin>; + pinctrl-names = "default"; + + vcc-supply = <&pm8941_lvs3>; + vdd-supply = <&pm8941_l13>; + + linux,keycodes = ; + }; + }; + touch_ldo: regulator-touch { compatible = "regulator-fixed"; regulator-name = "touch-ldo"; @@ -149,6 +177,14 @@ touch_ldo_pin: touchscreen-ldo-state { power-source = ; qcom,drive-strength = ; }; + + touchkey_pin: touchkey-int-state { + pins = "gpio29"; + function = "normal"; + bias-disable; + input-enable; + power-source = ; + }; }; &remoteproc_adsp { @@ -332,6 +368,9 @@ pm8941_l24: l24 { regulator-min-microvolt = <3075000>; regulator-max-microvolt = <3075000>; }; + + pm8941_lvs1: lvs1 {}; + pm8941_lvs3: lvs3 {}; }; }; @@ -378,6 +417,12 @@ sdhc3_pin_a: sdhc3-pin-active-state { drive-strength = <8>; bias-disable; }; + + i2c_touchkey_pins: i2c-touchkey-state { + pins = "gpio95", "gpio96"; + function = "gpio"; + bias-pull-up; + }; }; &usb { From 0f85b6c1cb5746180b2bf674a436a48e6722e7ed Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Fri, 18 Jul 2025 00:36:24 -0700 Subject: [PATCH 00345/11391] gpu: nova-core: vbios: use size_of instead of magic number 12 is identical to the value of `size_of::()`, so use the latter instead. [acourbot@nvidia.com: remove `dead_code` expect to fix `unfulfilled_lint_expectations` lint] Reviewed-by: Alexandre Courbot Signed-off-by: Rhys Lloyd Link: https://lore.kernel.org/r/20250718073633.194032-2-krakow20@gmail.com Signed-off-by: Alexandre Courbot --- drivers/gpu/nova-core/vbios.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/nova-core/vbios.rs b/drivers/gpu/nova-core/vbios.rs index 5b5d9f38cbb3..b4bca1919d8f 100644 --- a/drivers/gpu/nova-core/vbios.rs +++ b/drivers/gpu/nova-core/vbios.rs @@ -345,7 +345,7 @@ fn image_size_bytes(&self) -> usize { /// its header) is in the [`PciAtBiosImage`] and the falcon data it is pointing to is in the /// [`FwSecBiosImage`]. #[derive(Debug, Clone, Copy)] -#[expect(dead_code)] +#[repr(C)] struct BitHeader { /// 0h: BIT Header Identifier (BMP=0x7FFF/BIT=0xB8FF) id: u16, @@ -365,7 +365,7 @@ struct BitHeader { impl BitHeader { fn new(data: &[u8]) -> Result { - if data.len() < 12 { + if data.len() < core::mem::size_of::() { return Err(EINVAL); } From 2872c8982c80e22f9a7fc4db7d8f0e8188ab4cd7 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Fri, 18 Jul 2025 00:36:25 -0700 Subject: [PATCH 00346/11391] gpu: nova-core: vbios: change PmuLookupTableEntry to use size_of Annotate the PmuLookupTableEntry with an `#[repr(C, packed)]` attribute. Removes another magic number by making the struct the same size as the data it needs to read, allowing the use of `size_of::()` [acourbot@nvidia.com: remove `dead_code` expect to fix `unfulfilled_lint_expectations` lint] Reviewed-by: Alexandre Courbot Signed-off-by: Rhys Lloyd Link: https://lore.kernel.org/r/20250718073633.194032-3-krakow20@gmail.com Signed-off-by: Alexandre Courbot --- drivers/gpu/nova-core/vbios.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/nova-core/vbios.rs b/drivers/gpu/nova-core/vbios.rs index b4bca1919d8f..50fbea69fc00 100644 --- a/drivers/gpu/nova-core/vbios.rs +++ b/drivers/gpu/nova-core/vbios.rs @@ -892,7 +892,7 @@ fn try_from(base: BiosImageBase) -> Result { /// The [`PmuLookupTableEntry`] structure is a single entry in the [`PmuLookupTable`]. /// /// See the [`PmuLookupTable`] description for more information. -#[expect(dead_code)] +#[repr(C, packed)] struct PmuLookupTableEntry { application_id: u8, target_id: u8, @@ -901,7 +901,7 @@ struct PmuLookupTableEntry { impl PmuLookupTableEntry { fn new(data: &[u8]) -> Result { - if data.len() < 6 { + if data.len() < core::mem::size_of::() { return Err(EINVAL); } From 3b51739fa2001b047359e11afd755ae5e189b7db Mon Sep 17 00:00:00 2001 From: Philipp Stanner Date: Thu, 7 Aug 2025 09:07:57 +0200 Subject: [PATCH 00347/11391] MAINTAINERS: Add website of Nova GPU driver The Nova GPU driver has a sub-website on the Rust-for-Linux website which so far was missing from the respective section in MAINTAINERS. Add the Nova website. Signed-off-by: Philipp Stanner Link: https://lore.kernel.org/r/20250807070756.103816-2-phasta@kernel.org Signed-off-by: Alexandre Courbot --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index fe168477caa4..936650c7eff9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7829,6 +7829,7 @@ M: Danilo Krummrich M: Alexandre Courbot L: nouveau@lists.freedesktop.org S: Supported +W: https://rust-for-linux.com/nova-gpu-driver Q: https://patchwork.freedesktop.org/project/nouveau/ B: https://gitlab.freedesktop.org/drm/nova/-/issues C: irc://irc.oftc.net/nouveau @@ -7840,6 +7841,7 @@ DRM DRIVER FOR NVIDIA GPUS [RUST] M: Danilo Krummrich L: nouveau@lists.freedesktop.org S: Supported +W: https://rust-for-linux.com/nova-gpu-driver Q: https://patchwork.freedesktop.org/project/nouveau/ B: https://gitlab.freedesktop.org/drm/nova/-/issues C: irc://irc.oftc.net/nouveau From 60fdba1dccd81420bbe8da0d7483b4f28c7fa833 Mon Sep 17 00:00:00 2001 From: Aleksandrs Vinarskis Date: Mon, 30 Jun 2025 22:54:10 +0200 Subject: [PATCH 00348/11391] arm64: dts: qcom: x1-crd: Enable HBR3 on external DPs When no link frequencies are set, msm/dp driver defaults to HBR2 speed. Explicitly list supported frequencies including HBR3/8.1Gbps for all external DisplayPort(s). Signed-off-by: Aleksandrs Vinarskis Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250630205514.14022-2-alex.vinarskis@gmail.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/x1-crd.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/x1-crd.dtsi b/arch/arm64/boot/dts/qcom/x1-crd.dtsi index 730b27c878fc..35d26d14b6bd 100644 --- a/arch/arm64/boot/dts/qcom/x1-crd.dtsi +++ b/arch/arm64/boot/dts/qcom/x1-crd.dtsi @@ -1150,6 +1150,7 @@ &mdss_dp0 { &mdss_dp0_out { data-lanes = <0 1>; + link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; }; &mdss_dp1 { @@ -1158,6 +1159,7 @@ &mdss_dp1 { &mdss_dp1_out { data-lanes = <0 1>; + link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; }; &mdss_dp2 { @@ -1166,6 +1168,7 @@ &mdss_dp2 { &mdss_dp2_out { data-lanes = <0 1>; + link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; }; &mdss_dp3 { From 93109afda01593c2ddadb4ec1c42b3bdf695ee2a Mon Sep 17 00:00:00 2001 From: Aleksandrs Vinarskis Date: Mon, 30 Jun 2025 22:54:11 +0200 Subject: [PATCH 00349/11391] arm64: dts: qcom: x1e78100-lenovo-thinkpad-t14s: Enable HBR3 on external DPs When no link frequencies are set, msm/dp driver defaults to HBR2 speed. Explicitly list supported frequencies including HBR3/8.1Gbps for all external DisplayPort(s). Signed-off-by: Aleksandrs Vinarskis Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250630205514.14022-3-alex.vinarskis@gmail.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi | 2 ++ 1 file changed, 2 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..2308d5a0e3af 100644 --- a/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi +++ b/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi @@ -995,6 +995,7 @@ &mdss_dp0 { &mdss_dp0_out { data-lanes = <0 1>; + link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; }; &mdss_dp1 { @@ -1003,6 +1004,7 @@ &mdss_dp1 { &mdss_dp1_out { data-lanes = <0 1>; + link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; }; &mdss_dp3 { From 8839b8e6e849e209b52bf0ae4d0770d89c036b0e Mon Sep 17 00:00:00 2001 From: Richard Acayan Date: Mon, 30 Jun 2025 18:41:59 -0400 Subject: [PATCH 00350/11391] arm64: dts: qcom: sdm670-google-sargo: enable charger The Pixel 3a has a rechargeable 3000 mAh battery. Describe it and enable its charging controller in PM660. Signed-off-by: Richard Acayan Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250630224158.249726-2-mailingradian@gmail.com Signed-off-by: Bjorn Andersson --- .../arm64/boot/dts/qcom/sdm670-google-sargo.dts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm670-google-sargo.dts b/arch/arm64/boot/dts/qcom/sdm670-google-sargo.dts index 74b5d9c68eb6..d01422844fbf 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-google-sargo.dts +++ b/arch/arm64/boot/dts/qcom/sdm670-google-sargo.dts @@ -33,6 +33,14 @@ / { aliases { }; + battery: battery { + compatible = "simple-battery"; + + voltage-min-design-microvolt = <3312000>; + voltage-max-design-microvolt = <4400000>; + charge-full-design-microamp-hours = <3000000>; + }; + chosen { stdout-path = "serial0:115200n8"; @@ -478,6 +486,15 @@ &mdss_mdp { status = "okay"; }; +&pm660_charger { + monitored-battery = <&battery>; + status = "okay"; +}; + +&pm660_rradc { + status = "okay"; +}; + &pm660l_flash { status = "okay"; From 285fee8c65efd7969f9376ed9798afece9a0ccc9 Mon Sep 17 00:00:00 2001 From: David Heidelberg Date: Fri, 1 Aug 2025 10:21:39 +0200 Subject: [PATCH 00351/11391] arm64: dts: qcom: sdm845*: Use definition for msm-id For all boards it's QCOM_ID_SDM845 except Dragonboard, where it's QCOM_ID_SDA845. Except for OnePlus 6 / 6T, which is handled in following commit. Signed-off-by: David Heidelberg Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250801-sdm845-msmid-v2-1-9f44d125ee44@ixit.cz Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sdm845-db845c.dts | 3 ++- arch/arm64/boot/dts/qcom/sdm845-shift-axolotl.dts | 3 ++- arch/arm64/boot/dts/qcom/sdm845-sony-xperia-tama.dtsi | 3 ++- arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi | 3 ++- arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts index b5c63fa0365d..3ec2c7864f1e 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts @@ -5,6 +5,7 @@ /dts-v1/; +#include #include #include #include @@ -18,7 +19,7 @@ / { model = "Thundercomm Dragonboard 845c"; compatible = "thundercomm,db845c", "qcom,sdm845"; - qcom,msm-id = <341 0x20001>; + qcom,msm-id = ; qcom,board-id = <8 0>; aliases { diff --git a/arch/arm64/boot/dts/qcom/sdm845-shift-axolotl.dts b/arch/arm64/boot/dts/qcom/sdm845-shift-axolotl.dts index 2cf7b5e1243c..87e913343cbb 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-shift-axolotl.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-shift-axolotl.dts @@ -7,6 +7,7 @@ /dts-v1/; +#include #include #include #include @@ -17,7 +18,7 @@ / { model = "SHIFT SHIFT6mq"; compatible = "shift,axolotl", "qcom,sdm845"; - qcom,msm-id = <321 0x20001>; + qcom,msm-id = ; qcom,board-id = <11 0>; aliases { diff --git a/arch/arm64/boot/dts/qcom/sdm845-sony-xperia-tama.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sony-xperia-tama.dtsi index a3a304e1ac87..f3f4c0900572 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-sony-xperia-tama.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-sony-xperia-tama.dtsi @@ -3,6 +3,7 @@ * Copyright (c) 2021, Konrad Dybcio */ +#include #include #include #include @@ -12,7 +13,7 @@ #include "pmi8998.dtsi" / { - qcom,msm-id = <321 0x20001>; /* SDM845 v2.1 */ + qcom,msm-id = ; /* SDM845 v2.1 */ qcom,board-id = <8 0>; aliases { diff --git a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi index 7810b0ce7591..7480c8d7ac5b 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi @@ -2,6 +2,7 @@ /dts-v1/; +#include #include #include #include @@ -32,7 +33,7 @@ / { /* required for bootloader to select correct board */ qcom,board-id = <69 0>; - qcom,msm-id = <321 0x20001>; + qcom,msm-id = ; aliases { serial1 = &uart6; diff --git a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts index 63cf879a7a29..1c50a0563bc4 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts @@ -6,6 +6,7 @@ /dts-v1/; +#include #include #include #include @@ -38,7 +39,7 @@ / { chassis-type = "handset"; /* required for bootloader to select correct board */ - qcom,msm-id = <0x141 0x20001>; + qcom,msm-id = ; qcom,board-id = <0x2a 0x0>; aliases { From f72f3aac4a9a990701455a4759a49393cd5802d6 Mon Sep 17 00:00:00 2001 From: David Heidelberg Date: Fri, 1 Aug 2025 10:21:40 +0200 Subject: [PATCH 00352/11391] arm64: dts: qcom: sdm845-oneplus: Deduplicate shared entries Use the definition for qcom,msm-id and put them into the common dtsi. Signed-off-by: David Heidelberg Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250801-sdm845-msmid-v2-2-9f44d125ee44@ixit.cz Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi | 4 ++++ arch/arm64/boot/dts/qcom/sdm845-oneplus-enchilada.dts | 2 -- arch/arm64/boot/dts/qcom/sdm845-oneplus-fajita.dts | 2 -- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi index b118d666e535..dcfffb271fcf 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi @@ -7,6 +7,7 @@ /dts-v1/; +#include #include #include #include @@ -21,6 +22,9 @@ /delete-node/ &rmtfs_mem; / { + chassis-type = "handset"; + qcom,msm-id = ; + aliases { serial0 = &uart9; serial1 = &uart6; diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-enchilada.dts b/arch/arm64/boot/dts/qcom/sdm845-oneplus-enchilada.dts index 4005e04d998a..cd5546b69d13 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-enchilada.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-enchilada.dts @@ -10,8 +10,6 @@ / { model = "OnePlus 6"; compatible = "oneplus,enchilada", "qcom,sdm845"; - chassis-type = "handset"; - qcom,msm-id = <0x141 0x20001>; qcom,board-id = <8 0 17819 22>; battery: battery { diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-fajita.dts b/arch/arm64/boot/dts/qcom/sdm845-oneplus-fajita.dts index 9471ada0d6ad..b4212626b429 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-fajita.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-fajita.dts @@ -10,8 +10,6 @@ / { model = "OnePlus 6T"; compatible = "oneplus,fajita", "qcom,sdm845"; - chassis-type = "handset"; - qcom,msm-id = <0x141 0x20001>; qcom,board-id = <8 0 18801 41>; battery: battery { From dc231840dca64793da7a80ff156fa1d99584f3ea Mon Sep 17 00:00:00 2001 From: Sumit Garg Date: Wed, 30 Jul 2025 18:52:30 +0530 Subject: [PATCH 00353/11391] arm64: dts: qcom: qcm2290: Add TCSR download mode address Allow configuration of download mode via qcom_scm driver via specifying download mode register address in the TCSR space. It is especially useful for a clean watchdog reset without entry into download mode. The problem remained un-noticed until now since error reporting for missing download mode configuration feature was explicitly suppressed. Signed-off-by: Sumit Garg Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250730132230.247727-1-sumit.garg@kernel.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/qcm2290.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/qcm2290.dtsi b/arch/arm64/boot/dts/qcom/qcm2290.dtsi index fa24b77a31a7..5edf9ca29ca0 100644 --- a/arch/arm64/boot/dts/qcom/qcm2290.dtsi +++ b/arch/arm64/boot/dts/qcom/qcm2290.dtsi @@ -154,6 +154,7 @@ scm: scm { compatible = "qcom,scm-qcm2290", "qcom,scm"; clocks = <&rpmcc RPM_SMD_CE1_CLK>; clock-names = "core"; + qcom,dload-mode = <&tcsr_regs 0x13000>; #reset-cells = <1>; interconnects = <&system_noc MASTER_CRYPTO_CORE0 RPM_ALWAYS_TAG &bimc SLAVE_EBI1 RPM_ALWAYS_TAG>; From c2e07613b8d40f0ac60dd9b28c0dd15f9a298c11 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 29 Jul 2025 16:40:53 +0200 Subject: [PATCH 00354/11391] arm64: dts: qcom: sm8650: Add ACD levels for GPU Update GPU node to include acd level values. Signed-off-by: Neil Armstrong Reviewed-by: Akhil P Oommen Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250729-topic-sm8650-upstream-gpu-acd-level-v1-1-258090038a41@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8650.dtsi | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi index 34ec162db53d..d6794901f06b 100644 --- a/arch/arm64/boot/dts/qcom/sm8650.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi @@ -4127,72 +4127,84 @@ zap-shader { /* Speedbin needs more work on A740+, keep only lower freqs */ gpu_opp_table: opp-table { - compatible = "operating-points-v2"; + compatible = "operating-points-v2-adreno", + "operating-points-v2"; opp-231000000 { opp-hz = /bits/ 64 <231000000>; opp-level = ; opp-peak-kBps = <2136718>; + qcom,opp-acd-level = <0xc82f5ffd>; }; opp-310000000 { opp-hz = /bits/ 64 <310000000>; opp-level = ; opp-peak-kBps = <2136718>; + qcom,opp-acd-level = <0xc82c5ffd>; }; opp-366000000 { opp-hz = /bits/ 64 <366000000>; opp-level = ; opp-peak-kBps = <6074218>; + qcom,opp-acd-level = <0xc02e5ffd>; }; opp-422000000 { opp-hz = /bits/ 64 <422000000>; opp-level = ; opp-peak-kBps = <8171875>; + qcom,opp-acd-level = <0xc02d5ffd>; }; opp-500000000 { opp-hz = /bits/ 64 <500000000>; opp-level = ; opp-peak-kBps = <8171875>; + qcom,opp-acd-level = <0xc02a5ffd>; }; opp-578000000 { opp-hz = /bits/ 64 <578000000>; opp-level = ; opp-peak-kBps = <8171875>; + qcom,opp-acd-level = <0x882c5ffd>; }; opp-629000000 { opp-hz = /bits/ 64 <629000000>; opp-level = ; opp-peak-kBps = <10687500>; + qcom,opp-acd-level = <0x882a5ffd>; }; opp-680000000 { opp-hz = /bits/ 64 <680000000>; opp-level = ; opp-peak-kBps = <12449218>; + qcom,opp-acd-level = <0x882a5ffd>; }; opp-720000000 { opp-hz = /bits/ 64 <720000000>; opp-level = ; opp-peak-kBps = <12449218>; + qcom,opp-acd-level = <0x882a5ffd>; }; opp-770000000 { opp-hz = /bits/ 64 <770000000>; opp-level = ; opp-peak-kBps = <12449218>; + qcom,opp-acd-level = <0x882a5ffd>; }; opp-834000000 { opp-hz = /bits/ 64 <834000000>; opp-level = ; opp-peak-kBps = <14398437>; + qcom,opp-acd-level = <0x882a5ffd>; }; }; }; From d15cb624a60ab0119ec1b92d0a94f1cc305019e5 Mon Sep 17 00:00:00 2001 From: Ling Xu Date: Tue, 29 Jul 2025 08:42:59 +0530 Subject: [PATCH 00355/11391] arm64: dts: qcom: sm6150: Add ADSP and CDSP fastrpc nodes Add ADSP and CDSP fastrpc nodes for SM6150 platform. Signed-off-by: Ling Xu Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250729031259.4190916-1-quic_lxu5@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm6150.dtsi | 87 ++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index 591fcb740259..b66bc13c0b5e 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -3319,6 +3319,56 @@ glink-edge { mboxes = <&apss_shared 4>; label = "cdsp"; qcom,remote-pid = <5>; + + fastrpc { + compatible = "qcom,fastrpc"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + label = "cdsp"; + #address-cells = <1>; + #size-cells = <0>; + + compute-cb@1 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <1>; + iommus = <&apps_smmu 0x1081 0x0>; + dma-coherent; + }; + + compute-cb@2 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <2>; + iommus = <&apps_smmu 0x1082 0x0>; + dma-coherent; + }; + + compute-cb@3 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <3>; + iommus = <&apps_smmu 0x1083 0x0>; + dma-coherent; + }; + + compute-cb@4 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <4>; + iommus = <&apps_smmu 0x1084 0x0>; + dma-coherent; + }; + + compute-cb@5 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <5>; + iommus = <&apps_smmu 0x1085 0x0>; + dma-coherent; + }; + + compute-cb@6 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <6>; + iommus = <&apps_smmu 0x1086 0x0>; + dma-coherent; + }; + }; }; }; @@ -3991,6 +4041,43 @@ glink_edge: glink-edge { mboxes = <&apss_shared 24>; label = "lpass"; qcom,remote-pid = <2>; + + fastrpc { + compatible = "qcom,fastrpc"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + label = "adsp"; + #address-cells = <1>; + #size-cells = <0>; + + compute-cb@3 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <3>; + iommus = <&apps_smmu 0x1723 0x0>; + dma-coherent; + }; + + compute-cb@4 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <4>; + iommus = <&apps_smmu 0x1724 0x0>; + dma-coherent; + }; + + compute-cb@5 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <5>; + iommus = <&apps_smmu 0x1725 0x0>; + dma-coherent; + }; + + compute-cb@6 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <6>; + iommus = <&apps_smmu 0x1726 0x0>; + qcom,nsessions = <5>; + dma-coherent; + }; + }; }; }; }; From 1d363a6cf8a2627f31bc3609a0fa9d85dfb0d9dc Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Mon, 28 Jul 2025 11:34:26 +0200 Subject: [PATCH 00356/11391] arm64: dts: qcom: qcm2290: Enable HS eMMC timing modes The host controller supports HS200/HS400 and HS400 enhanced strobe mode. On RB1, this improves Linux eMMC read speed, from ~170MB/s to 300MB/s. Signed-off-by: Loic Poulain Reviewed-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250728093426.1413379-1-loic.poulain@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/qcm2290.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcm2290.dtsi b/arch/arm64/boot/dts/qcom/qcm2290.dtsi index 5edf9ca29ca0..eb489d0a684a 100644 --- a/arch/arm64/boot/dts/qcom/qcm2290.dtsi +++ b/arch/arm64/boot/dts/qcom/qcm2290.dtsi @@ -954,6 +954,11 @@ &bimc SLAVE_EBI1 RPM_ALWAYS_TAG>, qcom,ddr-config = <0x80040868>; bus-width = <8>; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + mmc-hs400-1_8v; + mmc-hs400-enhanced-strobe; + status = "disabled"; sdhc1_opp_table: opp-table { From 642af3f3d59003657483d60bb6b7229a43ff56e7 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Mon, 28 Jul 2025 11:33:52 +0200 Subject: [PATCH 00357/11391] arm64: dts: qcom: sc7280-chrome-common: Remove duplicate node sc7280.dtsi already includes the very same definition (bar 'memory@' vs 'video@', which doesn't matter). Remove the duplicate to fix a lot of dtbs W=1 warning instances (unique_unit_address_if_enabled). Signed-off-by: Konrad Dybcio Acked-by: Douglas Anderson Link: https://lore.kernel.org/r/20250728-topic-chrome_dt_fixup-v1-1-1fc38a95d5ea@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi b/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi index 8b4239f13748..84c6d662b54f 100644 --- a/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi @@ -44,11 +44,6 @@ camera_mem: memory@8ad00000 { reg = <0x0 0x8ad00000 0x0 0x500000>; no-map; }; - - venus_mem: memory@8b200000 { - reg = <0x0 0x8b200000 0x0 0x500000>; - no-map; - }; }; }; From d72cb0551d113a0a42e12dcdfdad78ade2c63f50 Mon Sep 17 00:00:00 2001 From: Krishna Kurapati Date: Mon, 28 Jul 2025 09:28:12 +0530 Subject: [PATCH 00358/11391] arm64: dts: qcom: sc7280: Flatten usb controller nodes Flatten usb controller nodes and update to using latest bindings and flattened driver approach. Signed-off-by: Krishna Kurapati Reviewed-by: Konrad Dybcio Tested-by: Konrad Dybcio # FP5 Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250728035812.2762957-1-krishna.kurapati@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/qcm6490-fairphone-fp5.dts | 6 +- arch/arm64/boot/dts/qcom/qcm6490-idp.dts | 7 +- .../boot/dts/qcom/qcm6490-shift-otter.dts | 6 +- arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts | 6 +- .../arm64/boot/dts/qcom/sc7280-herobrine.dtsi | 6 +- arch/arm64/boot/dts/qcom/sc7280-idp.dts | 6 +- arch/arm64/boot/dts/qcom/sc7280-idp.dtsi | 6 +- arch/arm64/boot/dts/qcom/sc7280.dtsi | 106 ++++++++---------- .../boot/dts/qcom/sm7325-nothing-spacewar.dts | 6 +- 9 files changed, 62 insertions(+), 93 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts b/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts index e115b6a52b29..f17ac3dc9b06 100644 --- a/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts +++ b/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts @@ -1364,12 +1364,10 @@ &ufs_mem_phy { }; &usb_1 { - status = "okay"; -}; - -&usb_1_dwc3 { dr_mode = "otg"; usb-role-switch; + + status = "okay"; }; &usb_1_dwc3_hs { diff --git a/arch/arm64/boot/dts/qcom/qcm6490-idp.dts b/arch/arm64/boot/dts/qcom/qcm6490-idp.dts index 7a155ef6492e..8ed6e28b0c29 100644 --- a/arch/arm64/boot/dts/qcom/qcm6490-idp.dts +++ b/arch/arm64/boot/dts/qcom/qcm6490-idp.dts @@ -751,12 +751,9 @@ &ufs_mem_phy { }; &usb_1 { - status = "okay"; -}; - -&usb_1_dwc3 { - /delete-property/ usb-role-switch; dr_mode = "peripheral"; + + status = "okay"; }; &usb_1_hsphy { diff --git a/arch/arm64/boot/dts/qcom/qcm6490-shift-otter.dts b/arch/arm64/boot/dts/qcom/qcm6490-shift-otter.dts index b9a0f7ac4d9c..eb8efba1b9dd 100644 --- a/arch/arm64/boot/dts/qcom/qcm6490-shift-otter.dts +++ b/arch/arm64/boot/dts/qcom/qcm6490-shift-otter.dts @@ -910,12 +910,10 @@ &ufs_mem_phy { }; &usb_1 { - status = "okay"; -}; - -&usb_1_dwc3 { dr_mode = "otg"; usb-role-switch; + + status = "okay"; }; &usb_1_dwc3_hs { diff --git a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts index 8f15be633946..7509c27bd3f8 100644 --- a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts +++ b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts @@ -1127,12 +1127,10 @@ bluetooth: bluetooth { }; &usb_1 { - status = "okay"; -}; - -&usb_1_dwc3 { dr_mode = "otg"; usb-role-switch; + + status = "okay"; }; &usb_1_dwc3_hs { diff --git a/arch/arm64/boot/dts/qcom/sc7280-herobrine.dtsi b/arch/arm64/boot/dts/qcom/sc7280-herobrine.dtsi index 2ba4ea60cb14..5c5e4f1dd221 100644 --- a/arch/arm64/boot/dts/qcom/sc7280-herobrine.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280-herobrine.dtsi @@ -621,15 +621,13 @@ CROS_STD_MAIN_KEYMAP }; &usb_1 { - status = "okay"; -}; - -&usb_1_dwc3 { dr_mode = "host"; #address-cells = <1>; #size-cells = <0>; + status = "okay"; + /* 2.x hub on port 1 */ usb_hub_2_x: hub@1 { compatible = "usbbda,5411"; diff --git a/arch/arm64/boot/dts/qcom/sc7280-idp.dts b/arch/arm64/boot/dts/qcom/sc7280-idp.dts index b5fe7356be48..3103f94cd685 100644 --- a/arch/arm64/boot/dts/qcom/sc7280-idp.dts +++ b/arch/arm64/boot/dts/qcom/sc7280-idp.dts @@ -81,11 +81,9 @@ channel@403 { }; &usb_2 { - status = "okay"; -}; - -&usb_2_dwc3 { dr_mode = "otg"; + + status = "okay"; }; &usb_2_hsphy { diff --git a/arch/arm64/boot/dts/qcom/sc7280-idp.dtsi b/arch/arm64/boot/dts/qcom/sc7280-idp.dtsi index 90e5b9ab5b84..ccd39a1baeda 100644 --- a/arch/arm64/boot/dts/qcom/sc7280-idp.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280-idp.dtsi @@ -520,11 +520,9 @@ &ufs_mem_phy { }; &usb_1 { - status = "okay"; -}; - -&usb_1_dwc3 { dr_mode = "host"; + + status = "okay"; }; &usb_1_hsphy { diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index 64a2abd30100..0fa8d34999a3 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -3711,14 +3711,10 @@ usb_dp_qmpphy_dp_in: endpoint { }; }; - usb_2: usb@8cf8800 { - compatible = "qcom,sc7280-dwc3", "qcom,dwc3"; - reg = <0 0x08cf8800 0 0x400>; + usb_2: usb@8c00000 { + compatible = "qcom,sc7280-dwc3", "qcom,snps-dwc3"; + reg = <0 0x08c00000 0 0xfc100>; status = "disabled"; - #address-cells = <2>; - #size-cells = <2>; - ranges; - dma-ranges; clocks = <&gcc GCC_CFG_NOC_USB3_SEC_AXI_CLK>, <&gcc GCC_USB30_SEC_MASTER_CLK>, @@ -3735,11 +3731,13 @@ usb_2: usb@8cf8800 { <&gcc GCC_USB30_SEC_MASTER_CLK>; assigned-clock-rates = <19200000>, <200000000>; - interrupts-extended = <&intc GIC_SPI 241 IRQ_TYPE_LEVEL_HIGH>, + interrupts-extended = <&intc GIC_SPI 242 IRQ_TYPE_LEVEL_HIGH>, + <&intc GIC_SPI 241 IRQ_TYPE_LEVEL_HIGH>, <&intc GIC_SPI 240 IRQ_TYPE_LEVEL_HIGH>, <&pdc 12 IRQ_TYPE_EDGE_BOTH>, <&pdc 13 IRQ_TYPE_EDGE_BOTH>; - interrupt-names = "pwr_event", + interrupt-names = "dwc_usb3", + "pwr_event", "hs_phy_irq", "dp_hs_phy_irq", "dm_hs_phy_irq"; @@ -3753,24 +3751,19 @@ usb_2: usb@8cf8800 { <&gem_noc MASTER_APPSS_PROC 0 &cnoc2 SLAVE_USB2 0>; interconnect-names = "usb-ddr", "apps-usb"; - usb_2_dwc3: usb@8c00000 { - compatible = "snps,dwc3"; - reg = <0 0x08c00000 0 0xe000>; - interrupts = ; - iommus = <&apps_smmu 0xa0 0x0>; - snps,dis_u2_susphy_quirk; - snps,dis_enblslpm_quirk; - snps,dis-u1-entry-quirk; - snps,dis-u2-entry-quirk; - phys = <&usb_2_hsphy>; - phy-names = "usb2-phy"; - maximum-speed = "high-speed"; - usb-role-switch; + iommus = <&apps_smmu 0xa0 0x0>; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; + snps,dis-u1-entry-quirk; + snps,dis-u2-entry-quirk; + phys = <&usb_2_hsphy>; + phy-names = "usb2-phy"; + maximum-speed = "high-speed"; + usb-role-switch; - port { - usb2_role_switch: endpoint { - remote-endpoint = <&eud_ep>; - }; + port { + usb2_role_switch: endpoint { + remote-endpoint = <&eud_ep>; }; }; }; @@ -4252,14 +4245,10 @@ compute-cb@14 { }; }; - usb_1: usb@a6f8800 { - compatible = "qcom,sc7280-dwc3", "qcom,dwc3"; - reg = <0 0x0a6f8800 0 0x400>; + usb_1: usb@a600000 { + compatible = "qcom,sc7280-dwc3", "qcom,snps-dwc3"; + reg = <0 0x0a600000 0 0xfc100>; status = "disabled"; - #address-cells = <2>; - #size-cells = <2>; - ranges; - dma-ranges; clocks = <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, <&gcc GCC_USB30_PRIM_MASTER_CLK>, @@ -4276,12 +4265,14 @@ usb_1: usb@a6f8800 { <&gcc GCC_USB30_PRIM_MASTER_CLK>; assigned-clock-rates = <19200000>, <200000000>; - interrupts-extended = <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>, + interrupts-extended = <&intc GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>, + <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>, <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, <&pdc 14 IRQ_TYPE_EDGE_BOTH>, <&pdc 15 IRQ_TYPE_EDGE_BOTH>, <&pdc 17 IRQ_TYPE_LEVEL_HIGH>; - interrupt-names = "pwr_event", + interrupt-names = "dwc_usb3", + "pwr_event", "hs_phy_irq", "dp_hs_phy_irq", "dm_hs_phy_irq", @@ -4298,37 +4289,32 @@ usb_1: usb@a6f8800 { wakeup-source; - usb_1_dwc3: usb@a600000 { - compatible = "snps,dwc3"; - reg = <0 0x0a600000 0 0xe000>; - interrupts = ; - iommus = <&apps_smmu 0xe0 0x0>; - snps,dis_u2_susphy_quirk; - snps,dis_enblslpm_quirk; - snps,parkmode-disable-ss-quirk; - snps,dis-u1-entry-quirk; - snps,dis-u2-entry-quirk; - phys = <&usb_1_hsphy>, <&usb_1_qmpphy QMP_USB43DP_USB3_PHY>; - phy-names = "usb2-phy", "usb3-phy"; - maximum-speed = "super-speed"; + iommus = <&apps_smmu 0xe0 0x0>; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; + snps,parkmode-disable-ss-quirk; + snps,dis-u1-entry-quirk; + snps,dis-u2-entry-quirk; + phys = <&usb_1_hsphy>, <&usb_1_qmpphy QMP_USB43DP_USB3_PHY>; + phy-names = "usb2-phy", "usb3-phy"; + maximum-speed = "super-speed"; - ports { - #address-cells = <1>; - #size-cells = <0>; + ports { + #address-cells = <1>; + #size-cells = <0>; - port@0 { - reg = <0>; + port@0 { + reg = <0>; - usb_1_dwc3_hs: endpoint { - }; + usb_1_dwc3_hs: endpoint { }; + }; - port@1 { - reg = <1>; + port@1 { + reg = <1>; - usb_1_dwc3_ss: endpoint { - remote-endpoint = <&usb_dp_qmpphy_usb_ss_in>; - }; + usb_1_dwc3_ss: endpoint { + remote-endpoint = <&usb_dp_qmpphy_usb_ss_in>; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sm7325-nothing-spacewar.dts b/arch/arm64/boot/dts/qcom/sm7325-nothing-spacewar.dts index befbb40228b5..f16b47b6a74c 100644 --- a/arch/arm64/boot/dts/qcom/sm7325-nothing-spacewar.dts +++ b/arch/arm64/boot/dts/qcom/sm7325-nothing-spacewar.dts @@ -1425,16 +1425,14 @@ &ufs_mem_phy { &usb_1 { /* USB 2.0 only */ qcom,select-utmi-as-pipe-clk; - status = "okay"; -}; - -&usb_1_dwc3 { dr_mode = "otg"; usb-role-switch; maximum-speed = "high-speed"; /* Remove USB3 phy */ phys = <&usb_1_hsphy>; phy-names = "usb2-phy"; + + status = "okay"; }; &usb_1_dwc3_hs { From 19e7aa0e9e46d0ad111a4af55b3d681b6ad945e0 Mon Sep 17 00:00:00 2001 From: Jens Reidel Date: Sun, 27 Jul 2025 01:56:46 +0200 Subject: [PATCH 00359/11391] soc: qcom: smem: Fix endian-unaware access of num_entries Add a missing le32_to_cpu when accessing num_entries, which is always a little endian integer. Fixes booting on Xiaomi Mi 9T (xiaomi-davinci) in big endian. Signed-off-by: Jens Reidel Link: https://lore.kernel.org/r/20250726235646.254730-1-adrian@mainlining.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/smem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index cf425930539e..c4c45f15dca4 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -898,7 +898,7 @@ static u32 qcom_smem_get_item_count(struct qcom_smem *smem) if (IS_ERR_OR_NULL(ptable)) return SMEM_ITEM_COUNT; - info = (struct smem_info *)&ptable->entry[ptable->num_entries]; + info = (struct smem_info *)&ptable->entry[le32_to_cpu(ptable->num_entries)]; if (memcmp(info->magic, SMEM_INFO_MAGIC, sizeof(info->magic))) return SMEM_ITEM_COUNT; From d41fb878adf64ef5dc4b4c25419e875483f62fe2 Mon Sep 17 00:00:00 2001 From: Ziyue Zhang Date: Fri, 25 Jul 2025 18:22:30 +0800 Subject: [PATCH 00360/11391] arm64: dts: qcom: sa8775p: remove aux clock from pcie phy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The gcc_aux_clk is used by the PCIe Root Complex (RC) and is not required by the PHY. The correct clock for the PHY is gcc_phy_aux_clk, which this patch uses to replace the incorrect reference. The distinction between AUX_CLK and PHY_AUX_CLK is important: AUX_CLK is typically used by the controller, while PHY_AUX_CLK is required by certain PHYs—particularly Gen4 QMP PHYs—for internal operations such as clock gating and power management. Some non-Gen4 Qualcomm PHYs also use PHY_AUX_CLK, but they do not require AUX_CLK. This change ensures proper clock configuration and avoids unnecessary dependencies. Signed-off-by: Ziyue Zhang Reviewed-by: Johan Hovold Fixes: 489f14be0e0a ("arm64: dts: qcom: sa8775p: Add pcie0 and pcie1 nodes") Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250725102231.3608298-3-ziyue.zhang@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/lemans.dtsi | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi index 322abd0294be..4ccaddb7794c 100644 --- a/arch/arm64/boot/dts/qcom/lemans.dtsi +++ b/arch/arm64/boot/dts/qcom/lemans.dtsi @@ -7719,16 +7719,18 @@ pcie0_phy: phy@1c04000 { compatible = "qcom,sa8775p-qmp-gen4x2-pcie-phy"; reg = <0x0 0x1c04000 0x0 0x2000>; - clocks = <&gcc GCC_PCIE_0_AUX_CLK>, + clocks = <&gcc GCC_PCIE_0_PHY_AUX_CLK>, <&gcc GCC_PCIE_0_CFG_AHB_CLK>, <&gcc GCC_PCIE_CLKREF_EN>, <&gcc GCC_PCIE_0_PHY_RCHNG_CLK>, <&gcc GCC_PCIE_0_PIPE_CLK>, - <&gcc GCC_PCIE_0_PIPEDIV2_CLK>, - <&gcc GCC_PCIE_0_PHY_AUX_CLK>; - - clock-names = "aux", "cfg_ahb", "ref", "rchng", "pipe", - "pipediv2", "phy_aux"; + <&gcc GCC_PCIE_0_PIPEDIV2_CLK>; + clock-names = "aux", + "cfg_ahb", + "ref", + "rchng", + "pipe", + "pipediv2"; assigned-clocks = <&gcc GCC_PCIE_0_PHY_RCHNG_CLK>; assigned-clock-rates = <100000000>; @@ -7885,16 +7887,18 @@ pcie1_phy: phy@1c14000 { compatible = "qcom,sa8775p-qmp-gen4x4-pcie-phy"; reg = <0x0 0x1c14000 0x0 0x4000>; - clocks = <&gcc GCC_PCIE_1_AUX_CLK>, + clocks = <&gcc GCC_PCIE_1_PHY_AUX_CLK>, <&gcc GCC_PCIE_1_CFG_AHB_CLK>, <&gcc GCC_PCIE_CLKREF_EN>, <&gcc GCC_PCIE_1_PHY_RCHNG_CLK>, <&gcc GCC_PCIE_1_PIPE_CLK>, - <&gcc GCC_PCIE_1_PIPEDIV2_CLK>, - <&gcc GCC_PCIE_1_PHY_AUX_CLK>; - - clock-names = "aux", "cfg_ahb", "ref", "rchng", "pipe", - "pipediv2", "phy_aux"; + <&gcc GCC_PCIE_1_PIPEDIV2_CLK>; + clock-names = "aux", + "cfg_ahb", + "ref", + "rchng", + "pipe", + "pipediv2"; assigned-clocks = <&gcc GCC_PCIE_1_PHY_RCHNG_CLK>; assigned-clock-rates = <100000000>; From f0370265b1d7fc169956927aa62c3abc375743b5 Mon Sep 17 00:00:00 2001 From: Ziyue Zhang Date: Fri, 25 Jul 2025 18:22:31 +0800 Subject: [PATCH 00361/11391] arm64: dts: qcom: sa8775p: add link_down reset for pcie SA8775p supports 'link_down' reset on hardware, so add it for both pcie0 and pcie1, which can provide a better user experience. Reviewed-by: Konrad Dybcio Reviewed-by: Johan Hovold Signed-off-by: Ziyue Zhang Link: https://lore.kernel.org/r/20250725102231.3608298-4-ziyue.zhang@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/lemans.dtsi | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi index 4ccaddb7794c..9b7fa4c932e3 100644 --- a/arch/arm64/boot/dts/qcom/lemans.dtsi +++ b/arch/arm64/boot/dts/qcom/lemans.dtsi @@ -7647,8 +7647,11 @@ pcie0: pcie@1c00000 { iommu-map = <0x0 &pcie_smmu 0x0000 0x1>, <0x100 &pcie_smmu 0x0001 0x1>; - resets = <&gcc GCC_PCIE_0_BCR>; - reset-names = "pci"; + resets = <&gcc GCC_PCIE_0_BCR>, + <&gcc GCC_PCIE_0_LINK_DOWN_BCR>; + reset-names = "pci", + "link_down"; + power-domains = <&gcc PCIE_0_GDSC>; phys = <&pcie0_phy>; @@ -7815,8 +7818,11 @@ pcie1: pcie@1c10000 { iommu-map = <0x0 &pcie_smmu 0x0080 0x1>, <0x100 &pcie_smmu 0x0081 0x1>; - resets = <&gcc GCC_PCIE_1_BCR>; - reset-names = "pci"; + resets = <&gcc GCC_PCIE_1_BCR>, + <&gcc GCC_PCIE_1_LINK_DOWN_BCR>; + reset-names = "pci", + "link_down"; + power-domains = <&gcc PCIE_1_GDSC>; phys = <&pcie1_phy>; From a42938e80357a13f8b8592111e63f2e33a919863 Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Fri, 8 Aug 2025 16:37:01 +0800 Subject: [PATCH 00362/11391] 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 c36748e8733ef9c5f4cd1d7c4327994e5b88b8df Mon Sep 17 00:00:00 2001 From: Wake Liu Date: Thu, 7 Aug 2025 16:09:32 +0800 Subject: [PATCH 00363/11391] selftests/net: Replace non-standard __WORDSIZE with sizeof(long) * 8 The `__WORDSIZE` macro, defined in the non-standard `` header, is a GNU extension and not universally available with all toolchains, such as Clang when used with musl libc. This can lead to build failures in environments where this header is missing. The intention of the code is to determine the bit width of a C `long`. Replace the non-portable `__WORDSIZE` with the standard and portable `sizeof(long) * 8` expression to achieve the same result. This change also removes the inclusion of the now-unused `` header. Signed-off-by: Wake Liu Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/psock_tpacket.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/testing/selftests/net/psock_tpacket.c b/tools/testing/selftests/net/psock_tpacket.c index 221270cee3ea..0dd909e325d9 100644 --- a/tools/testing/selftests/net/psock_tpacket.c +++ b/tools/testing/selftests/net/psock_tpacket.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -785,7 +784,7 @@ static int test_kernel_bit_width(void) static int test_user_bit_width(void) { - return __WORDSIZE; + return sizeof(long) * 8; } static const char *tpacket_str[] = { From bc4c0a48bdad7f225740b8e750fdc1da6d85e1eb Mon Sep 17 00:00:00 2001 From: Wake Liu Date: Sat, 9 Aug 2025 14:20:13 +0800 Subject: [PATCH 00364/11391] selftests/net: Ensure assert() triggers in psock_tpacket.c The get_next_frame() function in psock_tpacket.c was missing a return statement in its default switch case, leading to a compiler warning. This was caused by a `bug_on(1)` call, which is defined as an `assert()`, being compiled out because NDEBUG is defined during the build. Instead of adding a `return NULL;` which would silently hide the error and could lead to crashes later, this change restores the original author's intent. By adding `#undef NDEBUG` before including , we ensure the assertion is active and will cause the test to abort if this unreachable code is ever executed. Signed-off-by: Wake Liu Link: https://patch.msgid.link/20250809062013.2407822-1-wakel@google.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/psock_tpacket.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/net/psock_tpacket.c b/tools/testing/selftests/net/psock_tpacket.c index 0dd909e325d9..2938045c5cf9 100644 --- a/tools/testing/selftests/net/psock_tpacket.c +++ b/tools/testing/selftests/net/psock_tpacket.c @@ -22,6 +22,7 @@ * - TPACKET_V3: RX_RING */ +#undef NDEBUG #include #include #include From 45cca0f3c8208d210751ec91edf778a18336df88 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 24 Jul 2025 15:23:39 +0300 Subject: [PATCH 00365/11391] arm64: dts: qcom: sc8180x: add empty mdss_edp_out endpoint Follow the example of other DP controllers and also eDP controller on SC7280 and move mdss_edp_out endpoint declaration to the SoC DTSI. This slightly reduces the boilerplate in the platform DT files and also reduces the difference between DP and eDP controllers. Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250724-move-edp-endpoints-v1-1-6ca569812838@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts | 11 +++-------- arch/arm64/boot/dts/qcom/sc8180x-primus.dts | 11 +++-------- arch/arm64/boot/dts/qcom/sc8180x.dtsi | 7 +++++++ 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts b/arch/arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts index 21c2d25a2945..93dfb82c36da 100644 --- a/arch/arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts +++ b/arch/arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts @@ -457,15 +457,10 @@ auo_b140han06_in: endpoint { }; }; }; +}; - ports { - port@1 { - reg = <1>; - mdss_edp_out: endpoint { - remote-endpoint = <&auo_b140han06_in>; - }; - }; - }; +&mdss_edp_out { + remote-endpoint = <&auo_b140han06_in>; }; &pcie3 { diff --git a/arch/arm64/boot/dts/qcom/sc8180x-primus.dts b/arch/arm64/boot/dts/qcom/sc8180x-primus.dts index 7a4bd6955470..6808226b04e4 100644 --- a/arch/arm64/boot/dts/qcom/sc8180x-primus.dts +++ b/arch/arm64/boot/dts/qcom/sc8180x-primus.dts @@ -551,15 +551,10 @@ auo_b133han05_in: endpoint { }; }; }; +}; - ports { - port@1 { - reg = <1>; - mdss_edp_out: endpoint { - remote-endpoint = <&auo_b133han05_in>; - }; - }; - }; +&mdss_edp_out { + remote-endpoint = <&auo_b133han05_in>; }; &pcie1 { diff --git a/arch/arm64/boot/dts/qcom/sc8180x.dtsi b/arch/arm64/boot/dts/qcom/sc8180x.dtsi index f4f1d6a11960..836ac9455147 100644 --- a/arch/arm64/boot/dts/qcom/sc8180x.dtsi +++ b/arch/arm64/boot/dts/qcom/sc8180x.dtsi @@ -3423,6 +3423,13 @@ edp_in: endpoint { remote-endpoint = <&dpu_intf5_out>; }; }; + + port@1 { + reg = <1>; + + mdss_edp_out: endpoint { + }; + }; }; edp_opp_table: opp-table { From caaba55bb751133433c1b0806f5ce6b88359f0f7 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 24 Jul 2025 15:23:40 +0300 Subject: [PATCH 00366/11391] arm64: dts: qcom: sc8280xp: add empty mdss*_dp*_out endpoints Follow the example of other DP controllers and also eDP controller on SC7280 and move all mdss[01]_dp[0123]_out endpoints declaration to the SoC DTSI. This slightly reduces the boilerplate in the platform DT files and also reduces the difference between DP and eDP controllers. Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250724-move-edp-endpoints-v1-2-6ca569812838@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sa8295p-adp.dts | 78 ++++++------------- arch/arm64/boot/dts/qcom/sc8280xp-crd.dts | 11 +-- .../qcom/sc8280xp-lenovo-thinkpad-x13s.dts | 11 +-- .../dts/qcom/sc8280xp-microsoft-blackrock.dts | 13 +--- arch/arm64/boot/dts/qcom/sc8280xp.dtsi | 18 +++++ 5 files changed, 52 insertions(+), 79 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sa8295p-adp.dts b/arch/arm64/boot/dts/qcom/sa8295p-adp.dts index 2fd1dafe63ce..d5015ec4b23d 100644 --- a/arch/arm64/boot/dts/qcom/sa8295p-adp.dts +++ b/arch/arm64/boot/dts/qcom/sa8295p-adp.dts @@ -35,7 +35,7 @@ dp2-connector { port { dp2_connector_in: endpoint { - remote-endpoint = <&mdss1_dp0_phy_out>; + remote-endpoint = <&mdss1_dp0_out>; }; }; }; @@ -49,7 +49,7 @@ dp3-connector { port { dp3_connector_in: endpoint { - remote-endpoint = <&mdss1_dp1_phy_out>; + remote-endpoint = <&mdss1_dp1_out>; }; }; }; @@ -63,7 +63,7 @@ edp0-connector { port { edp0_connector_in: endpoint { - remote-endpoint = <&mdss0_dp2_phy_out>; + remote-endpoint = <&mdss0_dp2_out>; }; }; }; @@ -77,7 +77,7 @@ edp1-connector { port { edp1_connector_in: endpoint { - remote-endpoint = <&mdss0_dp3_phy_out>; + remote-endpoint = <&mdss0_dp3_out>; }; }; }; @@ -91,7 +91,7 @@ edp2-connector { port { edp2_connector_in: endpoint { - remote-endpoint = <&mdss1_dp2_phy_out>; + remote-endpoint = <&mdss1_dp2_out>; }; }; }; @@ -105,7 +105,7 @@ edp3-connector { port { edp3_connector_in: endpoint { - remote-endpoint = <&mdss1_dp3_phy_out>; + remote-endpoint = <&mdss1_dp3_out>; }; }; }; @@ -364,15 +364,10 @@ &mdss0_dp2 { data-lanes = <0 1 2 3>; status = "okay"; +}; - ports { - port@1 { - reg = <1>; - mdss0_dp2_phy_out: endpoint { - remote-endpoint = <&edp0_connector_in>; - }; - }; - }; +&mdss0_dp2_out { + remote-endpoint = <&edp0_connector_in>; }; &mdss0_dp2_phy { @@ -386,15 +381,10 @@ &mdss0_dp3 { data-lanes = <0 1 2 3>; status = "okay"; +}; - ports { - port@1 { - reg = <1>; - mdss0_dp3_phy_out: endpoint { - remote-endpoint = <&edp1_connector_in>; - }; - }; - }; +&mdss0_dp3_out { + remote-endpoint = <&edp1_connector_in>; }; &mdss0_dp3_phy { @@ -412,15 +402,10 @@ &mdss1_dp0 { data-lanes = <0 1 2 3>; status = "okay"; +}; - ports { - port@1 { - reg = <1>; - mdss1_dp0_phy_out: endpoint { - remote-endpoint = <&dp2_connector_in>; - }; - }; - }; +&mdss1_dp0_out { + remote-endpoint = <&dp2_connector_in>; }; &mdss1_dp0_phy { @@ -434,15 +419,10 @@ &mdss1_dp1 { data-lanes = <0 1 2 3>; status = "okay"; +}; - ports { - port@1 { - reg = <1>; - mdss1_dp1_phy_out: endpoint { - remote-endpoint = <&dp3_connector_in>; - }; - }; - }; +&mdss1_dp1_out { + remote-endpoint = <&dp3_connector_in>; }; &mdss1_dp1_phy { @@ -456,15 +436,10 @@ &mdss1_dp2 { data-lanes = <0 1 2 3>; status = "okay"; +}; - ports { - port@1 { - reg = <1>; - mdss1_dp2_phy_out: endpoint { - remote-endpoint = <&edp2_connector_in>; - }; - }; - }; +&mdss1_dp2_out { + remote-endpoint = <&edp2_connector_in>; }; &mdss1_dp2_phy { @@ -478,15 +453,10 @@ &mdss1_dp3 { data-lanes = <0 1 2 3>; status = "okay"; +}; - ports { - port@1 { - reg = <1>; - mdss1_dp3_phy_out: endpoint { - remote-endpoint = <&edp3_connector_in>; - }; - }; - }; +&mdss1_dp3_out { + remote-endpoint = <&edp3_connector_in>; }; &mdss1_dp3_phy { diff --git a/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts b/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts index 8e2c02497c05..bcbd668f562f 100644 --- a/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts +++ b/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts @@ -548,15 +548,10 @@ edp_panel_in: endpoint { }; }; }; +}; - ports { - port@1 { - reg = <1>; - mdss0_dp3_out: endpoint { - remote-endpoint = <&edp_panel_in>; - }; - }; - }; +&mdss0_dp3_out { + remote-endpoint = <&edp_panel_in>; }; &mdss0_dp3_phy { diff --git a/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts b/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts index cefecb7a23cf..0b479e98ba38 100644 --- a/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts +++ b/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts @@ -761,15 +761,10 @@ edp_panel_in: endpoint { }; }; }; +}; - ports { - port@1 { - reg = <1>; - mdss0_dp3_out: endpoint { - remote-endpoint = <&edp_panel_in>; - }; - }; - }; +&mdss0_dp3_out { + remote-endpoint = <&edp_panel_in>; }; &mdss0_dp3_phy { diff --git a/arch/arm64/boot/dts/qcom/sc8280xp-microsoft-blackrock.dts b/arch/arm64/boot/dts/qcom/sc8280xp-microsoft-blackrock.dts index 812251324002..29efbef5ef69 100644 --- a/arch/arm64/boot/dts/qcom/sc8280xp-microsoft-blackrock.dts +++ b/arch/arm64/boot/dts/qcom/sc8280xp-microsoft-blackrock.dts @@ -63,7 +63,7 @@ dp3_connector: connector { port { dp1_connector_in: endpoint { - remote-endpoint = <&mdss0_dp2_phy_out>; + remote-endpoint = <&mdss0_dp2_out>; }; }; }; @@ -602,15 +602,10 @@ &mdss0_dp2 { data-lanes = <0 1 2 3>; status = "okay"; +}; - ports { - port@1 { - reg = <1>; - mdss0_dp2_phy_out: endpoint { - remote-endpoint = <&dp1_connector_in>; - }; - }; - }; +&mdss0_dp2_out { + remote-endpoint = <&dp1_connector_in>; }; &mdss0_dp2_phy { diff --git a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi index 87555a119d94..421693208af0 100644 --- a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi +++ b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi @@ -4526,6 +4526,9 @@ mdss0_dp2_in: endpoint { port@1 { reg = <1>; + + mdss0_dp2_out: endpoint { + }; }; }; @@ -4598,6 +4601,9 @@ mdss0_dp3_in: endpoint { port@1 { reg = <1>; + + mdss0_dp3_out: endpoint { + }; }; }; @@ -5701,6 +5707,9 @@ mdss1_dp0_in: endpoint { port@1 { reg = <1>; + + mdss1_dp0_out: endpoint { + }; }; }; @@ -5773,6 +5782,9 @@ mdss1_dp1_in: endpoint { port@1 { reg = <1>; + + mdss1_dp1_out: endpoint { + }; }; }; @@ -5845,6 +5857,9 @@ mdss1_dp2_in: endpoint { port@1 { reg = <1>; + + mdss1_dp2_out: endpoint { + }; }; }; @@ -5917,6 +5932,9 @@ mdss1_dp3_in: endpoint { port@1 { reg = <1>; + + mdss1_dp3_out: endpoint { + }; }; }; From 91329efd132bf58aaecb33c07a4e566d9e95ff71 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 24 Jul 2025 15:23:41 +0300 Subject: [PATCH 00367/11391] arm64: dts: qcom: x1e80100: add empty mdss_dp3_out endpoint Follow the example of other DP controllers and also eDP controller on SC7280 and move mdss_dp3_out endpoint declaration to the SoC DTSI. This slightly reduces the boilerplate in the platform DT files and also reduces the difference between DP and eDP controllers. Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250724-move-edp-endpoints-v1-3-6ca569812838@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- .../arm64/boot/dts/qcom/x1-asus-zenbook-a14.dtsi | 16 +++++----------- arch/arm64/boot/dts/qcom/x1-crd.dtsi | 15 +++++---------- .../dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi | 16 +++++----------- .../boot/dts/qcom/x1e80100-asus-vivobook-s15.dts | 16 +++++----------- .../boot/dts/qcom/x1e80100-dell-xps13-9345.dts | 16 +++++----------- .../boot/dts/qcom/x1e80100-hp-omnibook-x14.dts | 16 +++++----------- .../dts/qcom/x1e80100-lenovo-yoga-slim7x.dts | 16 +++++----------- .../dts/qcom/x1e80100-microsoft-romulus.dtsi | 16 +++++----------- arch/arm64/boot/dts/qcom/x1e80100-qcp.dts | 15 +++++---------- arch/arm64/boot/dts/qcom/x1e80100.dtsi | 3 +++ 10 files changed, 48 insertions(+), 97 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/x1-asus-zenbook-a14.dtsi b/arch/arm64/boot/dts/qcom/x1-asus-zenbook-a14.dtsi index c771fd1d8029..16d045cf64c0 100644 --- a/arch/arm64/boot/dts/qcom/x1-asus-zenbook-a14.dtsi +++ b/arch/arm64/boot/dts/qcom/x1-asus-zenbook-a14.dtsi @@ -1019,19 +1019,13 @@ edp_panel_in: endpoint { }; }; }; +}; - ports { - port@1 { - reg = <1>; +&mdss_dp3_out { + data-lanes = <0 1 2 3>; + link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; - mdss_dp3_out: endpoint { - data-lanes = <0 1 2 3>; - link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; - - remote-endpoint = <&edp_panel_in>; - }; - }; - }; + remote-endpoint = <&edp_panel_in>; }; &mdss_dp3_phy { diff --git a/arch/arm64/boot/dts/qcom/x1-crd.dtsi b/arch/arm64/boot/dts/qcom/x1-crd.dtsi index 35d26d14b6bd..e3d2fc342bd1 100644 --- a/arch/arm64/boot/dts/qcom/x1-crd.dtsi +++ b/arch/arm64/boot/dts/qcom/x1-crd.dtsi @@ -1192,18 +1192,13 @@ edp_panel_in: endpoint { }; }; }; +}; - ports { - port@1 { - reg = <1>; - mdss_dp3_out: endpoint { - data-lanes = <0 1 2 3>; - link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; +&mdss_dp3_out { + data-lanes = <0 1 2 3>; + link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; - remote-endpoint = <&edp_panel_in>; - }; - }; - }; + remote-endpoint = <&edp_panel_in>; }; &mdss_dp3_phy { 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 2308d5a0e3af..4cf61c2a34e3 100644 --- a/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi +++ b/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi @@ -1024,19 +1024,13 @@ edp_panel_in: endpoint { }; }; }; +}; - ports { - port@1 { - reg = <1>; +&mdss_dp3_out { + data-lanes = <0 1 2 3>; + link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; - mdss_dp3_out: endpoint { - data-lanes = <0 1 2 3>; - link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; - - remote-endpoint = <&edp_panel_in>; - }; - }; - }; + remote-endpoint = <&edp_panel_in>; }; &mdss_dp3_phy { diff --git a/arch/arm64/boot/dts/qcom/x1e80100-asus-vivobook-s15.dts b/arch/arm64/boot/dts/qcom/x1e80100-asus-vivobook-s15.dts index 71b2cc6c392f..62eba17cdc87 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100-asus-vivobook-s15.dts +++ b/arch/arm64/boot/dts/qcom/x1e80100-asus-vivobook-s15.dts @@ -611,19 +611,13 @@ edp_panel_in: endpoint { }; }; }; +}; - ports { - port@1 { - reg = <1>; +&mdss_dp3_out { + data-lanes = <0 1 2 3>; + link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; - mdss_dp3_out: endpoint { - data-lanes = <0 1 2 3>; - link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; - - remote-endpoint = <&edp_panel_in>; - }; - }; - }; + remote-endpoint = <&edp_panel_in>; }; &mdss_dp3_phy { diff --git a/arch/arm64/boot/dts/qcom/x1e80100-dell-xps13-9345.dts b/arch/arm64/boot/dts/qcom/x1e80100-dell-xps13-9345.dts index fd00d1bf12e1..6b27067f0be6 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100-dell-xps13-9345.dts +++ b/arch/arm64/boot/dts/qcom/x1e80100-dell-xps13-9345.dts @@ -918,19 +918,13 @@ edp_panel_in: endpoint { }; }; }; +}; - ports { - port@1 { - reg = <1>; +&mdss_dp3_out { + data-lanes = <0 1 2 3>; + link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; - mdss_dp3_out: endpoint { - data-lanes = <0 1 2 3>; - link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; - - remote-endpoint = <&edp_panel_in>; - }; - }; - }; + remote-endpoint = <&edp_panel_in>; }; &mdss_dp3_phy { diff --git a/arch/arm64/boot/dts/qcom/x1e80100-hp-omnibook-x14.dts b/arch/arm64/boot/dts/qcom/x1e80100-hp-omnibook-x14.dts index 8d2a9b7f4730..f9ce2a63767c 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100-hp-omnibook-x14.dts +++ b/arch/arm64/boot/dts/qcom/x1e80100-hp-omnibook-x14.dts @@ -1060,19 +1060,13 @@ edp_panel_in: endpoint { }; }; }; +}; - ports { - port@1 { - reg = <1>; +&mdss_dp3_out { + data-lanes = <0 1 2 3>; + link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; - mdss_dp3_out: endpoint { - data-lanes = <0 1 2 3>; - link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; - - remote-endpoint = <&edp_panel_in>; - }; - }; - }; + remote-endpoint = <&edp_panel_in>; }; &mdss_dp3_phy { diff --git a/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts b/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts index d02f8d4f7baf..71becfc5e6f6 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts +++ b/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts @@ -1104,19 +1104,13 @@ edp_panel_in: endpoint { }; }; }; +}; - ports { - port@1 { - reg = <1>; +&mdss_dp3_out { + data-lanes = <0 1 2 3>; + link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; - mdss_dp3_out: endpoint { - data-lanes = <0 1 2 3>; - link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; - - remote-endpoint = <&edp_panel_in>; - }; - }; - }; + remote-endpoint = <&edp_panel_in>; }; &mdss_dp3_phy { diff --git a/arch/arm64/boot/dts/qcom/x1e80100-microsoft-romulus.dtsi b/arch/arm64/boot/dts/qcom/x1e80100-microsoft-romulus.dtsi index 0fd8516580b2..27dd5e4e9939 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100-microsoft-romulus.dtsi +++ b/arch/arm64/boot/dts/qcom/x1e80100-microsoft-romulus.dtsi @@ -981,19 +981,13 @@ edp_panel_in: endpoint { }; }; }; +}; - ports { - port@1 { - reg = <1>; +&mdss_dp3_out { + data-lanes = <0 1 2 3>; + link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; - mdss_dp3_out: endpoint { - data-lanes = <0 1 2 3>; - link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; - - remote-endpoint = <&edp_panel_in>; - }; - }; - }; + remote-endpoint = <&edp_panel_in>; }; &mdss_dp3_phy { diff --git a/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts b/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts index 71c44e37a44b..9369b76c668b 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts +++ b/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts @@ -929,18 +929,13 @@ edp_panel_in: endpoint { }; }; }; +}; - ports { - port@1 { - reg = <1>; - mdss_dp3_out: endpoint { - data-lanes = <0 1 2 3>; - link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; +&mdss_dp3_out { + data-lanes = <0 1 2 3>; + link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; - remote-endpoint = <&edp_panel_in>; - }; - }; - }; + remote-endpoint = <&edp_panel_in>; }; &mdss_dp3_phy { diff --git a/arch/arm64/boot/dts/qcom/x1e80100.dtsi b/arch/arm64/boot/dts/qcom/x1e80100.dtsi index c9fea040223b..4dba9f2b64f7 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100.dtsi +++ b/arch/arm64/boot/dts/qcom/x1e80100.dtsi @@ -5608,6 +5608,9 @@ mdss_dp3_in: endpoint { port@1 { reg = <1>; + + mdss_dp3_out: endpoint { + }; }; }; From c361adf09dfc77c62da4c0d548a8c8d50eb9c71d Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 24 Jul 2025 15:23:42 +0300 Subject: [PATCH 00368/11391] arm64: dts: qcom: move data-lanes to the DP-out endpoint Support for the data-lanes declaration in the DP node is deprecated. Move them to the corresponding endpoint as recommended by the current DP bindings. Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250724-move-edp-endpoints-v1-4-6ca569812838@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sa8295p-adp.dts | 18 ++++++------------ .../boot/dts/qcom/sc7180-acer-aspire1.dts | 3 +-- .../boot/dts/qcom/sc8180x-lenovo-flex-5g.dts | 3 +-- arch/arm64/boot/dts/qcom/sc8180x-primus.dts | 3 +-- 4 files changed, 9 insertions(+), 18 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sa8295p-adp.dts b/arch/arm64/boot/dts/qcom/sa8295p-adp.dts index d5015ec4b23d..64e59299672c 100644 --- a/arch/arm64/boot/dts/qcom/sa8295p-adp.dts +++ b/arch/arm64/boot/dts/qcom/sa8295p-adp.dts @@ -361,12 +361,11 @@ &mdss0 { }; &mdss0_dp2 { - data-lanes = <0 1 2 3>; - status = "okay"; }; &mdss0_dp2_out { + data-lanes = <0 1 2 3>; remote-endpoint = <&edp0_connector_in>; }; @@ -378,12 +377,11 @@ &mdss0_dp2_phy { }; &mdss0_dp3 { - data-lanes = <0 1 2 3>; - status = "okay"; }; &mdss0_dp3_out { + data-lanes = <0 1 2 3>; remote-endpoint = <&edp1_connector_in>; }; @@ -399,12 +397,11 @@ &mdss1 { }; &mdss1_dp0 { - data-lanes = <0 1 2 3>; - status = "okay"; }; &mdss1_dp0_out { + data-lanes = <0 1 2 3>; remote-endpoint = <&dp2_connector_in>; }; @@ -416,12 +413,11 @@ &mdss1_dp0_phy { }; &mdss1_dp1 { - data-lanes = <0 1 2 3>; - status = "okay"; }; &mdss1_dp1_out { + data-lanes = <0 1 2 3>; remote-endpoint = <&dp3_connector_in>; }; @@ -433,12 +429,11 @@ &mdss1_dp1_phy { }; &mdss1_dp2 { - data-lanes = <0 1 2 3>; - status = "okay"; }; &mdss1_dp2_out { + data-lanes = <0 1 2 3>; remote-endpoint = <&edp2_connector_in>; }; @@ -450,12 +445,11 @@ &mdss1_dp2_phy { }; &mdss1_dp3 { - data-lanes = <0 1 2 3>; - status = "okay"; }; &mdss1_dp3_out { + data-lanes = <0 1 2 3>; remote-endpoint = <&edp3_connector_in>; }; diff --git a/arch/arm64/boot/dts/qcom/sc7180-acer-aspire1.dts b/arch/arm64/boot/dts/qcom/sc7180-acer-aspire1.dts index 672ac4c3afa3..a70396f250f0 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-acer-aspire1.dts +++ b/arch/arm64/boot/dts/qcom/sc7180-acer-aspire1.dts @@ -438,8 +438,6 @@ &mdss { }; &mdss_dp { - data-lanes = <0 1>; - vdda-1p2-supply = <&vreg_l3c_1p2>; vdda-0p9-supply = <&vreg_l4a_0p8>; @@ -447,6 +445,7 @@ &mdss_dp { }; &mdss_dp_out { + data-lanes = <0 1>; remote-endpoint = <&ec_dp_in>; }; diff --git a/arch/arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts b/arch/arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts index 93dfb82c36da..08d0784d0cbb 100644 --- a/arch/arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts +++ b/arch/arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts @@ -436,8 +436,6 @@ &mdss_dp1_out { }; &mdss_edp { - data-lanes = <0 1 2 3>; - pinctrl-0 = <&edp_hpd_active>; pinctrl-names = "default"; @@ -460,6 +458,7 @@ auo_b140han06_in: endpoint { }; &mdss_edp_out { + data-lanes = <0 1 2 3>; remote-endpoint = <&auo_b140han06_in>; }; diff --git a/arch/arm64/boot/dts/qcom/sc8180x-primus.dts b/arch/arm64/boot/dts/qcom/sc8180x-primus.dts index 6808226b04e4..93de9fe918eb 100644 --- a/arch/arm64/boot/dts/qcom/sc8180x-primus.dts +++ b/arch/arm64/boot/dts/qcom/sc8180x-primus.dts @@ -531,8 +531,6 @@ &mdss_dp1_out { }; &mdss_edp { - data-lanes = <0 1 2 3>; - pinctrl-names = "default"; pinctrl-0 = <&edp_hpd_active>; @@ -554,6 +552,7 @@ auo_b133han05_in: endpoint { }; &mdss_edp_out { + data-lanes = <0 1 2 3>; remote-endpoint = <&auo_b133han05_in>; }; From afde4d8ea536964b7b7fe83cc6736e28475b6135 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 24 Jul 2025 15:23:43 +0300 Subject: [PATCH 00369/11391] arm64: dts: qcom: sc7180-acer-aspire1: drop deprecated DP supplies DP supplies were migrated to the corresponding DP PHY. Drop them from the DP controller node. Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250724-move-edp-endpoints-v1-5-6ca569812838@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc7180-acer-aspire1.dts | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sc7180-acer-aspire1.dts b/arch/arm64/boot/dts/qcom/sc7180-acer-aspire1.dts index a70396f250f0..ad342d8b7508 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-acer-aspire1.dts +++ b/arch/arm64/boot/dts/qcom/sc7180-acer-aspire1.dts @@ -438,9 +438,6 @@ &mdss { }; &mdss_dp { - vdda-1p2-supply = <&vreg_l3c_1p2>; - vdda-0p9-supply = <&vreg_l4a_0p8>; - status = "okay"; }; From 55863887fa1c536568dba6cb10b2cefc2b0e24cc Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Fri, 1 Aug 2025 15:51:05 +0200 Subject: [PATCH 00370/11391] arm64: dts: qcom: sc7280: Add q6usbdai node Add a node for q6usb which handles USB audio offloading, allowing to play audio via a USB-C headset with lower power consumption and enabling some other features. We also need to set num-hc-interrupters for the dwc3 for the q6usb to be able to use its sideband interrupter. Signed-off-by: Luca Weiss Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250801-fp5-usb-audio-offload-v1-1-240fc213d3d3@fairphone.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc7280.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index 0fa8d34999a3..97bb8a42a7b6 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -3855,6 +3855,13 @@ q6afecc: clock-controller { compatible = "qcom,q6afe-clocks"; #clock-cells = <2>; }; + + q6usbdai: usbd { + compatible = "qcom,q6usb"; + iommus = <&apps_smmu 0x180f 0x0>; + #sound-dai-cells = <1>; + qcom,usb-audio-intr-idx = /bits/ 16 <2>; + }; }; q6asm: service@7 { @@ -4295,6 +4302,7 @@ usb_1: usb@a600000 { snps,parkmode-disable-ss-quirk; snps,dis-u1-entry-quirk; snps,dis-u2-entry-quirk; + num-hc-interrupters = /bits/ 16 <3>; phys = <&usb_1_hsphy>, <&usb_1_qmpphy QMP_USB43DP_USB3_PHY>; phy-names = "usb2-phy", "usb3-phy"; maximum-speed = "super-speed"; From c183cebe69d0c02a3483d18b6953b29ff790c643 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Fri, 1 Aug 2025 15:51:06 +0200 Subject: [PATCH 00371/11391] arm64: dts: qcom: qcm6490-fairphone-fp5: Enable USB audio offload support Enable USB audio offloading which allows to play audio via a USB-C headset with lower power consumption and enabling some other features. This can be used like the following: $ amixer -c0 cset name='USB_RX Audio Mixer MultiMedia1' On $ aplay --device=plughw:0,0 test.wav Compared to regular playback to the USB sound card no xhci-hcd interrupts appear during playback, instead the ADSP will be handling the USB transfers. Signed-off-by: Luca Weiss Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250801-fp5-usb-audio-offload-v1-2-240fc213d3d3@fairphone.com Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/qcm6490-fairphone-fp5.dts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts b/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts index f17ac3dc9b06..519e458e1a89 100644 --- a/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts +++ b/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts @@ -1176,6 +1176,22 @@ platform { sound-dai = <&q6routing>; }; }; + + usb-dai-link { + link-name = "USB Playback"; + + codec { + sound-dai = <&q6usbdai USB_RX>; + }; + + cpu { + sound-dai = <&q6afedai USB_RX>; + }; + + platform { + sound-dai = <&q6routing>; + }; + }; }; &spi13 { From ce4d078469792d865b05f1687bca2eb24b77d84a Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Fri, 1 Aug 2025 15:40:59 +0200 Subject: [PATCH 00372/11391] arm64: dts: qcom: sm6350: Add rpmh-stats node The qcom_stats driver allows querying sleep stats from various remoteprocs. Add a node to enable it. Signed-off-by: Luca Weiss Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250801-sm6350-rpmh-stats-v1-1-f1fb649d1095@fairphone.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm6350.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6350.dtsi b/arch/arm64/boot/dts/qcom/sm6350.dtsi index 2d891a5640de..2493b9611dcb 100644 --- a/arch/arm64/boot/dts/qcom/sm6350.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6350.dtsi @@ -2487,6 +2487,11 @@ aoss_qmp: power-management@c300000 { #clock-cells = <0>; }; + sram@c3f0000 { + compatible = "qcom,rpmh-stats"; + reg = <0x0 0x0c3f0000 0x0 0x400>; + }; + spmi_bus: spmi@c440000 { compatible = "qcom,spmi-pmic-arb"; reg = <0x0 0x0c440000 0x0 0x1100>, From be477c3924f80809871df12f72d80d405d482ba2 Mon Sep 17 00:00:00 2001 From: Satya Priya Kakitapalli Date: Thu, 10 Jul 2025 18:30:39 +0530 Subject: [PATCH 00373/11391] 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 57e85e21b2729849407c9f851e30b2ff0f07523b Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Mon, 11 Aug 2025 14:51:01 -0700 Subject: [PATCH 00374/11391] MAINTAINERS: Add myself as virtual-cpufreq maintainer Forgot to update the MAINTAINERS file in the initial patch that landed the driver. Add myself as the maintainer for this driver. Signed-off-by: Saravana Kannan Signed-off-by: Viresh Kumar --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index fe168477caa4..6fac119a8e95 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6350,6 +6350,12 @@ F: kernel/sched/cpufreq*.c F: rust/kernel/cpufreq.rs F: tools/testing/selftests/cpufreq/ +CPU FREQUENCY DRIVERS - VIRTUAL MACHINE CPUFREQ +M: Saravana Kannan +L: linux-pm@vger.kernel.org +S: Maintained +F: drivers/cpufreq/virtual-cpufreq.c + CPU HOTPLUG M: Thomas Gleixner M: Peter Zijlstra From e98329896b5639f8437af8ff9316f20cb50d9187 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Wed, 2 Jul 2025 14:43:09 +0530 Subject: [PATCH 00375/11391] dt-bindings: cpufreq: cpufreq-qcom-hw: Add QCS615 compatible Document compatible for cpufreq hardware on Qualcomm QCS615 platform. Signed-off-by: Taniya Das Acked-by: Krzysztof Kozlowski Signed-off-by: Viresh Kumar --- Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.yaml b/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.yaml index e0242bed3342..2d42fc3d8ef8 100644 --- a/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.yaml +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.yaml @@ -22,6 +22,7 @@ properties: items: - enum: - qcom,qcm2290-cpufreq-hw + - qcom,qcs615-cpufreq-hw - qcom,sc7180-cpufreq-hw - qcom,sc8180x-cpufreq-hw - qcom,sdm670-cpufreq-hw @@ -132,6 +133,7 @@ allOf: compatible: contains: enum: + - qcom,qcs615-cpufreq-hw - qcom,qdu1000-cpufreq-epss - qcom,sa8255p-cpufreq-epss - qcom,sa8775p-cpufreq-epss From dd5d5a11bacb2eb0e00e0f6a9bc919afed2ec751 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 10 Jun 2025 11:42:30 +0200 Subject: [PATCH 00376/11391] docs: netlink: netlink-raw.rst: use :ref: instead of :doc: Currently, rt documents are referred with: Documentation/userspace-api/netlink/netlink-raw.rst: :doc:`rt-link<../../networking/netlink_spec/rt-link>` Documentation/userspace-api/netlink/netlink-raw.rst: :doc:`tc<../../networking/netlink_spec/tc>` Documentation/userspace-api/netlink/netlink-raw.rst: :doc:`tc<../../networking/netlink_spec/tc>` Having :doc: references with relative paths doesn't always work, as it may have troubles when O= is used. Also that's hard to maintain, and may break if we change the way rst files are generated from yaml. Better to use instead a reference for the netlink family. So, replace them by Sphinx cross-reference tag that are created by ynl_gen_rst.py. Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Donald Hunter --- Documentation/userspace-api/netlink/netlink-raw.rst | 6 +++--- tools/net/ynl/pyynl/ynl_gen_rst.py | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Documentation/userspace-api/netlink/netlink-raw.rst b/Documentation/userspace-api/netlink/netlink-raw.rst index 31fc91020eb3..aae296c170c5 100644 --- a/Documentation/userspace-api/netlink/netlink-raw.rst +++ b/Documentation/userspace-api/netlink/netlink-raw.rst @@ -62,8 +62,8 @@ Sub-messages ------------ Several raw netlink families such as -:doc:`rt-link<../../networking/netlink_spec/rt-link>` and -:doc:`tc<../../networking/netlink_spec/tc>` use attribute nesting as an +:ref:`rt-link` and +:ref:`tc` use attribute nesting as an abstraction to carry module specific information. Conceptually it looks as follows:: @@ -162,7 +162,7 @@ then this is an error. Nested struct definitions ------------------------- -Many raw netlink families such as :doc:`tc<../../networking/netlink_spec/tc>` +Many raw netlink families such as :ref:`tc` make use of nested struct definitions. The ``netlink-raw`` schema makes it possible to embed a struct within a struct definition using the ``struct`` property. For example, the following struct definition embeds the diff --git a/tools/net/ynl/pyynl/ynl_gen_rst.py b/tools/net/ynl/pyynl/ynl_gen_rst.py index 0cb6348e28d3..7bfb8ceeeefc 100755 --- a/tools/net/ynl/pyynl/ynl_gen_rst.py +++ b/tools/net/ynl/pyynl/ynl_gen_rst.py @@ -314,10 +314,11 @@ def parse_yaml(obj: Dict[str, Any]) -> str: # Main header - lines.append(rst_header()) - family = obj['name'] + lines.append(rst_header()) + lines.append(rst_label("netlink-" + family)) + title = f"Family ``{family}`` netlink specification" lines.append(rst_title(title)) lines.append(rst_paragraph(".. contents:: :depth: 3\n")) From f25f39e6d26644aeeef72433f67fc6d9e638c800 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 12 Jun 2025 08:27:00 +0200 Subject: [PATCH 00377/11391] tools: ynl_gen_rst.py: Split library from command line tool As we'll be using the Netlink specs parser inside a Sphinx extension, move the library part from the command line parser. While here, change the code which generates an index file to parse inputs from both .rst and .yaml extensions. With that, the tool can easily be tested with: tools/net/ynl/pyynl/ynl_gen_rst.py -x -o Documentation/netlink/specs/foo.rst Without needing to first generate a temp directory with the rst files. Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Donald Hunter --- tools/net/ynl/pyynl/lib/__init__.py | 2 + tools/net/ynl/pyynl/lib/doc_generator.py | 382 +++++++++++++++++++++++ tools/net/ynl/pyynl/ynl_gen_rst.py | 375 +--------------------- 3 files changed, 400 insertions(+), 359 deletions(-) create mode 100644 tools/net/ynl/pyynl/lib/doc_generator.py diff --git a/tools/net/ynl/pyynl/lib/__init__.py b/tools/net/ynl/pyynl/lib/__init__.py index 71518b9842ee..5f266ebe4526 100644 --- a/tools/net/ynl/pyynl/lib/__init__.py +++ b/tools/net/ynl/pyynl/lib/__init__.py @@ -4,6 +4,8 @@ from .nlspec import SpecAttr, SpecAttrSet, SpecEnumEntry, SpecEnumSet, \ SpecFamily, SpecOperation, SpecSubMessage, SpecSubMessageFormat from .ynl import YnlFamily, Netlink, NlError +from .doc_generator import YnlDocGenerator + __all__ = ["SpecAttr", "SpecAttrSet", "SpecEnumEntry", "SpecEnumSet", "SpecFamily", "SpecOperation", "SpecSubMessage", "SpecSubMessageFormat", "YnlFamily", "Netlink", "NlError"] diff --git a/tools/net/ynl/pyynl/lib/doc_generator.py b/tools/net/ynl/pyynl/lib/doc_generator.py new file mode 100644 index 000000000000..80e468086693 --- /dev/null +++ b/tools/net/ynl/pyynl/lib/doc_generator.py @@ -0,0 +1,382 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 +# -*- coding: utf-8; mode: python -*- + +""" + Class to auto generate the documentation for Netlink specifications. + + :copyright: Copyright (C) 2023 Breno Leitao + :license: GPL Version 2, June 1991 see linux/COPYING for details. + + This class performs extensive parsing to the Linux kernel's netlink YAML + spec files, in an effort to avoid needing to heavily mark up the original + YAML file. + + This code is split in two classes: + 1) RST formatters: Use to convert a string to a RST output + 2) YAML Netlink (YNL) doc generator: Generate docs from YAML data +""" + +from typing import Any, Dict, List +import os.path +import sys +import argparse +import logging +import yaml + + +# ============== +# RST Formatters +# ============== +class RstFormatters: + SPACE_PER_LEVEL = 4 + + @staticmethod + def headroom(level: int) -> str: + """Return space to format""" + return " " * (level * RstFormatters.SPACE_PER_LEVEL) + + + @staticmethod + def bold(text: str) -> str: + """Format bold text""" + return f"**{text}**" + + + @staticmethod + def inline(text: str) -> str: + """Format inline text""" + return f"``{text}``" + + + @staticmethod + def sanitize(text: str) -> str: + """Remove newlines and multiple spaces""" + # This is useful for some fields that are spread across multiple lines + return str(text).replace("\n", " ").strip() + + + def rst_fields(self, key: str, value: str, level: int = 0) -> str: + """Return a RST formatted field""" + return self.headroom(level) + f":{key}: {value}" + + + def rst_definition(self, key: str, value: Any, level: int = 0) -> str: + """Format a single rst definition""" + return self.headroom(level) + key + "\n" + self.headroom(level + 1) + str(value) + + + def rst_paragraph(self, paragraph: str, level: int = 0) -> str: + """Return a formatted paragraph""" + return self.headroom(level) + paragraph + + + def rst_bullet(self, item: str, level: int = 0) -> str: + """Return a formatted a bullet""" + return self.headroom(level) + f"- {item}" + + + @staticmethod + def rst_subsection(title: str) -> str: + """Add a sub-section to the document""" + return f"{title}\n" + "-" * len(title) + + + @staticmethod + def rst_subsubsection(title: str) -> str: + """Add a sub-sub-section to the document""" + return f"{title}\n" + "~" * len(title) + + + @staticmethod + def rst_section(namespace: str, prefix: str, title: str) -> str: + """Add a section to the document""" + return f".. _{namespace}-{prefix}-{title}:\n\n{title}\n" + "=" * len(title) + + + @staticmethod + def rst_subtitle(title: str) -> str: + """Add a subtitle to the document""" + return "\n" + "-" * len(title) + f"\n{title}\n" + "-" * len(title) + "\n\n" + + + @staticmethod + def rst_title(title: str) -> str: + """Add a title to the document""" + return "=" * len(title) + f"\n{title}\n" + "=" * len(title) + "\n\n" + + + def rst_list_inline(self, list_: List[str], level: int = 0) -> str: + """Format a list using inlines""" + return self.headroom(level) + "[" + ", ".join(self.inline(i) for i in list_) + "]" + + + @staticmethod + def rst_ref(namespace: str, prefix: str, name: str) -> str: + """Add a hyperlink to the document""" + mappings = {'enum': 'definition', + 'fixed-header': 'definition', + 'nested-attributes': 'attribute-set', + 'struct': 'definition'} + if prefix in mappings: + prefix = mappings[prefix] + return f":ref:`{namespace}-{prefix}-{name}`" + + + def rst_header(self) -> str: + """The headers for all the auto generated RST files""" + lines = [] + + lines.append(self.rst_paragraph(".. SPDX-License-Identifier: GPL-2.0")) + lines.append(self.rst_paragraph(".. NOTE: This document was auto-generated.\n\n")) + + return "\n".join(lines) + + + @staticmethod + def rst_toctree(maxdepth: int = 2) -> str: + """Generate a toctree RST primitive""" + lines = [] + + lines.append(".. toctree::") + lines.append(f" :maxdepth: {maxdepth}\n\n") + + return "\n".join(lines) + + + @staticmethod + def rst_label(title: str) -> str: + """Return a formatted label""" + return f".. _{title}:\n\n" + +# ======= +# Parsers +# ======= +class YnlDocGenerator: + + fmt = RstFormatters() + + def parse_mcast_group(self, mcast_group: List[Dict[str, Any]]) -> str: + """Parse 'multicast' group list and return a formatted string""" + lines = [] + for group in mcast_group: + lines.append(self.fmt.rst_bullet(group["name"])) + + return "\n".join(lines) + + + def parse_do(self, do_dict: Dict[str, Any], level: int = 0) -> str: + """Parse 'do' section and return a formatted string""" + lines = [] + for key in do_dict.keys(): + lines.append(self.fmt.rst_paragraph(self.fmt.bold(key), level + 1)) + if key in ['request', 'reply']: + lines.append(self.parse_do_attributes(do_dict[key], level + 1) + "\n") + else: + lines.append(self.fmt.headroom(level + 2) + do_dict[key] + "\n") + + return "\n".join(lines) + + + def parse_do_attributes(self, attrs: Dict[str, Any], level: int = 0) -> str: + """Parse 'attributes' section""" + if "attributes" not in attrs: + return "" + lines = [self.fmt.rst_fields("attributes", self.fmt.rst_list_inline(attrs["attributes"]), level + 1)] + + return "\n".join(lines) + + + def parse_operations(self, operations: List[Dict[str, Any]], namespace: str) -> str: + """Parse operations block""" + preprocessed = ["name", "doc", "title", "do", "dump", "flags"] + linkable = ["fixed-header", "attribute-set"] + lines = [] + + for operation in operations: + lines.append(self.fmt.rst_section(namespace, 'operation', operation["name"])) + lines.append(self.fmt.rst_paragraph(operation["doc"]) + "\n") + + for key in operation.keys(): + if key in preprocessed: + # Skip the special fields + continue + value = operation[key] + if key in linkable: + value = self.fmt.rst_ref(namespace, key, value) + lines.append(self.fmt.rst_fields(key, value, 0)) + if 'flags' in operation: + lines.append(self.fmt.rst_fields('flags', self.fmt.rst_list_inline(operation['flags']))) + + if "do" in operation: + lines.append(self.fmt.rst_paragraph(":do:", 0)) + lines.append(self.parse_do(operation["do"], 0)) + if "dump" in operation: + lines.append(self.fmt.rst_paragraph(":dump:", 0)) + lines.append(self.parse_do(operation["dump"], 0)) + + # New line after fields + lines.append("\n") + + return "\n".join(lines) + + + def parse_entries(self, entries: List[Dict[str, Any]], level: int) -> str: + """Parse a list of entries""" + ignored = ["pad"] + lines = [] + for entry in entries: + if isinstance(entry, dict): + # entries could be a list or a dictionary + field_name = entry.get("name", "") + if field_name in ignored: + continue + type_ = entry.get("type") + if type_: + field_name += f" ({self.fmt.inline(type_)})" + lines.append( + self.fmt.rst_fields(field_name, self.fmt.sanitize(entry.get("doc", "")), level) + ) + elif isinstance(entry, list): + lines.append(self.fmt.rst_list_inline(entry, level)) + else: + lines.append(self.fmt.rst_bullet(self.fmt.inline(self.fmt.sanitize(entry)), level)) + + lines.append("\n") + return "\n".join(lines) + + + def parse_definitions(self, defs: Dict[str, Any], namespace: str) -> str: + """Parse definitions section""" + preprocessed = ["name", "entries", "members"] + ignored = ["render-max"] # This is not printed + lines = [] + + for definition in defs: + lines.append(self.fmt.rst_section(namespace, 'definition', definition["name"])) + for k in definition.keys(): + if k in preprocessed + ignored: + continue + lines.append(self.fmt.rst_fields(k, self.fmt.sanitize(definition[k]), 0)) + + # Field list needs to finish with a new line + lines.append("\n") + if "entries" in definition: + lines.append(self.fmt.rst_paragraph(":entries:", 0)) + lines.append(self.parse_entries(definition["entries"], 1)) + if "members" in definition: + lines.append(self.fmt.rst_paragraph(":members:", 0)) + lines.append(self.parse_entries(definition["members"], 1)) + + return "\n".join(lines) + + + def parse_attr_sets(self, entries: List[Dict[str, Any]], namespace: str) -> str: + """Parse attribute from attribute-set""" + preprocessed = ["name", "type"] + linkable = ["enum", "nested-attributes", "struct", "sub-message"] + ignored = ["checks"] + lines = [] + + for entry in entries: + lines.append(self.fmt.rst_section(namespace, 'attribute-set', entry["name"])) + for attr in entry["attributes"]: + type_ = attr.get("type") + attr_line = attr["name"] + if type_: + # Add the attribute type in the same line + attr_line += f" ({self.fmt.inline(type_)})" + + lines.append(self.fmt.rst_subsubsection(attr_line)) + + for k in attr.keys(): + if k in preprocessed + ignored: + continue + if k in linkable: + value = self.fmt.rst_ref(namespace, k, attr[k]) + else: + value = self.fmt.sanitize(attr[k]) + lines.append(self.fmt.rst_fields(k, value, 0)) + lines.append("\n") + + return "\n".join(lines) + + + def parse_sub_messages(self, entries: List[Dict[str, Any]], namespace: str) -> str: + """Parse sub-message definitions""" + lines = [] + + for entry in entries: + lines.append(self.fmt.rst_section(namespace, 'sub-message', entry["name"])) + for fmt in entry["formats"]: + value = fmt["value"] + + lines.append(self.fmt.rst_bullet(self.fmt.bold(value))) + for attr in ['fixed-header', 'attribute-set']: + if attr in fmt: + lines.append(self.fmt.rst_fields(attr, + self.fmt.rst_ref(namespace, attr, fmt[attr]), + 1)) + lines.append("\n") + + return "\n".join(lines) + + + def parse_yaml(self, obj: Dict[str, Any]) -> str: + """Format the whole YAML into a RST string""" + lines = [] + + # Main header + + family = obj['name'] + + lines.append(self.fmt.rst_header()) + lines.append(self.fmt.rst_label("netlink-" + family)) + + title = f"Family ``{family}`` netlink specification" + lines.append(self.fmt.rst_title(title)) + lines.append(self.fmt.rst_paragraph(".. contents:: :depth: 3\n")) + + if "doc" in obj: + lines.append(self.fmt.rst_subtitle("Summary")) + lines.append(self.fmt.rst_paragraph(obj["doc"], 0)) + + # Operations + if "operations" in obj: + lines.append(self.fmt.rst_subtitle("Operations")) + lines.append(self.parse_operations(obj["operations"]["list"], family)) + + # Multicast groups + if "mcast-groups" in obj: + lines.append(self.fmt.rst_subtitle("Multicast groups")) + lines.append(self.parse_mcast_group(obj["mcast-groups"]["list"])) + + # Definitions + if "definitions" in obj: + lines.append(self.fmt.rst_subtitle("Definitions")) + lines.append(self.parse_definitions(obj["definitions"], family)) + + # Attributes set + if "attribute-sets" in obj: + lines.append(self.fmt.rst_subtitle("Attribute sets")) + lines.append(self.parse_attr_sets(obj["attribute-sets"], family)) + + # Sub-messages + if "sub-messages" in obj: + lines.append(self.fmt.rst_subtitle("Sub-messages")) + lines.append(self.parse_sub_messages(obj["sub-messages"], family)) + + return "\n".join(lines) + + + # Main functions + # ============== + + + def parse_yaml_file(self, filename: str) -> str: + """Transform the YAML specified by filename into an RST-formatted string""" + with open(filename, "r", encoding="utf-8") as spec_file: + yaml_data = yaml.safe_load(spec_file) + content = self.parse_yaml(yaml_data) + + return content diff --git a/tools/net/ynl/pyynl/ynl_gen_rst.py b/tools/net/ynl/pyynl/ynl_gen_rst.py index 7bfb8ceeeefc..010315fad498 100755 --- a/tools/net/ynl/pyynl/ynl_gen_rst.py +++ b/tools/net/ynl/pyynl/ynl_gen_rst.py @@ -10,354 +10,17 @@ This script performs extensive parsing to the Linux kernel's netlink YAML spec files, in an effort to avoid needing to heavily mark up the original - YAML file. - - This code is split in three big parts: - 1) RST formatters: Use to convert a string to a RST output - 2) Parser helpers: Functions to parse the YAML data structure - 3) Main function and small helpers + YAML file. It uses the library code from scripts/lib. """ -from typing import Any, Dict, List import os.path +import pathlib import sys import argparse import logging -import yaml - - -SPACE_PER_LEVEL = 4 - - -# RST Formatters -# ============== -def headroom(level: int) -> str: - """Return space to format""" - return " " * (level * SPACE_PER_LEVEL) - - -def bold(text: str) -> str: - """Format bold text""" - return f"**{text}**" - - -def inline(text: str) -> str: - """Format inline text""" - return f"``{text}``" - - -def sanitize(text: str) -> str: - """Remove newlines and multiple spaces""" - # This is useful for some fields that are spread across multiple lines - return str(text).replace("\n", " ").strip() - - -def rst_fields(key: str, value: str, level: int = 0) -> str: - """Return a RST formatted field""" - return headroom(level) + f":{key}: {value}" - - -def rst_definition(key: str, value: Any, level: int = 0) -> str: - """Format a single rst definition""" - return headroom(level) + key + "\n" + headroom(level + 1) + str(value) - - -def rst_paragraph(paragraph: str, level: int = 0) -> str: - """Return a formatted paragraph""" - return headroom(level) + paragraph - - -def rst_bullet(item: str, level: int = 0) -> str: - """Return a formatted a bullet""" - return headroom(level) + f"- {item}" - - -def rst_subsection(title: str) -> str: - """Add a sub-section to the document""" - return f"{title}\n" + "-" * len(title) - - -def rst_subsubsection(title: str) -> str: - """Add a sub-sub-section to the document""" - return f"{title}\n" + "~" * len(title) - - -def rst_section(namespace: str, prefix: str, title: str) -> str: - """Add a section to the document""" - return f".. _{namespace}-{prefix}-{title}:\n\n{title}\n" + "=" * len(title) - - -def rst_subtitle(title: str) -> str: - """Add a subtitle to the document""" - return "\n" + "-" * len(title) + f"\n{title}\n" + "-" * len(title) + "\n\n" - - -def rst_title(title: str) -> str: - """Add a title to the document""" - return "=" * len(title) + f"\n{title}\n" + "=" * len(title) + "\n\n" - - -def rst_list_inline(list_: List[str], level: int = 0) -> str: - """Format a list using inlines""" - return headroom(level) + "[" + ", ".join(inline(i) for i in list_) + "]" - - -def rst_ref(namespace: str, prefix: str, name: str) -> str: - """Add a hyperlink to the document""" - mappings = {'enum': 'definition', - 'fixed-header': 'definition', - 'nested-attributes': 'attribute-set', - 'struct': 'definition'} - if prefix in mappings: - prefix = mappings[prefix] - return f":ref:`{namespace}-{prefix}-{name}`" - - -def rst_header() -> str: - """The headers for all the auto generated RST files""" - lines = [] - - lines.append(rst_paragraph(".. SPDX-License-Identifier: GPL-2.0")) - lines.append(rst_paragraph(".. NOTE: This document was auto-generated.\n\n")) - - return "\n".join(lines) - - -def rst_toctree(maxdepth: int = 2) -> str: - """Generate a toctree RST primitive""" - lines = [] - - lines.append(".. toctree::") - lines.append(f" :maxdepth: {maxdepth}\n\n") - - return "\n".join(lines) - - -def rst_label(title: str) -> str: - """Return a formatted label""" - return f".. _{title}:\n\n" - - -# Parsers -# ======= - - -def parse_mcast_group(mcast_group: List[Dict[str, Any]]) -> str: - """Parse 'multicast' group list and return a formatted string""" - lines = [] - for group in mcast_group: - lines.append(rst_bullet(group["name"])) - - return "\n".join(lines) - - -def parse_do(do_dict: Dict[str, Any], level: int = 0) -> str: - """Parse 'do' section and return a formatted string""" - lines = [] - for key in do_dict.keys(): - lines.append(rst_paragraph(bold(key), level + 1)) - if key in ['request', 'reply']: - lines.append(parse_do_attributes(do_dict[key], level + 1) + "\n") - else: - lines.append(headroom(level + 2) + do_dict[key] + "\n") - - return "\n".join(lines) - - -def parse_do_attributes(attrs: Dict[str, Any], level: int = 0) -> str: - """Parse 'attributes' section""" - if "attributes" not in attrs: - return "" - lines = [rst_fields("attributes", rst_list_inline(attrs["attributes"]), level + 1)] - - return "\n".join(lines) - - -def parse_operations(operations: List[Dict[str, Any]], namespace: str) -> str: - """Parse operations block""" - preprocessed = ["name", "doc", "title", "do", "dump", "flags"] - linkable = ["fixed-header", "attribute-set"] - lines = [] - - for operation in operations: - lines.append(rst_section(namespace, 'operation', operation["name"])) - lines.append(rst_paragraph(operation["doc"]) + "\n") - - for key in operation.keys(): - if key in preprocessed: - # Skip the special fields - continue - value = operation[key] - if key in linkable: - value = rst_ref(namespace, key, value) - lines.append(rst_fields(key, value, 0)) - if 'flags' in operation: - lines.append(rst_fields('flags', rst_list_inline(operation['flags']))) - - if "do" in operation: - lines.append(rst_paragraph(":do:", 0)) - lines.append(parse_do(operation["do"], 0)) - if "dump" in operation: - lines.append(rst_paragraph(":dump:", 0)) - lines.append(parse_do(operation["dump"], 0)) - - # New line after fields - lines.append("\n") - - return "\n".join(lines) - - -def parse_entries(entries: List[Dict[str, Any]], level: int) -> str: - """Parse a list of entries""" - ignored = ["pad"] - lines = [] - for entry in entries: - if isinstance(entry, dict): - # entries could be a list or a dictionary - field_name = entry.get("name", "") - if field_name in ignored: - continue - type_ = entry.get("type") - if type_: - field_name += f" ({inline(type_)})" - lines.append( - rst_fields(field_name, sanitize(entry.get("doc", "")), level) - ) - elif isinstance(entry, list): - lines.append(rst_list_inline(entry, level)) - else: - lines.append(rst_bullet(inline(sanitize(entry)), level)) - - lines.append("\n") - return "\n".join(lines) - - -def parse_definitions(defs: Dict[str, Any], namespace: str) -> str: - """Parse definitions section""" - preprocessed = ["name", "entries", "members"] - ignored = ["render-max"] # This is not printed - lines = [] - - for definition in defs: - lines.append(rst_section(namespace, 'definition', definition["name"])) - for k in definition.keys(): - if k in preprocessed + ignored: - continue - lines.append(rst_fields(k, sanitize(definition[k]), 0)) - - # Field list needs to finish with a new line - lines.append("\n") - if "entries" in definition: - lines.append(rst_paragraph(":entries:", 0)) - lines.append(parse_entries(definition["entries"], 1)) - if "members" in definition: - lines.append(rst_paragraph(":members:", 0)) - lines.append(parse_entries(definition["members"], 1)) - - return "\n".join(lines) - - -def parse_attr_sets(entries: List[Dict[str, Any]], namespace: str) -> str: - """Parse attribute from attribute-set""" - preprocessed = ["name", "type"] - linkable = ["enum", "nested-attributes", "struct", "sub-message"] - ignored = ["checks"] - lines = [] - - for entry in entries: - lines.append(rst_section(namespace, 'attribute-set', entry["name"])) - for attr in entry["attributes"]: - type_ = attr.get("type") - attr_line = attr["name"] - if type_: - # Add the attribute type in the same line - attr_line += f" ({inline(type_)})" - - lines.append(rst_subsubsection(attr_line)) - - for k in attr.keys(): - if k in preprocessed + ignored: - continue - if k in linkable: - value = rst_ref(namespace, k, attr[k]) - else: - value = sanitize(attr[k]) - lines.append(rst_fields(k, value, 0)) - lines.append("\n") - - return "\n".join(lines) - - -def parse_sub_messages(entries: List[Dict[str, Any]], namespace: str) -> str: - """Parse sub-message definitions""" - lines = [] - - for entry in entries: - lines.append(rst_section(namespace, 'sub-message', entry["name"])) - for fmt in entry["formats"]: - value = fmt["value"] - - lines.append(rst_bullet(bold(value))) - for attr in ['fixed-header', 'attribute-set']: - if attr in fmt: - lines.append(rst_fields(attr, - rst_ref(namespace, attr, fmt[attr]), - 1)) - lines.append("\n") - - return "\n".join(lines) - - -def parse_yaml(obj: Dict[str, Any]) -> str: - """Format the whole YAML into a RST string""" - lines = [] - - # Main header - - family = obj['name'] - - lines.append(rst_header()) - lines.append(rst_label("netlink-" + family)) - - title = f"Family ``{family}`` netlink specification" - lines.append(rst_title(title)) - lines.append(rst_paragraph(".. contents:: :depth: 3\n")) - - if "doc" in obj: - lines.append(rst_subtitle("Summary")) - lines.append(rst_paragraph(obj["doc"], 0)) - - # Operations - if "operations" in obj: - lines.append(rst_subtitle("Operations")) - lines.append(parse_operations(obj["operations"]["list"], family)) - - # Multicast groups - if "mcast-groups" in obj: - lines.append(rst_subtitle("Multicast groups")) - lines.append(parse_mcast_group(obj["mcast-groups"]["list"])) - - # Definitions - if "definitions" in obj: - lines.append(rst_subtitle("Definitions")) - lines.append(parse_definitions(obj["definitions"], family)) - - # Attributes set - if "attribute-sets" in obj: - lines.append(rst_subtitle("Attribute sets")) - lines.append(parse_attr_sets(obj["attribute-sets"], family)) - - # Sub-messages - if "sub-messages" in obj: - lines.append(rst_subtitle("Sub-messages")) - lines.append(parse_sub_messages(obj["sub-messages"], family)) - - return "\n".join(lines) - - -# Main functions -# ============== +sys.path.append(pathlib.Path(__file__).resolve().parent.as_posix()) +from lib import YnlDocGenerator # pylint: disable=C0413 def parse_arguments() -> argparse.Namespace: """Parse arguments from user""" @@ -392,15 +55,6 @@ def parse_arguments() -> argparse.Namespace: return args -def parse_yaml_file(filename: str) -> str: - """Transform the YAML specified by filename into an RST-formatted string""" - with open(filename, "r", encoding="utf-8") as spec_file: - yaml_data = yaml.safe_load(spec_file) - content = parse_yaml(yaml_data) - - return content - - def write_to_rstfile(content: str, filename: str) -> None: """Write the generated content into an RST file""" logging.debug("Saving RST file to %s", filename) @@ -409,21 +63,22 @@ def write_to_rstfile(content: str, filename: str) -> None: rst_file.write(content) -def generate_main_index_rst(output: str) -> None: +def generate_main_index_rst(parser: YnlDocGenerator, output: str) -> None: """Generate the `networking_spec/index` content and write to the file""" lines = [] - lines.append(rst_header()) - lines.append(rst_label("specs")) - lines.append(rst_title("Netlink Family Specifications")) - lines.append(rst_toctree(1)) + lines.append(parser.fmt.rst_header()) + lines.append(parser.fmt.rst_label("specs")) + lines.append(parser.fmt.rst_title("Netlink Family Specifications")) + lines.append(parser.fmt.rst_toctree(1)) index_dir = os.path.dirname(output) logging.debug("Looking for .rst files in %s", index_dir) for filename in sorted(os.listdir(index_dir)): - if not filename.endswith(".rst") or filename == "index.rst": + base, ext = os.path.splitext(filename) + if filename == "index.rst" or ext not in [".rst", ".yaml"]: continue - lines.append(f" {filename.replace('.rst', '')}\n") + lines.append(f" {base}\n") logging.debug("Writing an index file at %s", output) write_to_rstfile("".join(lines), output) @@ -434,10 +89,12 @@ def main() -> None: args = parse_arguments() + parser = YnlDocGenerator() + if args.input: logging.debug("Parsing %s", args.input) try: - content = parse_yaml_file(os.path.join(args.input)) + content = parser.parse_yaml_file(os.path.join(args.input)) except Exception as exception: logging.warning("Failed to parse %s.", args.input) logging.warning(exception) @@ -447,7 +104,7 @@ def main() -> None: if args.index: # Generate the index RST file - generate_main_index_rst(args.output) + generate_main_index_rst(parser, args.output) if __name__ == "__main__": From beaea9c4ba2d8ef1b10223dc3a75a7d7be3e5cd9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 12 Jun 2025 10:34:30 +0200 Subject: [PATCH 00378/11391] docs: netlink: index.rst: add a netlink index file Instead of generating the index file, use glob to automatically include all data from yaml. Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Donald Hunter --- Documentation/netlink/specs/index.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 Documentation/netlink/specs/index.rst diff --git a/Documentation/netlink/specs/index.rst b/Documentation/netlink/specs/index.rst new file mode 100644 index 000000000000..7f7cf4a096f2 --- /dev/null +++ b/Documentation/netlink/specs/index.rst @@ -0,0 +1,13 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. _specs: + +============================= +Netlink Family Specifications +============================= + +.. toctree:: + :maxdepth: 1 + :glob: + + * From 3a3b8a144754858b59f108c7dc80eb613bf6fe64 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 13 Jun 2025 16:09:05 +0200 Subject: [PATCH 00379/11391] tools: ynl_gen_rst.py: cleanup coding style Cleanup some coding style issues pointed by pylint and flake8. No functional changes. Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Breno Leitao Reviewed-by: Donald Hunter --- tools/net/ynl/pyynl/lib/doc_generator.py | 72 ++++++++---------------- 1 file changed, 25 insertions(+), 47 deletions(-) diff --git a/tools/net/ynl/pyynl/lib/doc_generator.py b/tools/net/ynl/pyynl/lib/doc_generator.py index 80e468086693..474b2b78c7bc 100644 --- a/tools/net/ynl/pyynl/lib/doc_generator.py +++ b/tools/net/ynl/pyynl/lib/doc_generator.py @@ -18,17 +18,12 @@ """ from typing import Any, Dict, List -import os.path -import sys -import argparse -import logging import yaml -# ============== -# RST Formatters -# ============== class RstFormatters: + """RST Formatters""" + SPACE_PER_LEVEL = 4 @staticmethod @@ -36,81 +31,67 @@ class RstFormatters: """Return space to format""" return " " * (level * RstFormatters.SPACE_PER_LEVEL) - @staticmethod def bold(text: str) -> str: """Format bold text""" return f"**{text}**" - @staticmethod def inline(text: str) -> str: """Format inline text""" return f"``{text}``" - @staticmethod def sanitize(text: str) -> str: """Remove newlines and multiple spaces""" # This is useful for some fields that are spread across multiple lines return str(text).replace("\n", " ").strip() - def rst_fields(self, key: str, value: str, level: int = 0) -> str: """Return a RST formatted field""" return self.headroom(level) + f":{key}: {value}" - def rst_definition(self, key: str, value: Any, level: int = 0) -> str: """Format a single rst definition""" return self.headroom(level) + key + "\n" + self.headroom(level + 1) + str(value) - def rst_paragraph(self, paragraph: str, level: int = 0) -> str: """Return a formatted paragraph""" return self.headroom(level) + paragraph - def rst_bullet(self, item: str, level: int = 0) -> str: """Return a formatted a bullet""" return self.headroom(level) + f"- {item}" - @staticmethod def rst_subsection(title: str) -> str: """Add a sub-section to the document""" return f"{title}\n" + "-" * len(title) - @staticmethod def rst_subsubsection(title: str) -> str: """Add a sub-sub-section to the document""" return f"{title}\n" + "~" * len(title) - @staticmethod def rst_section(namespace: str, prefix: str, title: str) -> str: """Add a section to the document""" return f".. _{namespace}-{prefix}-{title}:\n\n{title}\n" + "=" * len(title) - @staticmethod def rst_subtitle(title: str) -> str: """Add a subtitle to the document""" return "\n" + "-" * len(title) + f"\n{title}\n" + "-" * len(title) + "\n\n" - @staticmethod def rst_title(title: str) -> str: """Add a title to the document""" return "=" * len(title) + f"\n{title}\n" + "=" * len(title) + "\n\n" - def rst_list_inline(self, list_: List[str], level: int = 0) -> str: """Format a list using inlines""" return self.headroom(level) + "[" + ", ".join(self.inline(i) for i in list_) + "]" - @staticmethod def rst_ref(namespace: str, prefix: str, name: str) -> str: """Add a hyperlink to the document""" @@ -122,7 +103,6 @@ class RstFormatters: prefix = mappings[prefix] return f":ref:`{namespace}-{prefix}-{name}`" - def rst_header(self) -> str: """The headers for all the auto generated RST files""" lines = [] @@ -132,7 +112,6 @@ class RstFormatters: return "\n".join(lines) - @staticmethod def rst_toctree(maxdepth: int = 2) -> str: """Generate a toctree RST primitive""" @@ -143,16 +122,13 @@ class RstFormatters: return "\n".join(lines) - @staticmethod def rst_label(title: str) -> str: """Return a formatted label""" return f".. _{title}:\n\n" -# ======= -# Parsers -# ======= class YnlDocGenerator: + """YAML Netlink specs Parser""" fmt = RstFormatters() @@ -164,7 +140,6 @@ class YnlDocGenerator: return "\n".join(lines) - def parse_do(self, do_dict: Dict[str, Any], level: int = 0) -> str: """Parse 'do' section and return a formatted string""" lines = [] @@ -177,16 +152,16 @@ class YnlDocGenerator: return "\n".join(lines) - def parse_do_attributes(self, attrs: Dict[str, Any], level: int = 0) -> str: """Parse 'attributes' section""" if "attributes" not in attrs: return "" - lines = [self.fmt.rst_fields("attributes", self.fmt.rst_list_inline(attrs["attributes"]), level + 1)] + lines = [self.fmt.rst_fields("attributes", + self.fmt.rst_list_inline(attrs["attributes"]), + level + 1)] return "\n".join(lines) - def parse_operations(self, operations: List[Dict[str, Any]], namespace: str) -> str: """Parse operations block""" preprocessed = ["name", "doc", "title", "do", "dump", "flags"] @@ -194,7 +169,8 @@ class YnlDocGenerator: lines = [] for operation in operations: - lines.append(self.fmt.rst_section(namespace, 'operation', operation["name"])) + lines.append(self.fmt.rst_section(namespace, 'operation', + operation["name"])) lines.append(self.fmt.rst_paragraph(operation["doc"]) + "\n") for key in operation.keys(): @@ -206,7 +182,8 @@ class YnlDocGenerator: value = self.fmt.rst_ref(namespace, key, value) lines.append(self.fmt.rst_fields(key, value, 0)) if 'flags' in operation: - lines.append(self.fmt.rst_fields('flags', self.fmt.rst_list_inline(operation['flags']))) + lines.append(self.fmt.rst_fields('flags', + self.fmt.rst_list_inline(operation['flags']))) if "do" in operation: lines.append(self.fmt.rst_paragraph(":do:", 0)) @@ -220,7 +197,6 @@ class YnlDocGenerator: return "\n".join(lines) - def parse_entries(self, entries: List[Dict[str, Any]], level: int) -> str: """Parse a list of entries""" ignored = ["pad"] @@ -235,17 +211,19 @@ class YnlDocGenerator: if type_: field_name += f" ({self.fmt.inline(type_)})" lines.append( - self.fmt.rst_fields(field_name, self.fmt.sanitize(entry.get("doc", "")), level) + self.fmt.rst_fields(field_name, + self.fmt.sanitize(entry.get("doc", "")), + level) ) elif isinstance(entry, list): lines.append(self.fmt.rst_list_inline(entry, level)) else: - lines.append(self.fmt.rst_bullet(self.fmt.inline(self.fmt.sanitize(entry)), level)) + lines.append(self.fmt.rst_bullet(self.fmt.inline(self.fmt.sanitize(entry)), + level)) lines.append("\n") return "\n".join(lines) - def parse_definitions(self, defs: Dict[str, Any], namespace: str) -> str: """Parse definitions section""" preprocessed = ["name", "entries", "members"] @@ -270,7 +248,6 @@ class YnlDocGenerator: return "\n".join(lines) - def parse_attr_sets(self, entries: List[Dict[str, Any]], namespace: str) -> str: """Parse attribute from attribute-set""" preprocessed = ["name", "type"] @@ -279,7 +256,8 @@ class YnlDocGenerator: lines = [] for entry in entries: - lines.append(self.fmt.rst_section(namespace, 'attribute-set', entry["name"])) + lines.append(self.fmt.rst_section(namespace, 'attribute-set', + entry["name"])) for attr in entry["attributes"]: type_ = attr.get("type") attr_line = attr["name"] @@ -301,13 +279,13 @@ class YnlDocGenerator: return "\n".join(lines) - def parse_sub_messages(self, entries: List[Dict[str, Any]], namespace: str) -> str: """Parse sub-message definitions""" lines = [] for entry in entries: - lines.append(self.fmt.rst_section(namespace, 'sub-message', entry["name"])) + lines.append(self.fmt.rst_section(namespace, 'sub-message', + entry["name"])) for fmt in entry["formats"]: value = fmt["value"] @@ -315,13 +293,14 @@ class YnlDocGenerator: for attr in ['fixed-header', 'attribute-set']: if attr in fmt: lines.append(self.fmt.rst_fields(attr, - self.fmt.rst_ref(namespace, attr, fmt[attr]), - 1)) + self.fmt.rst_ref(namespace, + attr, + fmt[attr]), + 1)) lines.append("\n") return "\n".join(lines) - def parse_yaml(self, obj: Dict[str, Any]) -> str: """Format the whole YAML into a RST string""" lines = [] @@ -344,7 +323,8 @@ class YnlDocGenerator: # Operations if "operations" in obj: lines.append(self.fmt.rst_subtitle("Operations")) - lines.append(self.parse_operations(obj["operations"]["list"], family)) + lines.append(self.parse_operations(obj["operations"]["list"], + family)) # Multicast groups if "mcast-groups" in obj: @@ -368,11 +348,9 @@ class YnlDocGenerator: return "\n".join(lines) - # Main functions # ============== - def parse_yaml_file(self, filename: str) -> str: """Transform the YAML specified by filename into an RST-formatted string""" with open(filename, "r", encoding="utf-8") as spec_file: From bb1e3629b2e684e03adb21d75c7839f3afeb488e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 12 Jun 2025 09:58:56 +0200 Subject: [PATCH 00380/11391] docs: sphinx: add a parser for yaml files for Netlink specs Add a simple sphinx.Parser to handle yaml files and add the the code to handle Netlink specs. All other yaml files are ignored. The code was written in a way that parsing yaml for different subsystems and even for different parts of Netlink are easy. All it takes to have a different parser is to add an import line similar to: from doc_generator import YnlDocGenerator adding the corresponding parser somewhere at the extension: netlink_parser = YnlDocGenerator() And then add a logic inside parse() to handle different doc outputs, depending on the file location, similar to: if "/netlink/specs/" in fname: msg = self.netlink_parser.parse_yaml_file(fname) Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Donald Hunter --- Documentation/sphinx/parser_yaml.py | 104 ++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100755 Documentation/sphinx/parser_yaml.py diff --git a/Documentation/sphinx/parser_yaml.py b/Documentation/sphinx/parser_yaml.py new file mode 100755 index 000000000000..fa2e6da17617 --- /dev/null +++ b/Documentation/sphinx/parser_yaml.py @@ -0,0 +1,104 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright 2025 Mauro Carvalho Chehab + +""" +Sphinx extension for processing YAML files +""" + +import os +import re +import sys + +from pprint import pformat + +from docutils.parsers.rst import Parser as RSTParser +from docutils.statemachine import ViewList + +from sphinx.util import logging +from sphinx.parsers import Parser + +srctree = os.path.abspath(os.environ["srctree"]) +sys.path.insert(0, os.path.join(srctree, "tools/net/ynl/pyynl/lib")) + +from doc_generator import YnlDocGenerator # pylint: disable=C0413 + +logger = logging.getLogger(__name__) + +class YamlParser(Parser): + """ + Kernel parser for YAML files. + + This is a simple sphinx.Parser to handle yaml files inside the + Kernel tree that will be part of the built documentation. + + The actual parser function is not contained here: the code was + written in a way that parsing yaml for different subsystems + can be done from a single dispatcher. + + All it takes to have parse YAML patches is to have an import line: + + from some_parser_code import NewYamlGenerator + + To this module. Then add an instance of the parser with: + + new_parser = NewYamlGenerator() + + and add a logic inside parse() to handle it based on the path, + like this: + + if "/foo" in fname: + msg = self.new_parser.parse_yaml_file(fname) + """ + + supported = ('yaml', ) + + netlink_parser = YnlDocGenerator() + + def rst_parse(self, inputstring, document, msg): + """ + Receives a ReST content that was previously converted by the + YAML parser, adding it to the document tree. + """ + + self.setup_parse(inputstring, document) + + result = ViewList() + + try: + # Parse message with RSTParser + for i, line in enumerate(msg.split('\n')): + result.append(line, document.current_source, i) + + rst_parser = RSTParser() + rst_parser.parse('\n'.join(result), document) + + except Exception as e: + document.reporter.error("YAML parsing error: %s" % pformat(e)) + + self.finish_parse() + + # Overrides docutils.parsers.Parser. See sphinx.parsers.RSTParser + def parse(self, inputstring, document): + """Check if a YAML is meant to be parsed.""" + + fname = document.current_source + + # Handle netlink yaml specs + if "/netlink/specs/" in fname: + msg = self.netlink_parser.parse_yaml_file(fname) + self.rst_parse(inputstring, document, msg) + + # All other yaml files are ignored + +def setup(app): + """Setup function for the Sphinx extension.""" + + # Add YAML parser + app.add_source_parser(YamlParser) + app.add_source_suffix('.yaml', 'yaml') + + return { + 'version': '1.0', + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } From 1ce4da3dd99e98bd4a8b396c291041080e0fe85e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 12 Jun 2025 10:34:30 +0200 Subject: [PATCH 00381/11391] docs: use parser_yaml extension to handle Netlink specs Instead of manually calling ynl_gen_rst.py, use a Sphinx extension. This way, no .rst files would be written to the Kernel source directories. We are using here a toctree with :glob: property. This way, there is no need to touch the netlink/specs/index.rst file every time a new Netlink spec is added/renamed/removed. Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Donald Hunter --- Documentation/Makefile | 17 ---------------- Documentation/conf.py | 20 ++++++++++++++----- Documentation/networking/index.rst | 2 +- .../networking/netlink_spec/readme.txt | 4 ---- 4 files changed, 16 insertions(+), 27 deletions(-) delete mode 100644 Documentation/networking/netlink_spec/readme.txt diff --git a/Documentation/Makefile b/Documentation/Makefile index b98477df5ddf..820f07e0afe6 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -104,22 +104,6 @@ quiet_cmd_sphinx = SPHINX $@ --> file://$(abspath $(BUILDDIR)/$3/$4) cp $(if $(patsubst /%,,$(DOCS_CSS)),$(abspath $(srctree)/$(DOCS_CSS)),$(DOCS_CSS)) $(BUILDDIR)/$3/_static/; \ fi -YNL_INDEX:=$(srctree)/Documentation/networking/netlink_spec/index.rst -YNL_RST_DIR:=$(srctree)/Documentation/networking/netlink_spec -YNL_YAML_DIR:=$(srctree)/Documentation/netlink/specs -YNL_TOOL:=$(srctree)/tools/net/ynl/pyynl/ynl_gen_rst.py - -YNL_RST_FILES_TMP := $(patsubst %.yaml,%.rst,$(wildcard $(YNL_YAML_DIR)/*.yaml)) -YNL_RST_FILES := $(patsubst $(YNL_YAML_DIR)%,$(YNL_RST_DIR)%, $(YNL_RST_FILES_TMP)) - -$(YNL_INDEX): $(YNL_RST_FILES) - $(Q)$(YNL_TOOL) -o $@ -x - -$(YNL_RST_DIR)/%.rst: $(YNL_YAML_DIR)/%.yaml $(YNL_TOOL) - $(Q)$(YNL_TOOL) -i $< -o $@ - -htmldocs texinfodocs latexdocs epubdocs xmldocs: $(YNL_INDEX) - htmldocs: @$(srctree)/scripts/sphinx-pre-install --version-check @+$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,html,$(var),,$(var))) @@ -186,7 +170,6 @@ refcheckdocs: $(Q)cd $(srctree);scripts/documentation-file-ref-check cleandocs: - $(Q)rm -f $(YNL_INDEX) $(YNL_RST_FILES) $(Q)rm -rf $(BUILDDIR) $(Q)$(MAKE) BUILDDIR=$(abspath $(BUILDDIR)) $(build)=Documentation/userspace-api/media clean diff --git a/Documentation/conf.py b/Documentation/conf.py index 700516238d3f..f9828f3862f9 100644 --- a/Documentation/conf.py +++ b/Documentation/conf.py @@ -42,6 +42,15 @@ exclude_patterns = [] dyn_include_patterns = [] dyn_exclude_patterns = ["output"] +# Currently, only netlink/specs has a parser for yaml. +# Prefer using include patterns if available, as it is faster +if has_include_patterns: + dyn_include_patterns.append("netlink/specs/*.yaml") +else: + dyn_exclude_patterns.append("netlink/*.yaml") + dyn_exclude_patterns.append("devicetree/bindings/**.yaml") + dyn_exclude_patterns.append("core-api/kho/bindings/**.yaml") + # Properly handle include/exclude patterns # ---------------------------------------- @@ -102,12 +111,12 @@ extensions = [ "kernel_include", "kfigure", "maintainers_include", + "parser_yaml", "rstFlatTable", "sphinx.ext.autosectionlabel", "sphinx.ext.ifconfig", "translations", ] - # Since Sphinx version 3, the C function parser is more pedantic with regards # to type checking. Due to that, having macros at c:function cause problems. # Those needed to be escaped by using c_id_attributes[] array @@ -204,10 +213,11 @@ else: # Add any paths that contain templates here, relative to this directory. templates_path = ["sphinx/templates"] -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# source_suffix = ['.rst', '.md'] -source_suffix = '.rst' +# The suffixes of source filenames that will be automatically parsed +source_suffix = { + ".rst": "restructuredtext", + ".yaml": "yaml", +} # The encoding of source files. # source_encoding = 'utf-8-sig' diff --git a/Documentation/networking/index.rst b/Documentation/networking/index.rst index ac90b82f3ce9..b7a4969e9bc9 100644 --- a/Documentation/networking/index.rst +++ b/Documentation/networking/index.rst @@ -57,7 +57,7 @@ Contents: filter generic-hdlc generic_netlink - netlink_spec/index + ../netlink/specs/index gen_stats gtp ila diff --git a/Documentation/networking/netlink_spec/readme.txt b/Documentation/networking/netlink_spec/readme.txt deleted file mode 100644 index 030b44aca4e6..000000000000 --- a/Documentation/networking/netlink_spec/readme.txt +++ /dev/null @@ -1,4 +0,0 @@ -SPDX-License-Identifier: GPL-2.0 - -This file is populated during the build of the documentation (htmldocs) by the -tools/net/ynl/pyynl/ynl_gen_rst.py script. From 11d137aaef802fb2a22b917b4d91e800141140c7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 12 Jun 2025 15:27:39 +0200 Subject: [PATCH 00382/11391] docs: uapi: netlink: update netlink specs link With the recent parser_yaml extension, and the removal of the auto-generated ReST source files, the location of netlink specs changed. Update uAPI accordingly. Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Donald Hunter --- Documentation/userspace-api/netlink/index.rst | 2 +- Documentation/userspace-api/netlink/specs.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/userspace-api/netlink/index.rst b/Documentation/userspace-api/netlink/index.rst index c1b6765cc963..83ae25066591 100644 --- a/Documentation/userspace-api/netlink/index.rst +++ b/Documentation/userspace-api/netlink/index.rst @@ -18,4 +18,4 @@ Netlink documentation for users. See also: - :ref:`Documentation/core-api/netlink.rst ` - - :ref:`Documentation/networking/netlink_spec/index.rst ` + - :ref:`Documentation/netlink/specs/index.rst ` diff --git a/Documentation/userspace-api/netlink/specs.rst b/Documentation/userspace-api/netlink/specs.rst index 1b50d97d8d7c..debb4bfca5c4 100644 --- a/Documentation/userspace-api/netlink/specs.rst +++ b/Documentation/userspace-api/netlink/specs.rst @@ -15,7 +15,7 @@ kernel headers directly. Internally kernel uses the YAML specs to generate: - the C uAPI header - - documentation of the protocol as a ReST file - see :ref:`Documentation/networking/netlink_spec/index.rst ` + - documentation of the protocol as a ReST file - see :ref:`Documentation/netlink/specs/index.rst ` - policy tables for input attribute validation - operation tables From dc2f50796a78061480a658e2b7c2ebacc4c8d84e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 17 Jun 2025 09:34:39 +0200 Subject: [PATCH 00383/11391] tools: ynl_gen_rst.py: drop support for generating index files As we're now using an index file with a glob, there's no need to generate index files anymore. Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Donald Hunter --- tools/net/ynl/pyynl/ynl_gen_rst.py | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_rst.py b/tools/net/ynl/pyynl/ynl_gen_rst.py index 010315fad498..90ae19aac89d 100755 --- a/tools/net/ynl/pyynl/ynl_gen_rst.py +++ b/tools/net/ynl/pyynl/ynl_gen_rst.py @@ -31,9 +31,6 @@ def parse_arguments() -> argparse.Namespace: # Index and input are mutually exclusive group = parser.add_mutually_exclusive_group() - group.add_argument( - "-x", "--index", action="store_true", help="Generate the index page" - ) group.add_argument("-i", "--input", help="YAML file name") args = parser.parse_args() @@ -63,27 +60,6 @@ def write_to_rstfile(content: str, filename: str) -> None: rst_file.write(content) -def generate_main_index_rst(parser: YnlDocGenerator, output: str) -> None: - """Generate the `networking_spec/index` content and write to the file""" - lines = [] - - lines.append(parser.fmt.rst_header()) - lines.append(parser.fmt.rst_label("specs")) - lines.append(parser.fmt.rst_title("Netlink Family Specifications")) - lines.append(parser.fmt.rst_toctree(1)) - - index_dir = os.path.dirname(output) - logging.debug("Looking for .rst files in %s", index_dir) - for filename in sorted(os.listdir(index_dir)): - base, ext = os.path.splitext(filename) - if filename == "index.rst" or ext not in [".rst", ".yaml"]: - continue - lines.append(f" {base}\n") - - logging.debug("Writing an index file at %s", output) - write_to_rstfile("".join(lines), output) - - def main() -> None: """Main function that reads the YAML files and generates the RST files""" @@ -102,10 +78,6 @@ def main() -> None: write_to_rstfile(content, args.output) - if args.index: - # Generate the index RST file - generate_main_index_rst(parser, args.output) - if __name__ == "__main__": main() From 6abc773747a80dfcbf8aa05fce7bb8d5d815fdb3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 10 Jun 2025 10:44:45 +0200 Subject: [PATCH 00384/11391] docs: netlink: remove obsolete .gitignore from unused directory The previous code was generating source rst files under Documentation/networking/netlink_spec/. With the Sphinx YAML parser, this is now gone. So, stop ignoring *.rst files inside netlink specs directory. Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Donald Hunter --- Documentation/networking/netlink_spec/.gitignore | 1 - 1 file changed, 1 deletion(-) delete mode 100644 Documentation/networking/netlink_spec/.gitignore diff --git a/Documentation/networking/netlink_spec/.gitignore b/Documentation/networking/netlink_spec/.gitignore deleted file mode 100644 index 30d85567b592..000000000000 --- a/Documentation/networking/netlink_spec/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.rst From 778756819af1e5aca9e3c9f77a3c4cfb4b2a5fb8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 13 Jun 2025 13:02:01 +0200 Subject: [PATCH 00385/11391] MAINTAINERS: add netlink_yml_parser.py to linux-doc The documentation build depends on the parsing code at ynl_gen_rst.py. Ensure that changes to it will be c/c to linux-doc ML and maintainers by adding an entry for it. This way, if a change there would affect the build, or the minimal version required for Python, doc developers may know in advance. Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Breno Leitao Reviewed-by: Donald Hunter --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index fe168477caa4..39d5e4e09273 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7307,6 +7307,7 @@ F: scripts/get_abi.py F: scripts/kernel-doc* F: scripts/lib/abi/* F: scripts/lib/kdoc/* +F: tools/net/ynl/pyynl/lib/doc_generator.py F: scripts/sphinx-pre-install X: Documentation/ABI/ X: Documentation/admin-guide/media/ From ad06a878a328f230e9bf62ec0042eea1798d2cb0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 17 Jun 2025 17:28:04 +0200 Subject: [PATCH 00386/11391] tools: netlink_yml_parser.py: add line numbers to parsed data When something goes wrong, we want Sphinx error to point to the right line number from the original source, not from the processed ReST data. Signed-off-by: Mauro Carvalho Chehab --- tools/net/ynl/pyynl/lib/doc_generator.py | 34 ++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/tools/net/ynl/pyynl/lib/doc_generator.py b/tools/net/ynl/pyynl/lib/doc_generator.py index 474b2b78c7bc..658759a527a6 100644 --- a/tools/net/ynl/pyynl/lib/doc_generator.py +++ b/tools/net/ynl/pyynl/lib/doc_generator.py @@ -20,6 +20,16 @@ from typing import Any, Dict, List import yaml +LINE_STR = '__lineno__' + +class NumberedSafeLoader(yaml.SafeLoader): # pylint: disable=R0901 + """Override the SafeLoader class to add line number to parsed data""" + + def construct_mapping(self, node, *args, **kwargs): + mapping = super().construct_mapping(node, *args, **kwargs) + mapping[LINE_STR] = node.start_mark.line + + return mapping class RstFormatters: """RST Formatters""" @@ -127,6 +137,11 @@ class RstFormatters: """Return a formatted label""" return f".. _{title}:\n\n" + @staticmethod + def rst_lineno(lineno: int) -> str: + """Return a lineno comment""" + return f".. LINENO {lineno}\n" + class YnlDocGenerator: """YAML Netlink specs Parser""" @@ -144,6 +159,9 @@ class YnlDocGenerator: """Parse 'do' section and return a formatted string""" lines = [] for key in do_dict.keys(): + if key == LINE_STR: + lines.append(self.fmt.rst_lineno(do_dict[key])) + continue lines.append(self.fmt.rst_paragraph(self.fmt.bold(key), level + 1)) if key in ['request', 'reply']: lines.append(self.parse_do_attributes(do_dict[key], level + 1) + "\n") @@ -174,6 +192,10 @@ class YnlDocGenerator: lines.append(self.fmt.rst_paragraph(operation["doc"]) + "\n") for key in operation.keys(): + if key == LINE_STR: + lines.append(self.fmt.rst_lineno(operation[key])) + continue + if key in preprocessed: # Skip the special fields continue @@ -233,6 +255,9 @@ class YnlDocGenerator: for definition in defs: lines.append(self.fmt.rst_section(namespace, 'definition', definition["name"])) for k in definition.keys(): + if k == LINE_STR: + lines.append(self.fmt.rst_lineno(definition[k])) + continue if k in preprocessed + ignored: continue lines.append(self.fmt.rst_fields(k, self.fmt.sanitize(definition[k]), 0)) @@ -268,6 +293,9 @@ class YnlDocGenerator: lines.append(self.fmt.rst_subsubsection(attr_line)) for k in attr.keys(): + if k == LINE_STR: + lines.append(self.fmt.rst_lineno(attr[k])) + continue if k in preprocessed + ignored: continue if k in linkable: @@ -306,6 +334,8 @@ class YnlDocGenerator: lines = [] # Main header + lineno = obj.get('__lineno__', 0) + lines.append(self.fmt.rst_lineno(lineno)) family = obj['name'] @@ -354,7 +384,7 @@ class YnlDocGenerator: def parse_yaml_file(self, filename: str) -> str: """Transform the YAML specified by filename into an RST-formatted string""" with open(filename, "r", encoding="utf-8") as spec_file: - yaml_data = yaml.safe_load(spec_file) - content = self.parse_yaml(yaml_data) + numbered_yaml = yaml.load(spec_file, Loader=NumberedSafeLoader) + content = self.parse_yaml(numbered_yaml) return content From 0b24dfdd12f4ca3ef5efa0cfaad3fc14f5b3fbf1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 17 Jun 2025 17:54:03 +0200 Subject: [PATCH 00387/11391] docs: parser_yaml.py: add support for line numbers from the parser Instead of printing line numbers from the temp converted ReST file, get them from the original source. Signed-off-by: Mauro Carvalho Chehab --- Documentation/sphinx/parser_yaml.py | 12 ++++++++++-- tools/net/ynl/pyynl/lib/doc_generator.py | 16 ++++++++++++---- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/Documentation/sphinx/parser_yaml.py b/Documentation/sphinx/parser_yaml.py index fa2e6da17617..8288e2ff7c7c 100755 --- a/Documentation/sphinx/parser_yaml.py +++ b/Documentation/sphinx/parser_yaml.py @@ -54,6 +54,8 @@ class YamlParser(Parser): netlink_parser = YnlDocGenerator() + re_lineno = re.compile(r"\.\. LINENO ([0-9]+)$") + def rst_parse(self, inputstring, document, msg): """ Receives a ReST content that was previously converted by the @@ -66,8 +68,14 @@ class YamlParser(Parser): try: # Parse message with RSTParser - for i, line in enumerate(msg.split('\n')): - result.append(line, document.current_source, i) + lineoffset = 0; + for line in msg.split('\n'): + match = self.re_lineno.match(line) + if match: + lineoffset = int(match.group(1)) + continue + + result.append(line, document.current_source, lineoffset) rst_parser = RSTParser() rst_parser.parse('\n'.join(result), document) diff --git a/tools/net/ynl/pyynl/lib/doc_generator.py b/tools/net/ynl/pyynl/lib/doc_generator.py index 658759a527a6..403abf1a2eda 100644 --- a/tools/net/ynl/pyynl/lib/doc_generator.py +++ b/tools/net/ynl/pyynl/lib/doc_generator.py @@ -158,9 +158,11 @@ class YnlDocGenerator: def parse_do(self, do_dict: Dict[str, Any], level: int = 0) -> str: """Parse 'do' section and return a formatted string""" lines = [] + if LINE_STR in do_dict: + lines.append(self.fmt.rst_lineno(do_dict[LINE_STR])) + for key in do_dict.keys(): if key == LINE_STR: - lines.append(self.fmt.rst_lineno(do_dict[key])) continue lines.append(self.fmt.rst_paragraph(self.fmt.bold(key), level + 1)) if key in ['request', 'reply']: @@ -187,13 +189,15 @@ class YnlDocGenerator: lines = [] for operation in operations: + if LINE_STR in operation: + lines.append(self.fmt.rst_lineno(operation[LINE_STR])) + lines.append(self.fmt.rst_section(namespace, 'operation', operation["name"])) lines.append(self.fmt.rst_paragraph(operation["doc"]) + "\n") for key in operation.keys(): if key == LINE_STR: - lines.append(self.fmt.rst_lineno(operation[key])) continue if key in preprocessed: @@ -253,10 +257,12 @@ class YnlDocGenerator: lines = [] for definition in defs: + if LINE_STR in definition: + lines.append(self.fmt.rst_lineno(definition[LINE_STR])) + lines.append(self.fmt.rst_section(namespace, 'definition', definition["name"])) for k in definition.keys(): if k == LINE_STR: - lines.append(self.fmt.rst_lineno(definition[k])) continue if k in preprocessed + ignored: continue @@ -284,6 +290,9 @@ class YnlDocGenerator: lines.append(self.fmt.rst_section(namespace, 'attribute-set', entry["name"])) for attr in entry["attributes"]: + if LINE_STR in attr: + lines.append(self.fmt.rst_lineno(attr[LINE_STR])) + type_ = attr.get("type") attr_line = attr["name"] if type_: @@ -294,7 +303,6 @@ class YnlDocGenerator: for k in attr.keys(): if k == LINE_STR: - lines.append(self.fmt.rst_lineno(attr[k])) continue if k in preprocessed + ignored: continue From d90555ef0603935529837e490d5acc8436297c56 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 19 Jun 2025 14:55:33 +0200 Subject: [PATCH 00388/11391] docs: parser_yaml.py: fix backward compatibility with old docutils As reported by Akira, older docutils versions are not compatible with the way some Sphinx versions send tab_width. Add a code to address it. Reported-by: Akira Yokosawa Closes: https://lore.kernel.org/linux-doc/598b2cb7-2fd7-4388-96ba-2ddf0ab55d2a@gmail.com/ Tested-by: Akira Yokosawa Signed-off-by: Mauro Carvalho Chehab --- Documentation/sphinx/parser_yaml.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/sphinx/parser_yaml.py b/Documentation/sphinx/parser_yaml.py index 8288e2ff7c7c..1602b31f448e 100755 --- a/Documentation/sphinx/parser_yaml.py +++ b/Documentation/sphinx/parser_yaml.py @@ -77,6 +77,10 @@ class YamlParser(Parser): result.append(line, document.current_source, lineoffset) + # Fix backward compatibility with docutils < 0.17.1 + if "tab_width" not in vars(document.settings): + document.settings.tab_width = 8 + rst_parser = RSTParser() rst_parser.parse('\n'.join(result), document) From 47459937be8031aae6aaa17ac5f60985f7c9e1bd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 10 Jul 2025 18:36:40 +0200 Subject: [PATCH 00389/11391] sphinx: parser_yaml.py: fix line numbers information As reported by Donald, this code: rst_parser = RSTParser() rst_parser.parse('\n'.join(result), document) breaks line parsing. As an alternative, I tested a variant of it: rst_parser.parse(result, document) but still line number was not preserved. As Donald noted, standard Parser classes don't have a direct mechanism to preserve line numbers from ViewList(). So, instead, let's use a mechanism similar to what we do already at kerneldoc.py: call the statemachine mechanism directly there. I double-checked when states and statemachine were introduced: both were back in 2002. I also tested doc build with docutils 0.16 and 0.21.2. It worked with both, so it seems to be stable enough for our needs. Reported-by: Donald Hunter Closes: https://lore.kernel.org/linux-doc/m24ivk78ng.fsf@gmail.com/T/#u Signed-off-by: Mauro Carvalho Chehab --- Documentation/sphinx/parser_yaml.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/Documentation/sphinx/parser_yaml.py b/Documentation/sphinx/parser_yaml.py index 1602b31f448e..634d84a202fc 100755 --- a/Documentation/sphinx/parser_yaml.py +++ b/Documentation/sphinx/parser_yaml.py @@ -11,7 +11,9 @@ import sys from pprint import pformat +from docutils import statemachine from docutils.parsers.rst import Parser as RSTParser +from docutils.parsers.rst import states from docutils.statemachine import ViewList from sphinx.util import logging @@ -56,6 +58,8 @@ class YamlParser(Parser): re_lineno = re.compile(r"\.\. LINENO ([0-9]+)$") + tab_width = 8 + def rst_parse(self, inputstring, document, msg): """ Receives a ReST content that was previously converted by the @@ -66,10 +70,18 @@ class YamlParser(Parser): result = ViewList() + self.statemachine = states.RSTStateMachine(state_classes=states.state_classes, + initial_state='Body', + debug=document.reporter.debug_flag) + try: # Parse message with RSTParser lineoffset = 0; - for line in msg.split('\n'): + + lines = statemachine.string2lines(msg, self.tab_width, + convert_whitespace=True) + + for line in lines: match = self.re_lineno.match(line) if match: lineoffset = int(match.group(1)) @@ -77,12 +89,7 @@ class YamlParser(Parser): result.append(line, document.current_source, lineoffset) - # Fix backward compatibility with docutils < 0.17.1 - if "tab_width" not in vars(document.settings): - document.settings.tab_width = 8 - - rst_parser = RSTParser() - rst_parser.parse('\n'.join(result), document) + self.statemachine.run(result, document) except Exception as e: document.reporter.error("YAML parsing error: %s" % pformat(e)) From 43d4940c944c20f41dde2e091284646367c10c60 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 11 Aug 2025 10:15:00 +0200 Subject: [PATCH 00390/11391] ALSA: usb: scarlett2: Clean ups with guard() and __free() There are lots of manual mutex lock/unlock and temporary kmalloc/kfree patterns found in mixer_scalett2.c. Let's simplify the code with the recent lock guard() and auto cleanup with __free(). Only code refactoring, and there should be no actual behavior change. Link: https://patch.msgid.link/20250811081502.30768-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/mixer_scarlett2.c | 1317 ++++++++++++----------------------- 1 file changed, 437 insertions(+), 880 deletions(-) diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c index 1ec203cbbd94..e762d6110b1a 100644 --- a/sound/usb/mixer_scarlett2.c +++ b/sound/usb/mixer_scarlett2.c @@ -2348,7 +2348,8 @@ static int scarlett2_usb( { struct scarlett2_data *private = mixer->private_data; struct usb_device *dev = mixer->chip->dev; - struct scarlett2_usb_packet *req, *resp = NULL; + struct scarlett2_usb_packet *req __free(kfree) = NULL; + struct scarlett2_usb_packet *resp __free(kfree) = NULL; size_t req_buf_size = struct_size(req, data, req_size); size_t resp_buf_size = struct_size(resp, data, resp_size); int retries = 0; @@ -2356,18 +2357,14 @@ static int scarlett2_usb( int err; req = kmalloc(req_buf_size, GFP_KERNEL); - if (!req) { - err = -ENOMEM; - goto error; - } + if (!req) + return -ENOMEM; resp = kmalloc(resp_buf_size, GFP_KERNEL); - if (!resp) { - err = -ENOMEM; - goto error; - } + if (!resp) + return -ENOMEM; - mutex_lock(&private->usb_mutex); + guard(mutex)(&private->usb_mutex); /* build request message and send it */ @@ -2389,8 +2386,7 @@ static int scarlett2_usb( mixer->chip, "%s USB request result cmd %x was %d\n", private->series_name, cmd, err); - err = -EINVAL; - goto unlock; + return -EINVAL; } if (!wait_for_completion_timeout(&private->cmd_done, @@ -2400,8 +2396,7 @@ static int scarlett2_usb( "%s USB request timed out, cmd %x\n", private->series_name, cmd); - err = -ETIMEDOUT; - goto unlock; + return -ETIMEDOUT; } /* send a second message to get the response */ @@ -2418,17 +2413,14 @@ static int scarlett2_usb( * reboot request */ if (cmd == SCARLETT2_USB_REBOOT && - (err == -ESHUTDOWN || err == -EPROTO)) { - err = 0; - goto unlock; - } + (err == -ESHUTDOWN || err == -EPROTO)) + return 0; usb_audio_err( mixer->chip, "%s USB response result cmd %x was %d expected %zu\n", private->series_name, cmd, err, resp_buf_size); - err = -EINVAL; - goto unlock; + return -EINVAL; } /* cmd/seq/size should match except when initialising @@ -2451,18 +2443,12 @@ static int scarlett2_usb( resp_size, le16_to_cpu(resp->size), le32_to_cpu(resp->error), le32_to_cpu(resp->pad)); - err = -EINVAL; - goto unlock; + return -EINVAL; } if (resp_data && resp_size > 0) memcpy(resp_data, resp->data, resp_size); -unlock: - mutex_unlock(&private->usb_mutex); -error: - kfree(req); - kfree(resp); return err; } @@ -3321,25 +3307,20 @@ static int scarlett2_sync_ctl_get(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int err = 0; + int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; if (private->sync_updated) { err = scarlett2_update_sync(mixer); if (err < 0) - goto unlock; + return err; } ucontrol->value.enumerated.item[0] = private->sync; - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return 0; } static const struct snd_kcontrol_new scarlett2_sync_ctl = { @@ -3589,17 +3570,13 @@ static int scarlett2_autogain_switch_ctl_info( struct scarlett2_data *private = mixer->private_data; int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); err = scarlett2_check_input_phantom_updated(mixer); if (err < 0) - goto unlock; + return err; - err = snd_ctl_boolean_mono_info(kctl, uinfo); - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return snd_ctl_boolean_mono_info(kctl, uinfo); } static int scarlett2_autogain_switch_ctl_get( @@ -3610,23 +3587,18 @@ static int scarlett2_autogain_switch_ctl_get( struct scarlett2_data *private = mixer->private_data; int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; err = scarlett2_check_autogain_updated(mixer); if (err < 0) - goto unlock; + return err; ucontrol->value.enumerated.item[0] = private->autogain_switch[elem->control]; - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return 0; } static int scarlett2_autogain_status_ctl_get( @@ -3637,23 +3609,18 @@ static int scarlett2_autogain_status_ctl_get( struct scarlett2_data *private = mixer->private_data; int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; err = scarlett2_check_autogain_updated(mixer); if (err < 0) - goto unlock; + return err; ucontrol->value.enumerated.item[0] = private->autogain_status[elem->control]; - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return 0; } static int scarlett2_autogain_switch_ctl_put( @@ -3662,46 +3629,37 @@ static int scarlett2_autogain_switch_ctl_put( struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int index = elem->control; int oval, val, err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; err = scarlett2_check_input_phantom_updated(mixer); if (err < 0) - goto unlock; + return err; - if (scarlett2_phantom_is_switching(private, index)) { - err = -EPERM; - goto unlock; - } + if (scarlett2_phantom_is_switching(private, index)) + return -EPERM; oval = private->autogain_switch[index]; val = !!ucontrol->value.integer.value[0]; if (oval == val) - goto unlock; + return 0; private->autogain_switch[index] = val; /* Send switch change to the device */ err = scarlett2_usb_set_config( mixer, SCARLETT2_CONFIG_AUTOGAIN_SWITCH, index, val); - if (err == 0) - err = 1; scarlett2_autogain_update_access(mixer); scarlett2_autogain_notify_access(mixer); -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static int scarlett2_autogain_status_ctl_info( @@ -3742,16 +3700,14 @@ static int scarlett2_ag_target_ctl_info( struct scarlett2_data *private = mixer->private_data; int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; err = scarlett2_check_autogain_updated(mixer); if (err < 0) - goto unlock; + return err; uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; @@ -3759,9 +3715,7 @@ static int scarlett2_ag_target_ctl_info( uinfo->value.integer.max = 0; uinfo->value.integer.step = 1; -unlock: - mutex_unlock(&private->data_mutex); - return err; + return 0; } static int scarlett2_ag_target_ctl_get( @@ -3770,26 +3724,21 @@ static int scarlett2_ag_target_ctl_get( struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int err = 0; + int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; if (private->autogain_updated) { err = scarlett2_update_autogain(mixer); if (err < 0) - goto unlock; + return err; } ucontrol->value.integer.value[0] = private->ag_targets[elem->control]; - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return 0; } static int scarlett2_ag_target_ctl_put( @@ -3798,39 +3747,32 @@ static int scarlett2_ag_target_ctl_put( struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int index = elem->control; int oval, val, err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; err = scarlett2_check_put_during_autogain(mixer); if (err < 0) - goto unlock; + return err; oval = private->ag_targets[index]; val = clamp(ucontrol->value.integer.value[0], (long)SCARLETT2_AG_TARGET_MIN, 0L); if (oval == val) - goto unlock; + return 0; private->ag_targets[index] = val; /* Send new value to the device */ err = scarlett2_usb_set_config( mixer, scarlett2_ag_target_configs[index], 1, -val); - if (err == 0) - err = 1; -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static const DECLARE_TLV_DB_MINMAX( @@ -3885,25 +3827,20 @@ static int scarlett2_input_select_ctl_get( struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int err = 0; + int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; if (private->input_select_updated) { err = scarlett2_update_input_select(mixer); if (err < 0) - goto unlock; + return err; } ucontrol->value.enumerated.item[0] = private->input_select_switch; - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return 0; } static int scarlett2_input_select_ctl_put( @@ -3913,19 +3850,16 @@ static int scarlett2_input_select_ctl_put( struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; const struct scarlett2_device_info *info = private->info; - int oval, val, err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; err = scarlett2_check_put_during_autogain(mixer); if (err < 0) - goto unlock; + return err; oval = private->input_select_switch; val = ucontrol->value.integer.value[0]; @@ -3936,7 +3870,7 @@ static int scarlett2_input_select_ctl_put( val = info->gain_input_count - 1; if (oval == val) - goto unlock; + return 0; private->input_select_switch = val; @@ -3944,12 +3878,8 @@ static int scarlett2_input_select_ctl_put( err = scarlett2_usb_set_config( mixer, SCARLETT2_CONFIG_INPUT_SELECT_SWITCH, 0, val); - if (err == 0) - err = 1; -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static int scarlett2_input_select_ctl_info( @@ -3958,43 +3888,38 @@ static int scarlett2_input_select_ctl_info( struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int inputs = private->info->gain_input_count; int i, err; - char **values = kcalloc(inputs, sizeof(char *), GFP_KERNEL); + char **values __free(kfree) = NULL; + values = kcalloc(inputs, sizeof(char *), GFP_KERNEL); if (!values) return -ENOMEM; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; err = scarlett2_check_autogain_updated(mixer); if (err < 0) - goto unlock; + return err; /* Loop through each input */ for (i = 0; i < inputs; i++) { values[i] = kasprintf(GFP_KERNEL, "Input %d", i + 1); if (!values[i]) { err = -ENOMEM; - goto unlock; + goto clear; } } err = snd_ctl_enum_info(uinfo, 1, i, (const char * const *)values); -unlock: - mutex_unlock(&private->data_mutex); - +clear: for (i = 0; i < inputs; i++) kfree(values[i]); - kfree(values); return err; } @@ -4020,22 +3945,16 @@ static int scarlett2_autogain_disables_ctl_info(struct snd_kcontrol *kctl, struct scarlett2_data *private = mixer->private_data; int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; err = scarlett2_check_autogain_updated(mixer); if (err < 0) - goto unlock; + return err; - err = snd_ctl_boolean_mono_info(kctl, uinfo); - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return snd_ctl_boolean_mono_info(kctl, uinfo); } static int scarlett2_input_link_ctl_get( @@ -4044,26 +3963,21 @@ static int scarlett2_input_link_ctl_get( struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int err = 0; + int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; if (private->input_select_updated) { err = scarlett2_update_input_select(mixer); if (err < 0) - goto unlock; + return err; } ucontrol->value.enumerated.item[0] = private->input_link_switch[elem->control]; - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return 0; } static int scarlett2_input_link_ctl_put( @@ -4072,37 +3986,30 @@ static int scarlett2_input_link_ctl_put( struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int index = elem->control; int oval, val, err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; err = scarlett2_check_put_during_autogain(mixer); if (err < 0) - goto unlock; + return err; oval = private->input_link_switch[index]; val = !!ucontrol->value.integer.value[0]; if (oval == val) - goto unlock; + return 0; private->input_link_switch[index] = val; err = scarlett2_usb_set_config( mixer, SCARLETT2_CONFIG_INPUT_LINK_SWITCH, index, val); - if (err == 0) - err = 1; -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static const struct snd_kcontrol_new scarlett2_input_link_ctl = { @@ -4138,16 +4045,14 @@ static int scarlett2_input_gain_ctl_info(struct snd_kcontrol *kctl, struct scarlett2_data *private = mixer->private_data; int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; err = scarlett2_check_autogain_updated(mixer); if (err < 0) - goto unlock; + return err; uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = elem->channels; @@ -4155,9 +4060,7 @@ static int scarlett2_input_gain_ctl_info(struct snd_kcontrol *kctl, uinfo->value.integer.max = SCARLETT2_MAX_GAIN_VALUE; uinfo->value.integer.step = 1; -unlock: - mutex_unlock(&private->data_mutex); - return err; + return 0; } static int scarlett2_input_gain_ctl_get(struct snd_kcontrol *kctl, @@ -4166,26 +4069,21 @@ static int scarlett2_input_gain_ctl_get(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int err = 0; + int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; if (private->input_gain_updated) { err = scarlett2_update_input_gain(mixer); if (err < 0) - goto unlock; + return err; } ucontrol->value.integer.value[0] = private->gain[elem->control]; - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return 0; } static int scarlett2_input_gain_ctl_put(struct snd_kcontrol *kctl, @@ -4194,38 +4092,31 @@ static int scarlett2_input_gain_ctl_put(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int index = elem->control; int oval, val, err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; err = scarlett2_check_put_during_autogain(mixer); if (err < 0) - goto unlock; + return err; oval = private->gain[index]; val = ucontrol->value.integer.value[0]; if (oval == val) - goto unlock; + return 0; private->gain[index] = val; /* Send gain change to the device */ err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_INPUT_GAIN, index, val); - if (err == 0) - err = 1; -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static const struct snd_kcontrol_new scarlett2_input_gain_ctl = { @@ -4262,26 +4153,21 @@ static int scarlett2_safe_ctl_get(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int err = 0; + int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; if (private->input_safe_updated) { err = scarlett2_update_input_safe(mixer); if (err < 0) - goto unlock; + return err; } ucontrol->value.integer.value[0] = private->safe_switch[elem->control]; - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return 0; } static int scarlett2_safe_ctl_put(struct snd_kcontrol *kctl, @@ -4290,38 +4176,31 @@ static int scarlett2_safe_ctl_put(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int index = elem->control; int oval, val, err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; err = scarlett2_check_put_during_autogain(mixer); if (err < 0) - goto unlock; + return err; oval = private->safe_switch[index]; val = !!ucontrol->value.integer.value[0]; if (oval == val) - goto unlock; + return 0; private->safe_switch[index] = val; /* Send switch change to the device */ err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_SAFE_SWITCH, index, val); - if (err == 0) - err = 1; -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static const struct snd_kcontrol_new scarlett2_safe_ctl = { @@ -4356,20 +4235,17 @@ static int scarlett2_pcm_input_switch_ctl_get( struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = elem->head.mixer->private_data; - int err = 0; + int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); if (private->pcm_input_switch_updated) { err = scarlett2_update_pcm_input_switch(mixer); if (err < 0) - goto unlock; + return err; } ucontrol->value.enumerated.item[0] = private->pcm_input_switch; - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return 0; } static int scarlett2_pcm_input_switch_ctl_put( @@ -4378,21 +4254,18 @@ static int scarlett2_pcm_input_switch_ctl_put( struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; + int oval, val, err; - int oval, val, err = 0; + guard(mutex)(&private->data_mutex); - mutex_lock(&private->data_mutex); - - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; oval = private->pcm_input_switch; val = !!ucontrol->value.integer.value[0]; if (oval == val) - goto unlock; + return 0; private->pcm_input_switch = val; @@ -4400,12 +4273,8 @@ static int scarlett2_pcm_input_switch_ctl_put( err = scarlett2_usb_set_config( mixer, SCARLETT2_CONFIG_PCM_INPUT_SWITCH, 0, val); - if (err == 0) - err = 1; -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static int scarlett2_pcm_input_switch_ctl_info( @@ -4492,25 +4361,20 @@ static int scarlett2_master_volume_ctl_get(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int err = 0; + int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; if (private->vol_updated) { err = scarlett2_update_volumes(mixer); if (err < 0) - goto unlock; + return err; } ucontrol->value.integer.value[0] = private->master_vol; - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return 0; } static int scarlett2_headphone_volume_ctl_get( @@ -4520,25 +4384,20 @@ static int scarlett2_headphone_volume_ctl_get( struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int err = 0; + int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; if (private->vol_updated) { err = scarlett2_update_volumes(mixer); if (err < 0) - goto unlock; + return err; } ucontrol->value.integer.value[0] = private->headphone_vol; - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return 0; } static int line_out_remap(struct scarlett2_data *private, int index) @@ -4561,25 +4420,20 @@ static int scarlett2_volume_ctl_get(struct snd_kcontrol *kctl, struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; int index = line_out_remap(private, elem->control); - int err = 0; + int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; if (private->vol_updated) { err = scarlett2_update_volumes(mixer); if (err < 0) - goto unlock; + return err; } ucontrol->value.integer.value[0] = private->vol[index]; - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return 0; } static int scarlett2_volume_ctl_put(struct snd_kcontrol *kctl, @@ -4589,30 +4443,24 @@ static int scarlett2_volume_ctl_put(struct snd_kcontrol *kctl, struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; int index = line_out_remap(private, elem->control); - int oval, val, err = 0; + int oval, val, err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; oval = private->vol[index]; val = ucontrol->value.integer.value[0]; if (oval == val) - goto unlock; + return 0; private->vol[index] = val; err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_LINE_OUT_VOLUME, index, val - SCARLETT2_VOLUME_BIAS); - if (err == 0) - err = 1; -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static const DECLARE_TLV_DB_MINMAX( @@ -4691,25 +4539,20 @@ static int scarlett2_mute_ctl_get(struct snd_kcontrol *kctl, struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; int index = line_out_remap(private, elem->control); - int err = 0; + int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; if (private->dim_mute_updated) { err = scarlett2_update_dim_mute(mixer); if (err < 0) - goto unlock; + return err; } ucontrol->value.integer.value[0] = private->mute_switch[index]; - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return 0; } static int scarlett2_mute_ctl_put(struct snd_kcontrol *kctl, @@ -4719,32 +4562,26 @@ static int scarlett2_mute_ctl_put(struct snd_kcontrol *kctl, struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; int index = line_out_remap(private, elem->control); - int oval, val, err = 0; + int oval, val, err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; oval = private->mute_switch[index]; val = !!ucontrol->value.integer.value[0]; if (oval == val) - goto unlock; + return 0; private->mute_switch[index] = val; /* Send mute change to the device */ err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_MUTE_SWITCH, index, val); - if (err == 0) - err = 1; -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static const struct snd_kcontrol_new scarlett2_mute_ctl = { @@ -4863,28 +4700,22 @@ static int scarlett2_sw_hw_enum_ctl_put(struct snd_kcontrol *kctl, struct scarlett2_data *private = mixer->private_data; int ctl_index = elem->control; int index = line_out_remap(private, ctl_index); - int oval, val, err = 0; + int oval, val, err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; oval = private->vol_sw_hw_switch[index]; val = !!ucontrol->value.enumerated.item[0]; if (oval == val) - goto unlock; + return 0; err = scarlett2_sw_hw_change(mixer, ctl_index, val); - if (err == 0) - err = 1; -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static const struct snd_kcontrol_new scarlett2_sw_hw_enum_ctl = { @@ -4924,22 +4755,16 @@ static int scarlett2_level_enum_ctl_info(struct snd_kcontrol *kctl, struct scarlett2_data *private = mixer->private_data; int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; err = scarlett2_check_autogain_updated(mixer); if (err < 0) - goto unlock; + return err; - err = snd_ctl_enum_info(uinfo, 1, 2, values); - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return snd_ctl_enum_info(uinfo, 1, 2, values); } static int scarlett2_level_enum_ctl_get(struct snd_kcontrol *kctl, @@ -4949,28 +4774,22 @@ static int scarlett2_level_enum_ctl_get(struct snd_kcontrol *kctl, struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; const struct scarlett2_device_info *info = private->info; - int index = elem->control + info->level_input_first; - int err = 0; + int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; if (private->input_level_updated) { err = scarlett2_update_input_level(mixer); if (err < 0) - goto unlock; + return err; } ucontrol->value.enumerated.item[0] = scarlett2_decode_muteable( private->level_switch[index]); - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return 0; } static int scarlett2_level_enum_ctl_put(struct snd_kcontrol *kctl, @@ -4980,26 +4799,23 @@ static int scarlett2_level_enum_ctl_put(struct snd_kcontrol *kctl, struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; const struct scarlett2_device_info *info = private->info; - int index = elem->control + info->level_input_first; int oval, val, err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; err = scarlett2_check_put_during_autogain(mixer); if (err < 0) - goto unlock; + return err; oval = private->level_switch[index]; val = !!ucontrol->value.enumerated.item[0]; if (oval == val) - goto unlock; + return 0; private->level_switch[index] = val; @@ -5010,12 +4826,8 @@ static int scarlett2_level_enum_ctl_put(struct snd_kcontrol *kctl, /* Send switch change to the device */ err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_LEVEL_SWITCH, index, val); - if (err == 0) - err = 1; -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static const struct snd_kcontrol_new scarlett2_level_enum_ctl = { @@ -5049,26 +4861,21 @@ static int scarlett2_pad_ctl_get(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int err = 0; + int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; if (private->input_pad_updated) { err = scarlett2_update_input_pad(mixer); if (err < 0) - goto unlock; + return err; } ucontrol->value.integer.value[0] = private->pad_switch[elem->control]; - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return 0; } static int scarlett2_pad_ctl_put(struct snd_kcontrol *kctl, @@ -5077,34 +4884,27 @@ static int scarlett2_pad_ctl_put(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int index = elem->control; - int oval, val, err = 0; + int oval, val, err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; oval = private->pad_switch[index]; val = !!ucontrol->value.integer.value[0]; if (oval == val) - goto unlock; + return 0; private->pad_switch[index] = val; /* Send switch change to the device */ err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_PAD_SWITCH, index, val); - if (err == 0) - err = 1; -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static const struct snd_kcontrol_new scarlett2_pad_ctl = { @@ -5138,25 +4938,20 @@ static int scarlett2_air_ctl_get(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int err = 0; + int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; if (private->input_air_updated) { err = scarlett2_update_input_air(mixer); if (err < 0) - goto unlock; + return err; } ucontrol->value.integer.value[0] = private->air_switch[elem->control]; - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return 0; } static int scarlett2_air_ctl_put(struct snd_kcontrol *kctl, @@ -5165,38 +4960,31 @@ static int scarlett2_air_ctl_put(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int index = elem->control; int oval, val, err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; err = scarlett2_check_put_during_autogain(mixer); if (err < 0) - goto unlock; + return err; oval = private->air_switch[index]; val = ucontrol->value.integer.value[0]; if (oval == val) - goto unlock; + return 0; private->air_switch[index] = val; /* Send switch change to the device */ err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_AIR_SWITCH, index, val); - if (err == 0) - err = 1; -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static int scarlett2_air_with_drive_ctl_info( @@ -5210,22 +4998,16 @@ static int scarlett2_air_with_drive_ctl_info( struct scarlett2_data *private = mixer->private_data; int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; err = scarlett2_check_autogain_updated(mixer); if (err < 0) - goto unlock; + return err; - err = snd_ctl_enum_info(uinfo, 1, 3, values); - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return snd_ctl_enum_info(uinfo, 1, 3, values); } static const struct snd_kcontrol_new scarlett2_air_ctl[2] = { @@ -5268,25 +5050,20 @@ static int scarlett2_dsp_ctl_get(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int err = 0; + int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; if (private->input_dsp_updated) { err = scarlett2_update_input_dsp(mixer); if (err < 0) - goto unlock; + return err; } ucontrol->value.integer.value[0] = private->dsp_switch[elem->control]; - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return 0; } static int scarlett2_dsp_ctl_put(struct snd_kcontrol *kctl, @@ -5295,38 +5072,31 @@ static int scarlett2_dsp_ctl_put(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int index = elem->control; int oval, val, err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; err = scarlett2_check_put_during_autogain(mixer); if (err < 0) - goto unlock; + return err; oval = private->dsp_switch[index]; val = ucontrol->value.integer.value[0]; if (oval == val) - goto unlock; + return 0; private->dsp_switch[index] = val; /* Send switch change to the device */ err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_DSP_SWITCH, index, val); - if (err == 0) - err = 1; -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static const struct snd_kcontrol_new scarlett2_dsp_ctl = { @@ -5389,30 +5159,26 @@ static int scarlett2_compressor_ctl_put( struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int index = elem->control; int channel = index / SCARLETT2_COMPRESSOR_PARAM_COUNT; int param_index = index % SCARLETT2_COMPRESSOR_PARAM_COUNT; const struct compressor_param *param = &compressor_params[param_index]; - int oval, val, err; s32 scaled_val; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; err = scarlett2_check_put_during_autogain(mixer); if (err < 0) - goto unlock; + return err; oval = private->compressor_values[index]; val = ucontrol->value.integer.value[0]; if (oval == val) - goto unlock; + return 0; private->compressor_values[index] = val; @@ -5427,19 +5193,12 @@ static int scarlett2_compressor_ctl_put( err = scarlett2_usb_set_data( mixer, private->config_set->param_buf_addr + 1, 1, channel); if (err < 0) - goto unlock; + return err; err = scarlett2_usb_set_config( mixer, SCARLETT2_CONFIG_COMPRESSOR_PARAMS, index, scaled_val); - if (err < 0) - goto unlock; - if (err == 0) - err = 1; - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static int scarlett2_compressor_ctl_info( @@ -5495,20 +5254,18 @@ static int scarlett2_precomp_flt_switch_ctl_put( struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int oval, val, err = 0; + int oval, val, err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; oval = private->precomp_flt_switch[elem->control]; val = ucontrol->value.integer.value[0]; if (oval == val) - goto unlock; + return 0; private->precomp_flt_switch[elem->control] = val; @@ -5516,12 +5273,8 @@ static int scarlett2_precomp_flt_switch_ctl_put( err = scarlett2_usb_set_config( mixer, SCARLETT2_CONFIG_PRECOMP_FLT_SWITCH, elem->control, val); - if (err == 0) - err = 1; -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static int scarlett2_peq_flt_switch_ctl_put( @@ -5530,20 +5283,18 @@ static int scarlett2_peq_flt_switch_ctl_put( struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int oval, val, err = 0; + int oval, val, err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; oval = private->peq_flt_switch[elem->control]; val = ucontrol->value.integer.value[0]; if (oval == val) - goto unlock; + return 0; private->peq_flt_switch[elem->control] = val; @@ -5551,12 +5302,8 @@ static int scarlett2_peq_flt_switch_ctl_put( err = scarlett2_usb_set_config( mixer, SCARLETT2_CONFIG_PEQ_FLT_SWITCH, elem->control, val); - if (err == 0) - err = 1; -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static const struct snd_kcontrol_new scarlett2_precomp_flt_switch_ctl = { @@ -5677,20 +5424,17 @@ static int scarlett2_precomp_flt_ctl_put( struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int index = elem->control * SCARLETT2_BIQUAD_COEFFS; int i, oval, val, err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; err = scarlett2_check_put_during_autogain(mixer); if (err < 0) - goto unlock; + return err; /* Check if any of the values have changed; if not, return */ for (i = 0; i < SCARLETT2_BIQUAD_COEFFS; i++) { @@ -5701,7 +5445,7 @@ static int scarlett2_precomp_flt_ctl_put( } if (i == SCARLETT2_BIQUAD_COEFFS) - goto unlock; + return 0; /* Update the values */ for (i = 0; i < SCARLETT2_BIQUAD_COEFFS; i++) @@ -5712,19 +5456,14 @@ static int scarlett2_precomp_flt_ctl_put( err = scarlett2_usb_set_data( mixer, private->config_set->param_buf_addr, 1, index); if (err < 0) - goto unlock; + return err; err = scarlett2_usb_set_config_buf( mixer, SCARLETT2_CONFIG_PRECOMP_FLT_PARAMS, index, SCARLETT2_BIQUAD_COEFFS, &private->precomp_flt_values[index]); - if (err == 0) - err = 1; - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static int scarlett2_peq_flt_ctl_put( @@ -5734,7 +5473,6 @@ static int scarlett2_peq_flt_ctl_put( struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; const struct scarlett2_device_info *info = private->info; - int src_index = elem->control * SCARLETT2_BIQUAD_COEFFS; int dst_index = ( elem->control / @@ -5744,16 +5482,14 @@ static int scarlett2_peq_flt_ctl_put( ) * SCARLETT2_BIQUAD_COEFFS; int i, oval, val, err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; err = scarlett2_check_put_during_autogain(mixer); if (err < 0) - goto unlock; + return err; /* Check if any of the values have changed; if not, return */ for (i = 0; i < SCARLETT2_BIQUAD_COEFFS; i++) { @@ -5764,7 +5500,7 @@ static int scarlett2_peq_flt_ctl_put( } if (i == SCARLETT2_BIQUAD_COEFFS) - goto unlock; + return 0; /* Update the values */ for (i = 0; i < SCARLETT2_BIQUAD_COEFFS; i++) @@ -5775,19 +5511,14 @@ static int scarlett2_peq_flt_ctl_put( err = scarlett2_usb_set_data( mixer, private->config_set->param_buf_addr, 1, dst_index); if (err < 0) - goto unlock; + return err; err = scarlett2_usb_set_config_buf( mixer, SCARLETT2_CONFIG_PEQ_FLT_PARAMS, dst_index, SCARLETT2_BIQUAD_COEFFS, &private->peq_flt_values[src_index]); - if (err == 0) - err = 1; - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static int scarlett2_flt_ctl_info( @@ -5840,26 +5571,21 @@ static int scarlett2_input_mute_ctl_get(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int err = 0; + int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; if (private->input_mute_updated) { err = scarlett2_update_input_mute(mixer); if (err < 0) - goto unlock; + return err; } ucontrol->value.integer.value[0] = private->input_mute_switch[elem->control]; - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return 0; } static int scarlett2_input_mute_ctl_put(struct snd_kcontrol *kctl, @@ -5868,26 +5594,23 @@ static int scarlett2_input_mute_ctl_put(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int index = elem->control; int oval, val, err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; err = scarlett2_check_put_during_autogain(mixer); if (err < 0) - goto unlock; + return err; oval = private->input_mute_switch[index]; val = ucontrol->value.integer.value[0]; if (oval == val) - goto unlock; + return 0; private->input_mute_switch[index] = val; @@ -5895,12 +5618,8 @@ static int scarlett2_input_mute_ctl_put(struct snd_kcontrol *kctl, err = scarlett2_usb_set_config( mixer, SCARLETT2_CONFIG_INPUT_MUTE_SWITCH, index, val); - if (err == 0) - err = 1; -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static const struct snd_kcontrol_new scarlett2_input_mute_ctl = { @@ -6011,23 +5730,18 @@ static int scarlett2_phantom_ctl_get(struct snd_kcontrol *kctl, struct scarlett2_data *private = mixer->private_data; int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; err = scarlett2_check_input_phantom_updated(mixer); if (err < 0) - goto unlock; + return err; ucontrol->value.integer.value[0] = scarlett2_decode_muteable( private->phantom_switch[elem->control]); - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return 0; } static int scarlett2_phantom_ctl_put(struct snd_kcontrol *kctl, @@ -6037,26 +5751,23 @@ static int scarlett2_phantom_ctl_put(struct snd_kcontrol *kctl, struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; const struct scarlett2_device_info *info = private->info; - int index = elem->control; int oval, val, err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; err = scarlett2_check_put_during_autogain(mixer); if (err < 0) - goto unlock; + return err; oval = private->phantom_switch[index]; val = !!ucontrol->value.integer.value[0]; if (oval == val) - goto unlock; + return 0; private->phantom_switch[index] = val; @@ -6067,15 +5778,10 @@ static int scarlett2_phantom_ctl_put(struct snd_kcontrol *kctl, /* Send switch change to the device */ err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_PHANTOM_SWITCH, index + info->phantom_first, val); - if (err == 0) - err = 1; - scarlett2_phantom_update_access(mixer); scarlett2_phantom_notify_access(mixer); -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static const struct snd_kcontrol_new scarlett2_phantom_ctl = { @@ -6104,34 +5810,27 @@ static int scarlett2_phantom_persistence_ctl_put( struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int index = elem->control; - int oval, val, err = 0; + int oval, val, err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; oval = private->phantom_persistence; val = !!ucontrol->value.integer.value[0]; if (oval == val) - goto unlock; + return 0; private->phantom_persistence = val; /* Send switch change to the device */ err = scarlett2_usb_set_config( mixer, SCARLETT2_CONFIG_PHANTOM_PERSISTENCE, index, val); - if (err == 0) - err = 1; -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static const struct snd_kcontrol_new scarlett2_phantom_persistence_ctl = { @@ -6222,25 +5921,20 @@ static int scarlett2_speaker_switch_enum_ctl_get( struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int err = 0; + int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; if (private->monitor_other_updated) { err = scarlett2_update_monitor_other(mixer); if (err < 0) - goto unlock; + return err; } ucontrol->value.enumerated.item[0] = private->speaker_switching_switch; - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return 0; } /* when speaker switching gets enabled, switch the main/alt speakers @@ -6306,21 +6000,18 @@ static int scarlett2_speaker_switch_enum_ctl_put( struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; + int oval, val, err; - int oval, val, err = 0; + guard(mutex)(&private->data_mutex); - mutex_lock(&private->data_mutex); - - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; oval = private->speaker_switching_switch; val = min(ucontrol->value.enumerated.item[0], 2U); if (oval == val) - goto unlock; + return 0; private->speaker_switching_switch = val; @@ -6329,14 +6020,14 @@ static int scarlett2_speaker_switch_enum_ctl_put( mixer, SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE, 0, !!val); if (err < 0) - goto unlock; + return err; /* if speaker switching is enabled, select main or alt */ err = scarlett2_usb_set_config( mixer, SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH, 0, val == 2); if (err < 0) - goto unlock; + return err; /* update controls if speaker switching gets enabled or disabled */ if (!oval && val) @@ -6344,12 +6035,7 @@ static int scarlett2_speaker_switch_enum_ctl_put( else if (oval && !val) scarlett2_speaker_switch_disable(mixer); - if (err == 0) - err = 1; - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static const struct snd_kcontrol_new scarlett2_speaker_switch_enum_ctl = { @@ -6392,25 +6078,20 @@ static int scarlett2_talkback_enum_ctl_get( struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int err = 0; + int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; if (private->monitor_other_updated) { err = scarlett2_update_monitor_other(mixer); if (err < 0) - goto unlock; + return err; } ucontrol->value.enumerated.item[0] = private->talkback_switch; - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return 0; } static int scarlett2_talkback_enum_ctl_put( @@ -6419,21 +6100,18 @@ static int scarlett2_talkback_enum_ctl_put( struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; + int oval, val, err; - int oval, val, err = 0; + guard(mutex)(&private->data_mutex); - mutex_lock(&private->data_mutex); - - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; oval = private->talkback_switch; val = min(ucontrol->value.enumerated.item[0], 2U); if (oval == val) - goto unlock; + return 0; private->talkback_switch = val; @@ -6442,18 +6120,14 @@ static int scarlett2_talkback_enum_ctl_put( mixer, SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE, 1, !!val); if (err < 0) - goto unlock; + return err; /* if talkback is enabled, select main or alt */ err = scarlett2_usb_set_config( mixer, SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH, 1, val == 2); - if (err == 0) - err = 1; -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static const struct snd_kcontrol_new scarlett2_talkback_enum_ctl = { @@ -6484,21 +6158,19 @@ static int scarlett2_talkback_map_ctl_put( struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; int index = elem->control; - int oval, val, err = 0, i; + int oval, val, err, i; u16 bitmap = 0; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; oval = private->talkback_map[index]; val = !!ucontrol->value.integer.value[0]; if (oval == val) - goto unlock; + return 0; private->talkback_map[index] = val; @@ -6508,12 +6180,8 @@ static int scarlett2_talkback_map_ctl_put( /* Send updated bitmap to the device */ err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_TALKBACK_MAP, 0, bitmap); - if (err == 0) - err = 1; -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static const struct snd_kcontrol_new scarlett2_talkback_map_ctl = { @@ -6561,25 +6229,20 @@ static int scarlett2_dim_mute_ctl_get(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int err = 0; + int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; if (private->dim_mute_updated) { err = scarlett2_update_dim_mute(mixer); if (err < 0) - goto unlock; + return err; } ucontrol->value.integer.value[0] = private->dim_mute[elem->control]; - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return 0; } static int scarlett2_dim_mute_ctl_put(struct snd_kcontrol *kctl, @@ -6589,29 +6252,24 @@ static int scarlett2_dim_mute_ctl_put(struct snd_kcontrol *kctl, struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; int index = elem->control; - int oval, val, err = 0, i; + int oval, val, err, i; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; oval = private->dim_mute[index]; val = !!ucontrol->value.integer.value[0]; if (oval == val) - goto unlock; + return 0; private->dim_mute[index] = val; /* Send switch change to the device */ err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_DIM_MUTE, index, val); - if (err == 0) - err = 1; - if (index == SCARLETT2_BUTTON_MUTE) for (i = 0; i < private->num_line_out; i++) { int line_index = line_out_remap(private, i); @@ -6624,9 +6282,7 @@ static int scarlett2_dim_mute_ctl_put(struct snd_kcontrol *kctl, } } -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static const struct snd_kcontrol_new scarlett2_dim_mute_ctl = { @@ -7038,25 +6694,20 @@ static int scarlett2_mixer_ctl_get(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int err = 0; + int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; if (private->mix_updated) { err = scarlett2_update_mix(mixer); if (err < 0) - goto unlock; + return err; } ucontrol->value.integer.value[0] = private->mix[elem->control]; - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return 0; } static int scarlett2_mixer_ctl_put(struct snd_kcontrol *kctl, @@ -7065,15 +6716,13 @@ static int scarlett2_mixer_ctl_put(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int oval, val, mix_num, err = 0; + int oval, val, mix_num, err; int index = elem->control; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; oval = private->mix[index]; val = clamp(ucontrol->value.integer.value[0], @@ -7081,16 +6730,12 @@ static int scarlett2_mixer_ctl_put(struct snd_kcontrol *kctl, mix_num = index / private->num_mix_in; if (oval == val) - goto unlock; + return 0; private->mix[index] = val; err = scarlett2_usb_set_mix(mixer, mix_num); - if (err == 0) - err = 1; -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static const DECLARE_TLV_DB_MINMAX( @@ -7177,25 +6822,20 @@ static int scarlett2_direct_monitor_ctl_get( struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int err = 0; + int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; if (private->direct_monitor_updated) { err = scarlett2_update_direct_monitor(mixer); if (err < 0) - goto unlock; + return err; } ucontrol->value.enumerated.item[0] = private->direct_monitor_switch; - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return 0; } static int scarlett2_direct_monitor_ctl_put( @@ -7204,34 +6844,27 @@ static int scarlett2_direct_monitor_ctl_put( struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int index = elem->control; - int oval, val, err = 0; + int oval, val, err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; oval = private->direct_monitor_switch; val = min(ucontrol->value.enumerated.item[0], 2U); if (oval == val) - goto unlock; + return 0; private->direct_monitor_switch = val; /* Send switch change to the device */ err = scarlett2_usb_set_config( mixer, SCARLETT2_CONFIG_DIRECT_MONITOR, index, val); - if (err == 0) - err = 1; -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static int scarlett2_direct_monitor_stereo_enum_ctl_info( @@ -7281,33 +6914,27 @@ static int scarlett2_monitor_mix_ctl_put(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int oval, val, err = 0; + int oval, val, err; int index = elem->control; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; oval = private->monitor_mix[index]; val = clamp(ucontrol->value.integer.value[0], 0L, (long)SCARLETT2_MIXER_MAX_VALUE); if (oval == val) - goto unlock; + return 0; private->monitor_mix[index] = val; err = scarlett2_usb_set_config( mixer, SCARLETT2_CONFIG_DIRECT_MONITOR_GAIN, index, scarlett2_mixer_values[val]); - if (err == 0) - err = 1; -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static const struct snd_kcontrol_new scarlett2_monitor_mix_ctl = { @@ -7433,25 +7060,20 @@ static int scarlett2_mux_src_enum_ctl_get(struct snd_kcontrol *kctl, struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; int index = line_out_remap(private, elem->control); - int err = 0; + int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; if (private->mux_updated) { err = scarlett2_usb_get_mux(mixer); if (err < 0) - goto unlock; + return err; } ucontrol->value.enumerated.item[0] = private->mux[index]; - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return 0; } static int scarlett2_mux_src_enum_ctl_put(struct snd_kcontrol *kctl, @@ -7461,30 +7083,24 @@ static int scarlett2_mux_src_enum_ctl_put(struct snd_kcontrol *kctl, struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; int index = line_out_remap(private, elem->control); - int oval, val, err = 0; + int oval, val, err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; oval = private->mux[index]; val = min(ucontrol->value.enumerated.item[0], private->num_mux_srcs - 1U); if (oval == val) - goto unlock; + return 0; private->mux[index] = val; err = scarlett2_usb_set_mux(mixer); - if (err == 0) - err = 1; -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static const struct snd_kcontrol_new scarlett2_mux_src_enum_ctl = { @@ -7561,17 +7177,15 @@ static int scarlett2_meter_ctl_get(struct snd_kcontrol *kctl, u16 meter_levels[SCARLETT2_MAX_METERS]; int i, err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; err = scarlett2_usb_get_meter_levels(mixer, elem->channels, meter_levels); if (err < 0) - goto unlock; + return err; /* copy & translate from meter_levels[] using meter_level_map[] */ for (i = 0; i < elem->channels; i++) { @@ -7586,10 +7200,7 @@ static int scarlett2_meter_ctl_get(struct snd_kcontrol *kctl, ucontrol->value.integer.value[i] = value; } -unlock: - mutex_unlock(&private->data_mutex); - - return err; + return 0; } static const struct snd_kcontrol_new scarlett2_meter_ctl = { @@ -7631,33 +7242,26 @@ static int scarlett2_msd_ctl_put(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; + int oval, val, err; - int oval, val, err = 0; + guard(mutex)(&private->data_mutex); - mutex_lock(&private->data_mutex); - - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; oval = private->msd_switch; val = !!ucontrol->value.integer.value[0]; if (oval == val) - goto unlock; + return 0; private->msd_switch = val; /* Send switch change to the device */ err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_MSD_SWITCH, 0, val); - if (err == 0) - err = 1; -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static const struct snd_kcontrol_new scarlett2_msd_ctl = { @@ -7702,21 +7306,18 @@ static int scarlett2_standalone_ctl_put(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; + int oval, val, err; - int oval, val, err = 0; + guard(mutex)(&private->data_mutex); - mutex_lock(&private->data_mutex); - - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; oval = private->standalone_switch; val = !!ucontrol->value.integer.value[0]; if (oval == val) - goto unlock; + return 0; private->standalone_switch = val; @@ -7724,12 +7325,8 @@ static int scarlett2_standalone_ctl_put(struct snd_kcontrol *kctl, err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_STANDALONE_SWITCH, 0, val); - if (err == 0) - err = 1; -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static const struct snd_kcontrol_new scarlett2_standalone_ctl = { @@ -7789,20 +7386,17 @@ static int scarlett2_power_status_ctl_get(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int err = 0; + int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); if (private->power_status_updated) { err = scarlett2_update_power_status(mixer); if (err < 0) - goto unlock; + return err; } ucontrol->value.integer.value[0] = private->power_status; - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return 0; } static int scarlett2_power_status_ctl_info( @@ -7864,25 +7458,20 @@ static int scarlett2_bluetooth_volume_ctl_get(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int err = 0; + int err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; if (private->bluetooth_updated) { err = scarlett2_update_bluetooth_volume(mixer); if (err < 0) - goto unlock; + return err; } ucontrol->value.integer.value[0] = private->bluetooth_volume; - -unlock: - mutex_unlock(&private->data_mutex); - return err; + return 0; } static int scarlett2_bluetooth_volume_ctl_put(struct snd_kcontrol *kctl, @@ -7891,32 +7480,26 @@ static int scarlett2_bluetooth_volume_ctl_put(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int oval, val, err = 0; + int oval, val, err; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); - if (private->hwdep_in_use) { - err = -EBUSY; - goto unlock; - } + if (private->hwdep_in_use) + return -EBUSY; oval = private->bluetooth_volume; val = clamp(ucontrol->value.integer.value[0], 0L, (long)SCARLETT2_MAX_BLUETOOTH_VOLUME); if (oval == val) - goto unlock; + return 0; private->bluetooth_volume = val; err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_BLUETOOTH_VOLUME, 0, val); - if (err == 0) - err = 1; -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static int scarlett2_bluetooth_volume_ctl_info( @@ -8011,39 +7594,31 @@ static int scarlett2_spdif_mode_ctl_put(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int oval, val, err = 0; + int oval, val, err; int i; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); oval = private->spdif_mode; val = ucontrol->value.enumerated.item[0]; - if (val < 0) { - err = -EINVAL; - goto unlock; - } + if (val < 0) + return -EINVAL; for (i = 0; i <= val; i++) - if (private->info->spdif_mode_values[i] == 0xff) { - err = -EINVAL; - goto unlock; - } + if (private->info->spdif_mode_values[i] == 0xff) + return -EINVAL; if (oval == val) - goto unlock; + return 0; private->spdif_mode = val; err = scarlett2_usb_set_config( mixer, SCARLETT2_CONFIG_SPDIF_MODE, 0, private->info->spdif_mode_values[val]); - if (!err) - err = 1; -unlock: - mutex_unlock(&private->data_mutex); - return err; + return err < 0 ? err : 1; } static const struct snd_kcontrol_new scarlett2_spdif_mode_ctl = { @@ -9140,9 +8715,8 @@ static int snd_scarlett2_controls_create( */ static void scarlett2_lock(struct scarlett2_data *private) { - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); private->hwdep_in_use = 1; - mutex_unlock(&private->data_mutex); } /* Call SCARLETT2_USB_GET_ERASE to get the erase progress */ @@ -9414,7 +8988,7 @@ static long scarlett2_hwdep_read(struct snd_hwdep *hw, __le32 len; } __packed req; - u8 *resp; + u8 *resp __free(kfree) = NULL; /* Flash segment must first be selected */ if (private->flash_write_state != SCARLETT2_FLASH_WRITE_STATE_SELECTED) @@ -9460,20 +9034,14 @@ static long scarlett2_hwdep_read(struct snd_hwdep *hw, err = scarlett2_usb(mixer, SCARLETT2_USB_READ_SEGMENT, &req, sizeof(req), resp, count); if (err < 0) - goto error; + return err; /* Copy the response to userspace */ - if (copy_to_user(buf, resp, count)) { - err = -EFAULT; - goto error; - } + if (copy_to_user(buf, resp, count)) + return -EFAULT; *offset += count; - err = count; - -error: - kfree(resp); - return err; + return count; } static long scarlett2_hwdep_write(struct snd_hwdep *hw, @@ -9491,7 +9059,7 @@ static long scarlett2_hwdep_write(struct snd_hwdep *hw, __le32 offset; __le32 pad; u8 data[]; - } __packed *req; + } __packed *req __free(kfree) = NULL; /* Calculate the maximum permitted in data[] */ const size_t max_data_size = SCARLETT2_FLASH_RW_MAX - @@ -9545,22 +9113,16 @@ static long scarlett2_hwdep_write(struct snd_hwdep *hw, req->offset = cpu_to_le32(*offset); req->pad = 0; - if (copy_from_user(req->data, buf, count)) { - err = -EFAULT; - goto error; - } + if (copy_from_user(req->data, buf, count)) + return -EFAULT; err = scarlett2_usb(mixer, SCARLETT2_USB_WRITE_SEGMENT, req, len, NULL, 0); if (err < 0) - goto error; + return err; *offset += count; - err = count; - -error: - kfree(req); - return err; + return count; } static int scarlett2_hwdep_release(struct snd_hwdep *hw, struct file *file) @@ -9610,7 +9172,7 @@ static ssize_t scarlett2_devmap_read( loff_t pos) { struct usb_mixer_interface *mixer = entry->private_data; - u8 *resp_buf; + u8 *resp_buf __free(kfree) = NULL; const size_t block_size = SCARLETT2_DEVMAP_BLOCK_SIZE; size_t copied = 0; @@ -9649,15 +9211,11 @@ static ssize_t scarlett2_devmap_read( req = cpu_to_le32(pos / block_size); err = scarlett2_usb(mixer, SCARLETT2_USB_GET_DEVMAP, &req, sizeof(req), resp_buf, read_size); - if (err < 0) { - kfree(resp_buf); + if (err < 0) return copied ? copied : err; - } - if (copy_to_user(buf, resp_buf + offset, copy_size)) { - kfree(resp_buf); + if (copy_to_user(buf, resp_buf + offset, copy_size)) return -EFAULT; - } buf += copy_size; pos += copy_size; @@ -9665,7 +9223,6 @@ static ssize_t scarlett2_devmap_read( count -= copy_size; } - kfree(resp_buf); return copied; } From 6ff0d95774f0c728f96b8f78367318e95e09ee64 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 11 Aug 2025 10:22:29 +0200 Subject: [PATCH 00391/11391] ALSA: 6fire: Clean ups with guard() Simple code cleanups with the guard() for spinlock and mutex. No functional changes. Link: https://patch.msgid.link/20250811082231.31498-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/6fire/chip.c | 40 ++++++++++---------- sound/usb/6fire/midi.c | 21 +++-------- sound/usb/6fire/pcm.c | 83 ++++++++++++++++++------------------------ 3 files changed, 59 insertions(+), 85 deletions(-) diff --git a/sound/usb/6fire/chip.c b/sound/usb/6fire/chip.c index 9eb4bf9b138b..5ff78814e687 100644 --- a/sound/usb/6fire/chip.c +++ b/sound/usb/6fire/chip.c @@ -88,24 +88,22 @@ static int usb6fire_chip_probe(struct usb_interface *intf, struct snd_card *card = NULL; /* look if we already serve this card and return if so */ - mutex_lock(®ister_mutex); - for (i = 0; i < SNDRV_CARDS; i++) { - if (devices[i] == device) { - if (chips[i]) - chips[i]->intf_count++; - usb_set_intfdata(intf, chips[i]); - mutex_unlock(®ister_mutex); - return 0; - } else if (!devices[i] && regidx < 0) - regidx = i; + scoped_guard(mutex, ®ister_mutex) { + for (i = 0; i < SNDRV_CARDS; i++) { + if (devices[i] == device) { + if (chips[i]) + chips[i]->intf_count++; + usb_set_intfdata(intf, chips[i]); + return 0; + } else if (!devices[i] && regidx < 0) + regidx = i; + } + if (regidx < 0) { + dev_err(&intf->dev, "too many cards registered.\n"); + return -ENODEV; + } + devices[regidx] = device; } - if (regidx < 0) { - mutex_unlock(®ister_mutex); - dev_err(&intf->dev, "too many cards registered.\n"); - return -ENODEV; - } - devices[regidx] = device; - mutex_unlock(®ister_mutex); /* check, if firmware is present on device, upload it if not */ ret = usb6fire_fw_init(intf); @@ -175,10 +173,10 @@ static void usb6fire_chip_disconnect(struct usb_interface *intf) if (chip) { /* if !chip, fw upload has been performed */ chip->intf_count--; if (!chip->intf_count) { - mutex_lock(®ister_mutex); - devices[chip->regidx] = NULL; - chips[chip->regidx] = NULL; - mutex_unlock(®ister_mutex); + scoped_guard(mutex, ®ister_mutex) { + devices[chip->regidx] = NULL; + chips[chip->regidx] = NULL; + } chip->shutdown = true; usb6fire_chip_abort(chip); diff --git a/sound/usb/6fire/midi.c b/sound/usb/6fire/midi.c index 923f7767e62f..4d1eeb32c5fe 100644 --- a/sound/usb/6fire/midi.c +++ b/sound/usb/6fire/midi.c @@ -23,9 +23,8 @@ static void usb6fire_midi_out_handler(struct urb *urb) { struct midi_runtime *rt = urb->context; int ret; - unsigned long flags; - spin_lock_irqsave(&rt->out_lock, flags); + guard(spinlock_irqsave)(&rt->out_lock); if (rt->out) { ret = snd_rawmidi_transmit(rt->out, rt->out_buffer + 4, @@ -43,18 +42,14 @@ static void usb6fire_midi_out_handler(struct urb *urb) } else /* no more data to transmit */ rt->out = NULL; } - spin_unlock_irqrestore(&rt->out_lock, flags); } static void usb6fire_midi_in_received( struct midi_runtime *rt, u8 *data, int length) { - unsigned long flags; - - spin_lock_irqsave(&rt->in_lock, flags); + guard(spinlock_irqsave)(&rt->in_lock); if (rt->in) snd_rawmidi_receive(rt->in, data, length); - spin_unlock_irqrestore(&rt->in_lock, flags); } static int usb6fire_midi_out_open(struct snd_rawmidi_substream *alsa_sub) @@ -73,14 +68,11 @@ static void usb6fire_midi_out_trigger( struct midi_runtime *rt = alsa_sub->rmidi->private_data; struct urb *urb = &rt->out_urb; __s8 ret; - unsigned long flags; - spin_lock_irqsave(&rt->out_lock, flags); + guard(spinlock_irqsave)(&rt->out_lock); if (up) { /* start transfer */ - if (rt->out) { /* we are already transmitting so just return */ - spin_unlock_irqrestore(&rt->out_lock, flags); + if (rt->out) /* we are already transmitting so just return */ return; - } ret = snd_rawmidi_transmit(alsa_sub, rt->out_buffer + 4, MIDI_BUFSIZE - 4); @@ -99,7 +91,6 @@ static void usb6fire_midi_out_trigger( } } else if (rt->out == alsa_sub) rt->out = NULL; - spin_unlock_irqrestore(&rt->out_lock, flags); } static void usb6fire_midi_out_drain(struct snd_rawmidi_substream *alsa_sub) @@ -125,14 +116,12 @@ static void usb6fire_midi_in_trigger( struct snd_rawmidi_substream *alsa_sub, int up) { struct midi_runtime *rt = alsa_sub->rmidi->private_data; - unsigned long flags; - spin_lock_irqsave(&rt->in_lock, flags); + guard(spinlock_irqsave)(&rt->in_lock); if (up) rt->in = alsa_sub; else rt->in = NULL; - spin_unlock_irqrestore(&rt->in_lock, flags); } static const struct snd_rawmidi_ops out_ops = { diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c index d53cad97889a..08515da5dcc8 100644 --- a/sound/usb/6fire/pcm.c +++ b/sound/usb/6fire/pcm.c @@ -289,7 +289,7 @@ static void usb6fire_pcm_in_urb_handler(struct urb *usb_urb) struct pcm_urb *out_urb = in_urb->peer; struct pcm_runtime *rt = in_urb->chip->pcm; struct pcm_substream *sub; - unsigned long flags; + bool period_elapsed; int total_length = 0; int frame_count; int frame; @@ -313,17 +313,18 @@ static void usb6fire_pcm_in_urb_handler(struct urb *usb_urb) /* receive our capture data */ sub = &rt->capture; - spin_lock_irqsave(&sub->lock, flags); - if (sub->active) { - usb6fire_pcm_capture(sub, in_urb); - if (sub->period_off >= sub->instance->runtime->period_size) { - sub->period_off %= sub->instance->runtime->period_size; - spin_unlock_irqrestore(&sub->lock, flags); - snd_pcm_period_elapsed(sub->instance); - } else - spin_unlock_irqrestore(&sub->lock, flags); - } else - spin_unlock_irqrestore(&sub->lock, flags); + period_elapsed = false; + scoped_guard(spinlock_irqsave, &sub->lock) { + if (sub->active) { + usb6fire_pcm_capture(sub, in_urb); + if (sub->period_off >= sub->instance->runtime->period_size) { + sub->period_off %= sub->instance->runtime->period_size; + period_elapsed = true; + } + } + } + if (period_elapsed) + snd_pcm_period_elapsed(sub->instance); /* setup out urb structure */ for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) { @@ -338,17 +339,18 @@ static void usb6fire_pcm_in_urb_handler(struct urb *usb_urb) /* now send our playback data (if a free out urb was found) */ sub = &rt->playback; - spin_lock_irqsave(&sub->lock, flags); - if (sub->active) { - usb6fire_pcm_playback(sub, out_urb); - if (sub->period_off >= sub->instance->runtime->period_size) { - sub->period_off %= sub->instance->runtime->period_size; - spin_unlock_irqrestore(&sub->lock, flags); - snd_pcm_period_elapsed(sub->instance); - } else - spin_unlock_irqrestore(&sub->lock, flags); - } else - spin_unlock_irqrestore(&sub->lock, flags); + period_elapsed = false; + scoped_guard(spinlock_irqsave, &sub->lock) { + if (sub->active) { + usb6fire_pcm_playback(sub, out_urb); + if (sub->period_off >= sub->instance->runtime->period_size) { + sub->period_off %= sub->instance->runtime->period_size; + period_elapsed = true; + } + } + } + if (period_elapsed) + snd_pcm_period_elapsed(sub->instance); /* setup the 4th byte of each sample (0x40 for analog channels) */ dest = out_urb->buffer; @@ -392,7 +394,7 @@ static int usb6fire_pcm_open(struct snd_pcm_substream *alsa_sub) if (rt->panic) return -EPIPE; - mutex_lock(&rt->stream_mutex); + guard(mutex)(&rt->stream_mutex); alsa_rt->hw = pcm_hw; if (alsa_sub->stream == SNDRV_PCM_STREAM_PLAYBACK) { @@ -408,14 +410,12 @@ static int usb6fire_pcm_open(struct snd_pcm_substream *alsa_sub) } if (!sub) { - mutex_unlock(&rt->stream_mutex); dev_err(&rt->chip->dev->dev, "invalid stream type.\n"); return -EINVAL; } sub->instance = alsa_sub; sub->active = false; - mutex_unlock(&rt->stream_mutex); return 0; } @@ -423,18 +423,17 @@ static int usb6fire_pcm_close(struct snd_pcm_substream *alsa_sub) { struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub); - unsigned long flags; if (rt->panic) return 0; - mutex_lock(&rt->stream_mutex); + guard(mutex)(&rt->stream_mutex); if (sub) { /* deactivate substream */ - spin_lock_irqsave(&sub->lock, flags); - sub->instance = NULL; - sub->active = false; - spin_unlock_irqrestore(&sub->lock, flags); + scoped_guard(spinlock_irqsave, &sub->lock) { + sub->instance = NULL; + sub->active = false; + } /* all substreams closed? if so, stop streaming */ if (!rt->playback.instance && !rt->capture.instance) { @@ -442,7 +441,6 @@ static int usb6fire_pcm_close(struct snd_pcm_substream *alsa_sub) rt->rate = ARRAY_SIZE(rates); } } - mutex_unlock(&rt->stream_mutex); return 0; } @@ -458,7 +456,7 @@ static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub) if (!sub) return -ENODEV; - mutex_lock(&rt->stream_mutex); + guard(mutex)(&rt->stream_mutex); sub->dma_off = 0; sub->period_off = 0; @@ -467,7 +465,6 @@ static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub) if (alsa_rt->rate == rates[rt->rate]) break; if (rt->rate == ARRAY_SIZE(rates)) { - mutex_unlock(&rt->stream_mutex); dev_err(&rt->chip->dev->dev, "invalid rate %d in prepare.\n", alsa_rt->rate); @@ -475,19 +472,15 @@ static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub) } ret = usb6fire_pcm_set_rate(rt); - if (ret) { - mutex_unlock(&rt->stream_mutex); + if (ret) return ret; - } ret = usb6fire_pcm_stream_start(rt); if (ret) { - mutex_unlock(&rt->stream_mutex); dev_err(&rt->chip->dev->dev, "could not start pcm stream.\n"); return ret; } } - mutex_unlock(&rt->stream_mutex); return 0; } @@ -495,26 +488,22 @@ static int usb6fire_pcm_trigger(struct snd_pcm_substream *alsa_sub, int cmd) { struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub); struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); - unsigned long flags; if (rt->panic) return -EPIPE; if (!sub) return -ENODEV; + guard(spinlock_irqsave)(&sub->lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - spin_lock_irqsave(&sub->lock, flags); sub->active = true; - spin_unlock_irqrestore(&sub->lock, flags); return 0; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - spin_lock_irqsave(&sub->lock, flags); sub->active = false; - spin_unlock_irqrestore(&sub->lock, flags); return 0; default: @@ -527,15 +516,13 @@ static snd_pcm_uframes_t usb6fire_pcm_pointer( { struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub); struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); - unsigned long flags; snd_pcm_uframes_t ret; if (rt->panic || !sub) return SNDRV_PCM_POS_XRUN; - spin_lock_irqsave(&sub->lock, flags); + guard(spinlock_irqsave)(&sub->lock); ret = sub->dma_off; - spin_unlock_irqrestore(&sub->lock, flags); return ret; } From efea7a57370b956ef612dc603faa2df9126cc3ed Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 11 Aug 2025 10:20:18 +0200 Subject: [PATCH 00392/11391] ALSA: usb-audio: Replace manual mutex/spinlock with guard() This is another code cleanup by replacing the manual mutex or spinlock with guard() macros. usb_audio_disconnect() is slightly refactored (split to another function) to apply guard() cleanly, but the rest are rather straightforward conversions. No functional changes but only code refactoring. Link: https://patch.msgid.link/20250811082019.31052-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/card.c | 39 ++++++------ sound/usb/endpoint.c | 124 ++++++++++++++------------------------ sound/usb/media.c | 6 +- sound/usb/midi.c | 66 ++++++++------------ sound/usb/midi2.c | 16 ++--- sound/usb/mixer_s1810c.c | 35 ++++------- sound/usb/mixer_us16x08.c | 3 +- sound/usb/pcm.c | 72 +++++++++++----------- sound/usb/proc.c | 3 +- 9 files changed, 148 insertions(+), 216 deletions(-) diff --git a/sound/usb/card.c b/sound/usb/card.c index 10d9b7285597..0265206a8e8c 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -900,7 +900,7 @@ static int usb_audio_probe(struct usb_interface *intf, /* check whether it's already registered */ chip = NULL; - mutex_lock(®ister_mutex); + guard(mutex)(®ister_mutex); for (i = 0; i < SNDRV_CARDS; i++) { if (usb_chip[i] && usb_chip[i]->dev == dev) { if (atomic_read(&usb_chip[i]->shutdown)) { @@ -1015,7 +1015,6 @@ static int usb_audio_probe(struct usb_interface *intf, if (platform_ops && platform_ops->connect_cb) platform_ops->connect_cb(chip); - mutex_unlock(®ister_mutex); return 0; @@ -1033,7 +1032,6 @@ static int usb_audio_probe(struct usb_interface *intf, if (!chip->num_interfaces) snd_card_free(chip->card); } - mutex_unlock(®ister_mutex); return err; } @@ -1041,18 +1039,14 @@ static int usb_audio_probe(struct usb_interface *intf, * we need to take care of counter, since disconnection can be called also * many times as well as usb_audio_probe(). */ -static void usb_audio_disconnect(struct usb_interface *intf) +static bool __usb_audio_disconnect(struct usb_interface *intf, + struct snd_usb_audio *chip, + struct snd_card *card) { - struct snd_usb_audio *chip = usb_get_intfdata(intf); - struct snd_card *card; struct list_head *p; - if (chip == USB_AUDIO_IFACE_UNUSED) - return; + guard(mutex)(®ister_mutex); - card = chip->card; - - mutex_lock(®ister_mutex); if (platform_ops && platform_ops->disconnect_cb) platform_ops->disconnect_cb(chip); @@ -1098,13 +1092,24 @@ static void usb_audio_disconnect(struct usb_interface *intf) usb_enable_autosuspend(interface_to_usbdev(intf)); chip->num_interfaces--; - if (chip->num_interfaces <= 0) { - usb_chip[chip->index] = NULL; - mutex_unlock(®ister_mutex); + if (chip->num_interfaces > 0) + return false; + + usb_chip[chip->index] = NULL; + return true; +} + +static void usb_audio_disconnect(struct usb_interface *intf) +{ + struct snd_usb_audio *chip = usb_get_intfdata(intf); + struct snd_card *card; + + if (chip == USB_AUDIO_IFACE_UNUSED) + return; + + card = chip->card; + if (__usb_audio_disconnect(intf, chip, card)) snd_card_free_when_closed(card); - } else { - mutex_unlock(®ister_mutex); - } } /* lock the shutdown (disconnect) task and autoresume */ diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 7b01e7b4e335..880f5afcce60 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -163,22 +163,19 @@ int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep) static int slave_next_packet_size(struct snd_usb_endpoint *ep, unsigned int avail) { - unsigned long flags; unsigned int phase; int ret; if (ep->fill_max) return ep->maxframesize; - spin_lock_irqsave(&ep->lock, flags); + guard(spinlock_irqsave)(&ep->lock); phase = (ep->phase & 0xffff) + (ep->freqm << ep->datainterval); ret = min(phase >> 16, ep->maxframesize); if (avail && ret >= avail) ret = -EAGAIN; else ep->phase = phase; - spin_unlock_irqrestore(&ep->lock, flags); - return ret; } @@ -440,11 +437,8 @@ next_packet_fifo_dequeue(struct snd_usb_endpoint *ep) static void push_back_to_ready_list(struct snd_usb_endpoint *ep, struct snd_urb_ctx *ctx) { - unsigned long flags; - - spin_lock_irqsave(&ep->lock, flags); + guard(spinlock_irqsave)(&ep->lock); list_add_tail(&ctx->ready_list, &ep->ready_playback_urbs); - spin_unlock_irqrestore(&ep->lock, flags); } /* @@ -466,23 +460,21 @@ int snd_usb_queue_pending_output_urbs(struct snd_usb_endpoint *ep, bool implicit_fb = snd_usb_endpoint_implicit_feedback_sink(ep); while (ep_state_running(ep)) { - - unsigned long flags; struct snd_usb_packet_info *packet; struct snd_urb_ctx *ctx = NULL; int err, i; - spin_lock_irqsave(&ep->lock, flags); - if ((!implicit_fb || ep->next_packet_queued > 0) && - !list_empty(&ep->ready_playback_urbs)) { - /* take URB out of FIFO */ - ctx = list_first_entry(&ep->ready_playback_urbs, - struct snd_urb_ctx, ready_list); - list_del_init(&ctx->ready_list); - if (implicit_fb) - packet = next_packet_fifo_dequeue(ep); + scoped_guard(spinlock_irqsave, &ep->lock) { + if ((!implicit_fb || ep->next_packet_queued > 0) && + !list_empty(&ep->ready_playback_urbs)) { + /* take URB out of FIFO */ + ctx = list_first_entry(&ep->ready_playback_urbs, + struct snd_urb_ctx, ready_list); + list_del_init(&ctx->ready_list); + if (implicit_fb) + packet = next_packet_fifo_dequeue(ep); + } } - spin_unlock_irqrestore(&ep->lock, flags); if (ctx == NULL) break; @@ -768,12 +760,8 @@ bool snd_usb_endpoint_compatible(struct snd_usb_audio *chip, const struct audioformat *fp, const struct snd_pcm_hw_params *params) { - bool ret; - - mutex_lock(&chip->mutex); - ret = endpoint_compatible(ep, fp, params); - mutex_unlock(&chip->mutex); - return ret; + guard(mutex)(&chip->mutex); + return endpoint_compatible(ep, fp, params); } /* @@ -799,11 +787,11 @@ snd_usb_endpoint_open(struct snd_usb_audio *chip, struct snd_usb_endpoint *ep; int ep_num = is_sync_ep ? fp->sync_ep : fp->endpoint; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); ep = snd_usb_get_endpoint(chip, ep_num); if (!ep) { usb_audio_err(chip, "Cannot find EP 0x%x to open\n", ep_num); - goto unlock; + return NULL; } if (!ep->opened) { @@ -820,17 +808,13 @@ snd_usb_endpoint_open(struct snd_usb_audio *chip, ep_num, ep->iface, ep->altsetting, ep->ep_idx); ep->iface_ref = iface_ref_find(chip, ep->iface); - if (!ep->iface_ref) { - ep = NULL; - goto unlock; - } + if (!ep->iface_ref) + return NULL; if (fp->protocol != UAC_VERSION_1) { ep->clock_ref = clock_ref_find(chip, fp->clock); - if (!ep->clock_ref) { - ep = NULL; - goto unlock; - } + if (!ep->clock_ref) + return NULL; ep->clock_ref->opened++; } @@ -859,16 +843,13 @@ snd_usb_endpoint_open(struct snd_usb_audio *chip, ep->implicit_fb_sync); } else { - if (WARN_ON(!ep->iface_ref)) { - ep = NULL; - goto unlock; - } + if (WARN_ON(!ep->iface_ref)) + return NULL; if (!endpoint_compatible(ep, fp, params)) { usb_audio_err(chip, "Incompatible EP setup for 0x%x\n", ep_num); - ep = NULL; - goto unlock; + return NULL; } usb_audio_dbg(chip, "Reopened EP 0x%x (count %d)\n", @@ -879,9 +860,6 @@ snd_usb_endpoint_open(struct snd_usb_audio *chip, ep->iface_ref->need_setup = true; ep->opened++; - - unlock: - mutex_unlock(&chip->mutex); return ep; } @@ -964,7 +942,7 @@ static int endpoint_set_interface(struct snd_usb_audio *chip, void snd_usb_endpoint_close(struct snd_usb_audio *chip, struct snd_usb_endpoint *ep) { - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); usb_audio_dbg(chip, "Closing EP 0x%x (count %d)\n", ep->ep_num, ep->opened); @@ -985,7 +963,6 @@ void snd_usb_endpoint_close(struct snd_usb_audio *chip, ep->clock_ref = NULL; usb_audio_dbg(chip, "EP 0x%x closed\n", ep->ep_num); } - mutex_unlock(&chip->mutex); } /* Prepare for suspening EP, called from the main suspend handler */ @@ -1047,7 +1024,6 @@ void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep) static int stop_urbs(struct snd_usb_endpoint *ep, bool force, bool keep_pending) { unsigned int i; - unsigned long flags; if (!force && atomic_read(&ep->running)) return -EBUSY; @@ -1055,11 +1031,11 @@ static int stop_urbs(struct snd_usb_endpoint *ep, bool force, bool keep_pending) if (!ep_state_update(ep, EP_STATE_RUNNING, EP_STATE_STOPPING)) return 0; - spin_lock_irqsave(&ep->lock, flags); - INIT_LIST_HEAD(&ep->ready_playback_urbs); - ep->next_packet_head = 0; - ep->next_packet_queued = 0; - spin_unlock_irqrestore(&ep->lock, flags); + scoped_guard(spinlock_irqsave, &ep->lock) { + INIT_LIST_HEAD(&ep->ready_playback_urbs); + ep->next_packet_head = 0; + ep->next_packet_queued = 0; + } if (keep_pending) return 0; @@ -1360,16 +1336,16 @@ int snd_usb_endpoint_set_params(struct snd_usb_audio *chip, struct snd_usb_endpoint *ep) { const struct audioformat *fmt = ep->cur_audiofmt; - int err = 0; + int err; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); if (!ep->need_setup) - goto unlock; + return 0; /* release old buffers, if any */ err = release_urbs(ep, false); if (err < 0) - goto unlock; + return err; ep->datainterval = fmt->datainterval; ep->maxpacksize = fmt->maxpacksize; @@ -1407,7 +1383,7 @@ int snd_usb_endpoint_set_params(struct snd_usb_audio *chip, usb_audio_dbg(chip, "Set up %d URBS, ret=%d\n", ep->nurbs, err); if (err < 0) - goto unlock; + return err; /* some unit conversions in runtime */ ep->maxframesize = ep->maxpacksize / ep->cur_frame_bytes; @@ -1419,8 +1395,6 @@ int snd_usb_endpoint_set_params(struct snd_usb_audio *chip, err = 0; } - unlock: - mutex_unlock(&chip->mutex); return err; } @@ -1467,11 +1441,11 @@ int snd_usb_endpoint_prepare(struct snd_usb_audio *chip, bool iface_first; int err = 0; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); if (WARN_ON(!ep->iface_ref)) - goto unlock; + return 0; if (!ep->need_prepare) - goto unlock; + return 0; /* If the interface has been already set up, just set EP parameters */ if (!ep->iface_ref->need_setup) { @@ -1481,7 +1455,7 @@ int snd_usb_endpoint_prepare(struct snd_usb_audio *chip, if (ep->cur_audiofmt->protocol == UAC_VERSION_1) { err = init_sample_rate(chip, ep); if (err < 0) - goto unlock; + return err; } goto done; } @@ -1499,37 +1473,33 @@ int snd_usb_endpoint_prepare(struct snd_usb_audio *chip, if (iface_first) { err = endpoint_set_interface(chip, ep, true); if (err < 0) - goto unlock; + return err; } err = snd_usb_init_pitch(chip, ep->cur_audiofmt); if (err < 0) - goto unlock; + return err; err = init_sample_rate(chip, ep); if (err < 0) - goto unlock; + return err; err = snd_usb_select_mode_quirk(chip, ep->cur_audiofmt); if (err < 0) - goto unlock; + return err; /* for UAC2/3, enable the interface altset here at last */ if (!iface_first) { err = endpoint_set_interface(chip, ep, true); if (err < 0) - goto unlock; + return err; } ep->iface_ref->need_setup = false; done: ep->need_prepare = false; - err = 1; - -unlock: - mutex_unlock(&chip->mutex); - return err; + return 1; } EXPORT_SYMBOL_GPL(snd_usb_endpoint_prepare); @@ -1541,14 +1511,13 @@ int snd_usb_endpoint_get_clock_rate(struct snd_usb_audio *chip, int clock) if (!clock) return 0; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); list_for_each_entry(ref, &chip->clock_ref_list, list) { if (ref->clock == clock) { rate = ref->rate; break; } } - mutex_unlock(&chip->mutex); return rate; } @@ -1898,9 +1867,8 @@ static void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep, * If the frequency looks valid, set it. * This value is referred to in prepare_playback_urb(). */ - spin_lock_irqsave(&ep->lock, flags); + guard(spinlock_irqsave)(&ep->lock); ep->freqm = f; - spin_unlock_irqrestore(&ep->lock, flags); } else { /* * Out of range; maybe the shift value is wrong. diff --git a/sound/usb/media.c b/sound/usb/media.c index d48db6f3ae65..0064f8d12422 100644 --- a/sound/usb/media.c +++ b/sound/usb/media.c @@ -140,11 +140,10 @@ int snd_media_start_pipeline(struct snd_usb_substream *subs) if (!mctl) return 0; - mutex_lock(&mctl->media_dev->graph_mutex); + guard(mutex)(&mctl->media_dev->graph_mutex); if (mctl->media_dev->enable_source) ret = mctl->media_dev->enable_source(&mctl->media_entity, &mctl->media_pipe); - mutex_unlock(&mctl->media_dev->graph_mutex); return ret; } @@ -155,10 +154,9 @@ void snd_media_stop_pipeline(struct snd_usb_substream *subs) if (!mctl) return; - mutex_lock(&mctl->media_dev->graph_mutex); + guard(mutex)(&mctl->media_dev->graph_mutex); if (mctl->media_dev->disable_source) mctl->media_dev->disable_source(&mctl->media_entity); - mutex_unlock(&mctl->media_dev->graph_mutex); } static int snd_media_mixer_init(struct snd_usb_audio *chip) diff --git a/sound/usb/midi.c b/sound/usb/midi.c index acb3bf92857c..1912d59627bd 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -265,16 +265,15 @@ static void snd_usbmidi_out_urb_complete(struct urb *urb) struct out_urb_context *context = urb->context; struct snd_usb_midi_out_endpoint *ep = context->ep; unsigned int urb_index; - unsigned long flags; - spin_lock_irqsave(&ep->buffer_lock, flags); - urb_index = context - ep->urbs; - ep->active_urbs &= ~(1 << urb_index); - if (unlikely(ep->drain_urbs)) { - ep->drain_urbs &= ~(1 << urb_index); - wake_up(&ep->drain_wait); + scoped_guard(spinlock_irqsave, &ep->buffer_lock) { + urb_index = context - ep->urbs; + ep->active_urbs &= ~(1 << urb_index); + if (unlikely(ep->drain_urbs)) { + ep->drain_urbs &= ~(1 << urb_index); + wake_up(&ep->drain_wait); + } } - spin_unlock_irqrestore(&ep->buffer_lock, flags); if (urb->status < 0) { int err = snd_usbmidi_urb_error(urb); if (err < 0) { @@ -295,13 +294,10 @@ static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint *ep) { unsigned int urb_index; struct urb *urb; - unsigned long flags; - spin_lock_irqsave(&ep->buffer_lock, flags); - if (ep->umidi->disconnected) { - spin_unlock_irqrestore(&ep->buffer_lock, flags); + guard(spinlock_irqsave)(&ep->buffer_lock); + if (ep->umidi->disconnected) return; - } urb_index = ep->next_urb; for (;;) { @@ -325,7 +321,6 @@ static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint *ep) break; } ep->next_urb = urb_index; - spin_unlock_irqrestore(&ep->buffer_lock, flags); } static void snd_usbmidi_out_work(struct work_struct *work) @@ -342,9 +337,8 @@ static void snd_usbmidi_error_timer(struct timer_list *t) struct snd_usb_midi *umidi = timer_container_of(umidi, t, error_timer); unsigned int i, j; - spin_lock(&umidi->disc_lock); + guard(spinlock)(&umidi->disc_lock); if (umidi->disconnected) { - spin_unlock(&umidi->disc_lock); return; } for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { @@ -361,7 +355,6 @@ static void snd_usbmidi_error_timer(struct timer_list *t) if (umidi->endpoints[i].out) snd_usbmidi_do_output(umidi->endpoints[i].out); } - spin_unlock(&umidi->disc_lock); } /* helper function to send static data that may not DMA-able */ @@ -1148,13 +1141,11 @@ static int substream_open(struct snd_rawmidi_substream *substream, int dir, struct snd_usb_midi *umidi = substream->rmidi->private_data; struct snd_kcontrol *ctl; - down_read(&umidi->disc_rwsem); - if (umidi->disconnected) { - up_read(&umidi->disc_rwsem); + guard(rwsem_read)(&umidi->disc_rwsem); + if (umidi->disconnected) return open ? -ENODEV : 0; - } - mutex_lock(&umidi->mutex); + guard(mutex)(&umidi->mutex); if (open) { if (!umidi->opened[0] && !umidi->opened[1]) { if (umidi->roland_load_ctl) { @@ -1183,8 +1174,6 @@ static int substream_open(struct snd_rawmidi_substream *substream, int dir, } } } - mutex_unlock(&umidi->mutex); - up_read(&umidi->disc_rwsem); return 0; } @@ -1548,11 +1537,10 @@ void snd_usbmidi_disconnect(struct list_head *p) * a timer may submit an URB. To reliably break the cycle * a flag under lock must be used */ - down_write(&umidi->disc_rwsem); - spin_lock_irq(&umidi->disc_lock); - umidi->disconnected = 1; - spin_unlock_irq(&umidi->disc_lock); - up_write(&umidi->disc_rwsem); + scoped_guard(rwsem_write, &umidi->disc_rwsem) { + guard(spinlock_irq)(&umidi->disc_lock); + umidi->disconnected = 1; + } timer_shutdown_sync(&umidi->error_timer); @@ -2094,11 +2082,10 @@ static int roland_load_put(struct snd_kcontrol *kcontrol, if (value->value.enumerated.item[0] > 1) return -EINVAL; - mutex_lock(&umidi->mutex); + guard(mutex)(&umidi->mutex); changed = value->value.enumerated.item[0] != kcontrol->private_value; if (changed) kcontrol->private_value = value->value.enumerated.item[0]; - mutex_unlock(&umidi->mutex); return changed; } @@ -2448,18 +2435,17 @@ static void snd_usbmidi_input_start_ep(struct snd_usb_midi *umidi, struct snd_usb_midi_in_endpoint *ep) { unsigned int i; - unsigned long flags; if (!ep) return; for (i = 0; i < INPUT_URBS; ++i) { struct urb *urb = ep->urbs[i]; - spin_lock_irqsave(&umidi->disc_lock, flags); - if (!atomic_read(&urb->use_count)) { - urb->dev = ep->umidi->dev; - snd_usbmidi_submit_urb(urb, GFP_ATOMIC); + scoped_guard(spinlock_irqsave, &umidi->disc_lock) { + if (!atomic_read(&urb->use_count)) { + urb->dev = ep->umidi->dev; + snd_usbmidi_submit_urb(urb, GFP_ATOMIC); + } } - spin_unlock_irqrestore(&umidi->disc_lock, flags); } } @@ -2488,9 +2474,8 @@ void snd_usbmidi_suspend(struct list_head *p) struct snd_usb_midi *umidi; umidi = list_entry(p, struct snd_usb_midi, list); - mutex_lock(&umidi->mutex); + guard(mutex)(&umidi->mutex); snd_usbmidi_input_stop(p); - mutex_unlock(&umidi->mutex); } EXPORT_SYMBOL(snd_usbmidi_suspend); @@ -2502,9 +2487,8 @@ void snd_usbmidi_resume(struct list_head *p) struct snd_usb_midi *umidi; umidi = list_entry(p, struct snd_usb_midi, list); - mutex_lock(&umidi->mutex); + guard(mutex)(&umidi->mutex); snd_usbmidi_input_start(p); - mutex_unlock(&umidi->mutex); } EXPORT_SYMBOL(snd_usbmidi_resume); diff --git a/sound/usb/midi2.c b/sound/usb/midi2.c index 030569fda416..e6793f3bdfc3 100644 --- a/sound/usb/midi2.c +++ b/sound/usb/midi2.c @@ -160,15 +160,13 @@ static void output_urb_complete(struct urb *urb) { struct snd_usb_midi2_urb *ctx = urb->context; struct snd_usb_midi2_endpoint *ep = ctx->ep; - unsigned long flags; - spin_lock_irqsave(&ep->lock, flags); + guard(spinlock_irqsave)(&ep->lock); set_bit(ctx->index, &ep->urb_free); if (urb->status >= 0 && atomic_read(&ep->running)) submit_output_urbs_locked(ep); if (ep->urb_free == ep->urb_free_mask) wake_up(&ep->wait); - spin_unlock_irqrestore(&ep->lock, flags); } /* prepare for input submission: just set the buffer length */ @@ -189,10 +187,9 @@ static void input_urb_complete(struct urb *urb) { struct snd_usb_midi2_urb *ctx = urb->context; struct snd_usb_midi2_endpoint *ep = ctx->ep; - unsigned long flags; int len; - spin_lock_irqsave(&ep->lock, flags); + guard(spinlock_irqsave)(&ep->lock); if (ep->disconnected || urb->status < 0) goto dequeue; len = urb->actual_length; @@ -208,22 +205,18 @@ static void input_urb_complete(struct urb *urb) submit_input_urbs_locked(ep); if (ep->urb_free == ep->urb_free_mask) wake_up(&ep->wait); - spin_unlock_irqrestore(&ep->lock, flags); } /* URB submission helper; for both direction */ static void submit_io_urbs(struct snd_usb_midi2_endpoint *ep) { - unsigned long flags; - if (!ep) return; - spin_lock_irqsave(&ep->lock, flags); + guard(spinlock_irqsave)(&ep->lock); if (ep->direction == STR_IN) submit_input_urbs_locked(ep); else submit_output_urbs_locked(ep); - spin_unlock_irqrestore(&ep->lock, flags); } /* kill URBs for close, suspend and disconnect */ @@ -248,13 +241,12 @@ static void drain_urb_queue(struct snd_usb_midi2_endpoint *ep) { if (!ep) return; - spin_lock_irq(&ep->lock); + guard(spinlock_irq)(&ep->lock); atomic_set(&ep->running, 0); wait_event_lock_irq_timeout(ep->wait, ep->disconnected || ep->urb_free == ep->urb_free_mask, ep->lock, msecs_to_jiffies(500)); - spin_unlock_irq(&ep->lock); } /* release URBs for an EP */ diff --git a/sound/usb/mixer_s1810c.c b/sound/usb/mixer_s1810c.c index fac4bbc6b275..bee2a65fd3c9 100644 --- a/sound/usb/mixer_s1810c.c +++ b/sound/usb/mixer_s1810c.c @@ -338,18 +338,16 @@ snd_s1810c_get_switch_state(struct usb_mixer_interface *mixer, struct s1810_mixer_state *private = mixer->private_data; u32 field = 0; u32 ctl_idx = (u32) (kctl->private_value & 0xFF); - int ret = 0; + int ret; - mutex_lock(&private->usb_mutex); + guard(mutex)(&private->usb_mutex); ret = snd_sc1810c_get_status_field(chip->dev, &field, ctl_idx, &private->seqnum); if (ret < 0) - goto unlock; + return ret; *state = field; - unlock: - mutex_unlock(&private->usb_mutex); - return ret ? ret : 0; + return ret; } /* @@ -366,12 +364,9 @@ snd_s1810c_set_switch_state(struct usb_mixer_interface *mixer, u32 pval = (u32) kctl->private_value; u32 ctl_id = (pval >> 8) & 0xFF; u32 ctl_val = (pval >> 16) & 0x1; - int ret = 0; - mutex_lock(&private->usb_mutex); - ret = snd_s1810c_send_ctl_packet(chip->dev, 0, 0, 0, ctl_id, ctl_val); - mutex_unlock(&private->usb_mutex); - return ret; + guard(mutex)(&private->usb_mutex); + return snd_s1810c_send_ctl_packet(chip->dev, 0, 0, 0, ctl_id, ctl_val); } /* Generic get/set/init functions for switch controls */ @@ -386,12 +381,12 @@ snd_s1810c_switch_get(struct snd_kcontrol *kctl, u32 pval = (u32) kctl->private_value; u32 ctl_idx = pval & 0xFF; u32 state = 0; - int ret = 0; + int ret; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); ret = snd_s1810c_get_switch_state(mixer, kctl, &state); if (ret < 0) - goto unlock; + return ret; switch (ctl_idx) { case SC1810C_STATE_LINE_SW: @@ -402,9 +397,7 @@ snd_s1810c_switch_get(struct snd_kcontrol *kctl, ctl_elem->value.integer.value[0] = (long)state; } - unlock: - mutex_unlock(&private->data_mutex); - return (ret < 0) ? ret : 0; + return 0; } static int @@ -420,10 +413,10 @@ snd_s1810c_switch_set(struct snd_kcontrol *kctl, u32 newval = 0; int ret = 0; - mutex_lock(&private->data_mutex); + guard(mutex)(&private->data_mutex); ret = snd_s1810c_get_switch_state(mixer, kctl, &curval); if (ret < 0) - goto unlock; + return ret; switch (ctl_idx) { case SC1810C_STATE_LINE_SW: @@ -435,14 +428,12 @@ snd_s1810c_switch_set(struct snd_kcontrol *kctl, } if (curval == newval) - goto unlock; + return 0; kctl->private_value &= ~(0x1 << 16); kctl->private_value |= (unsigned int)(newval & 0x1) << 16; ret = snd_s1810c_set_switch_state(mixer, kctl); - unlock: - mutex_unlock(&private->data_mutex); return (ret < 0) ? 0 : 1; } diff --git a/sound/usb/mixer_us16x08.c b/sound/usb/mixer_us16x08.c index 236b69054867..1c5712c31f5e 100644 --- a/sound/usb/mixer_us16x08.c +++ b/sound/usb/mixer_us16x08.c @@ -152,12 +152,11 @@ static int snd_us16x08_recv_urb(struct snd_usb_audio *chip, unsigned char *buf, int size) { - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), SND_US16X08_URB_METER_REQUEST, SND_US16X08_URB_METER_REQUESTTYPE, 0, 0, buf, size); - mutex_unlock(&chip->mutex); return 0; } diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index bff92505e408..c52fd0989c93 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -77,10 +77,10 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream if (atomic_read(&subs->stream->chip->shutdown)) return SNDRV_PCM_POS_XRUN; - spin_lock(&subs->lock); - hwptr_done = subs->hwptr_done; - runtime->delay = snd_usb_pcm_delay(subs, runtime); - spin_unlock(&subs->lock); + scoped_guard(spinlock, &subs->lock) { + hwptr_done = subs->hwptr_done; + runtime->delay = snd_usb_pcm_delay(subs, runtime); + } return bytes_to_frames(runtime, hwptr_done); } @@ -560,9 +560,9 @@ int snd_usb_hw_params(struct snd_usb_substream *subs, subs->sync_endpoint); } - mutex_lock(&chip->mutex); - subs->cur_audiofmt = fmt; - mutex_unlock(&chip->mutex); + scoped_guard(mutex, &chip->mutex) { + subs->cur_audiofmt = fmt; + } if (!subs->data_endpoint->need_setup) goto unlock; @@ -611,9 +611,9 @@ int snd_usb_hw_free(struct snd_usb_substream *subs) struct snd_usb_audio *chip = subs->stream->chip; snd_media_stop_pipeline(subs); - mutex_lock(&chip->mutex); - subs->cur_audiofmt = NULL; - mutex_unlock(&chip->mutex); + scoped_guard(mutex, &chip->mutex) { + subs->cur_audiofmt = NULL; + } if (!snd_usb_lock_shutdown(chip)) { if (stop_endpoints(subs, false)) sync_pending_stops(subs); @@ -1244,13 +1244,11 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream) struct snd_usb_audio *chip = subs->stream->chip; int ret; - mutex_lock(&chip->mutex); - if (subs->opened) { - mutex_unlock(&chip->mutex); - return -EBUSY; + scoped_guard(mutex, &chip->mutex) { + if (subs->opened) + return -EBUSY; + subs->opened = 1; } - subs->opened = 1; - mutex_unlock(&chip->mutex); runtime->hw = snd_usb_hardware; /* need an explicit sync to catch applptr update in low-latency mode */ @@ -1281,9 +1279,9 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream) err_resume: snd_usb_autosuspend(subs->stream->chip); err_open: - mutex_lock(&chip->mutex); - subs->opened = 0; - mutex_unlock(&chip->mutex); + scoped_guard(mutex, &chip->mutex) { + subs->opened = 0; + } return ret; } @@ -1307,9 +1305,9 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream) subs->pcm_substream = NULL; snd_usb_autosuspend(subs->stream->chip); - mutex_lock(&chip->mutex); - subs->opened = 0; - mutex_unlock(&chip->mutex); + scoped_guard(mutex, &chip->mutex) { + subs->opened = 0; + } return 0; } @@ -1325,7 +1323,6 @@ static void retire_capture_urb(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; unsigned int stride, frames, bytes, oldptr; int i, period_elapsed = 0; - unsigned long flags; unsigned char *cp; int current_frame_number; @@ -1358,22 +1355,21 @@ static void retire_capture_urb(struct snd_usb_substream *subs, oldbytes, bytes); } /* update the current pointer */ - spin_lock_irqsave(&subs->lock, flags); - oldptr = subs->hwptr_done; - subs->hwptr_done += bytes; - if (subs->hwptr_done >= subs->buffer_bytes) - subs->hwptr_done -= subs->buffer_bytes; - frames = (bytes + (oldptr % stride)) / stride; - subs->transfer_done += frames; - if (subs->transfer_done >= runtime->period_size) { - subs->transfer_done -= runtime->period_size; - period_elapsed = 1; + scoped_guard(spinlock_irqsave, &subs->lock) { + oldptr = subs->hwptr_done; + subs->hwptr_done += bytes; + if (subs->hwptr_done >= subs->buffer_bytes) + subs->hwptr_done -= subs->buffer_bytes; + frames = (bytes + (oldptr % stride)) / stride; + subs->transfer_done += frames; + if (subs->transfer_done >= runtime->period_size) { + subs->transfer_done -= runtime->period_size; + period_elapsed = 1; + } + + /* realign last_frame_number */ + subs->last_frame_number = current_frame_number; } - - /* realign last_frame_number */ - subs->last_frame_number = current_frame_number; - - spin_unlock_irqrestore(&subs->lock, flags); /* copy a data chunk */ if (oldptr + bytes > subs->buffer_bytes) { unsigned int bytes1 = subs->buffer_bytes - oldptr; diff --git a/sound/usb/proc.c b/sound/usb/proc.c index c8b967bd7065..f4b7a7ff3203 100644 --- a/sound/usb/proc.c +++ b/sound/usb/proc.c @@ -193,7 +193,7 @@ static void proc_dump_substream_status(struct snd_usb_audio *chip, struct snd_usb_substream *subs, struct snd_info_buffer *buffer) { - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); if (subs->running) { snd_iprintf(buffer, " Status: Running\n"); if (subs->cur_audiofmt) { @@ -204,7 +204,6 @@ static void proc_dump_substream_status(struct snd_usb_audio *chip, } else { snd_iprintf(buffer, " Status: Stop\n"); } - mutex_unlock(&chip->mutex); } static void proc_pcm_format_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) From 1335a89bbc8ac5b0310db9457018c261816e61cc Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Mon, 7 Jul 2025 16:35:30 +0100 Subject: [PATCH 00393/11391] arm64: dts: renesas: r9a09g077: Add I2C controller nodes The Renesas RZ/T2H ("R9A09G077") SoC includes three I2C (RIIC) channels. Add device tree nodes for all three I2C controllers to the RZ/T2H SoC DTSI. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250707153533.287832-2-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- arch/arm64/boot/dts/renesas/r9a09g077.dtsi | 45 ++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/arch/arm64/boot/dts/renesas/r9a09g077.dtsi b/arch/arm64/boot/dts/renesas/r9a09g077.dtsi index 42c3b86196d6..0583a26ecbc4 100644 --- a/arch/arm64/boot/dts/renesas/r9a09g077.dtsi +++ b/arch/arm64/boot/dts/renesas/r9a09g077.dtsi @@ -90,6 +90,51 @@ sci0: serial@80005000 { status = "disabled"; }; + i2c0: i2c@80088000 { + compatible = "renesas,riic-r9a09g077"; + reg = <0 0x80088000 0 0x400>; + interrupts = , + , + , + ; + interrupt-names = "eei", "rxi", "txi", "tei"; + clocks = <&cpg CPG_MOD 100>; + power-domains = <&cpg>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c1: i2c@80088400 { + compatible = "renesas,riic-r9a09g077"; + reg = <0 0x80088400 0 0x400>; + interrupts = , + , + , + ; + interrupt-names = "eei", "rxi", "txi", "tei"; + clocks = <&cpg CPG_MOD 101>; + power-domains = <&cpg>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c2: i2c@81008000 { + compatible = "renesas,riic-r9a09g077"; + reg = <0 0x81008000 0 0x400>; + interrupts = , + , + , + ; + interrupt-names = "eei", "rxi", "txi", "tei"; + clocks = <&cpg CPG_MOD 601>; + power-domains = <&cpg>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + cpg: clock-controller@80280000 { compatible = "renesas,r9a09g077-cpg-mssr"; reg = <0 0x80280000 0 0x1000>, From 1977f7d0d180621c11af26e96be29cc4e772dcc4 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Mon, 7 Jul 2025 16:35:31 +0100 Subject: [PATCH 00394/11391] arm64: dts: renesas: r9a09g087: Add I2C controller nodes The Renesas RZ/N2H ("R9A09G087") SoC includes three I2C (RIIC) channels. Add device tree nodes for all three I2C controllers to the RZ/N2H SoC DTSI. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250707153533.287832-3-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- arch/arm64/boot/dts/renesas/r9a09g087.dtsi | 45 ++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/arch/arm64/boot/dts/renesas/r9a09g087.dtsi b/arch/arm64/boot/dts/renesas/r9a09g087.dtsi index e57a91adcb68..7452aca6b05b 100644 --- a/arch/arm64/boot/dts/renesas/r9a09g087.dtsi +++ b/arch/arm64/boot/dts/renesas/r9a09g087.dtsi @@ -90,6 +90,51 @@ sci0: serial@80005000 { status = "disabled"; }; + i2c0: i2c@80088000 { + compatible = "renesas,riic-r9a09g087", "renesas,riic-r9a09g077"; + reg = <0 0x80088000 0 0x400>; + interrupts = , + , + , + ; + interrupt-names = "eei", "rxi", "txi", "tei"; + clocks = <&cpg CPG_MOD 100>; + power-domains = <&cpg>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c1: i2c@80088400 { + compatible = "renesas,riic-r9a09g087", "renesas,riic-r9a09g077"; + reg = <0 0x80088400 0 0x400>; + interrupts = , + , + , + ; + interrupt-names = "eei", "rxi", "txi", "tei"; + clocks = <&cpg CPG_MOD 101>; + power-domains = <&cpg>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c2: i2c@81008000 { + compatible = "renesas,riic-r9a09g087", "renesas,riic-r9a09g077"; + reg = <0 0x81008000 0 0x400>; + interrupts = , + , + , + ; + interrupt-names = "eei", "rxi", "txi", "tei"; + clocks = <&cpg CPG_MOD 601>; + power-domains = <&cpg>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + cpg: clock-controller@80280000 { compatible = "renesas,r9a09g087-cpg-mssr"; reg = <0 0x80280000 0 0x1000>, From c5dbcd94fc78d67b6c0a7e55615ae2019300956f Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Mon, 7 Jul 2025 16:35:32 +0100 Subject: [PATCH 00395/11391] arm64: dts: renesas: r9a09g077: Add SDHI nodes Add the SDHI0-SDHI1 nodes to the RZ/T2H ("R9A09G077") SoC DTSI. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250707153533.287832-4-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- arch/arm64/boot/dts/renesas/r9a09g077.dtsi | 40 ++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/arch/arm64/boot/dts/renesas/r9a09g077.dtsi b/arch/arm64/boot/dts/renesas/r9a09g077.dtsi index 0583a26ecbc4..b16fd9259d8d 100644 --- a/arch/arm64/boot/dts/renesas/r9a09g077.dtsi +++ b/arch/arm64/boot/dts/renesas/r9a09g077.dtsi @@ -155,6 +155,46 @@ gic: interrupt-controller@83000000 { interrupt-controller; interrupts = ; }; + + sdhi0: mmc@92080000 { + compatible = "renesas,sdhi-r9a09g077", + "renesas,sdhi-r9a09g057"; + reg = <0x0 0x92080000 0 0x10000>; + interrupts = , + ; + clocks = <&cpg CPG_MOD 1212>, + <&cpg CPG_CORE R9A09G077_SDHI_CLKHS>; + clock-names = "aclk", "clkh"; + power-domains = <&cpg>; + status = "disabled"; + + sdhi0_vqmmc: vqmmc-regulator { + regulator-name = "SDHI0-VQMMC"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + status = "disabled"; + }; + }; + + sdhi1: mmc@92090000 { + compatible = "renesas,sdhi-r9a09g077", + "renesas,sdhi-r9a09g057"; + reg = <0x0 0x92090000 0 0x10000>; + interrupts = , + ; + clocks = <&cpg CPG_MOD 1213>, + <&cpg CPG_CORE R9A09G077_SDHI_CLKHS>; + clock-names = "aclk", "clkh"; + power-domains = <&cpg>; + status = "disabled"; + + sdhi1_vqmmc: vqmmc-regulator { + regulator-name = "SDHI1-VQMMC"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + status = "disabled"; + }; + }; }; timer { From deab74707654cbfcd4b1e984d8f64479145b6895 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Mon, 7 Jul 2025 16:35:33 +0100 Subject: [PATCH 00396/11391] arm64: dts: renesas: r9a09g087: Add SDHI nodes Add the SDHI0-SDHI1 nodes to the RZ/N2H ("R9A09G087") SoC DTSI. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250707153533.287832-5-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- arch/arm64/boot/dts/renesas/r9a09g087.dtsi | 40 ++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/arch/arm64/boot/dts/renesas/r9a09g087.dtsi b/arch/arm64/boot/dts/renesas/r9a09g087.dtsi index 7452aca6b05b..4da21199d22e 100644 --- a/arch/arm64/boot/dts/renesas/r9a09g087.dtsi +++ b/arch/arm64/boot/dts/renesas/r9a09g087.dtsi @@ -155,6 +155,46 @@ gic: interrupt-controller@83000000 { interrupt-controller; interrupts = ; }; + + sdhi0: mmc@92080000 { + compatible = "renesas,sdhi-r9a09g087", + "renesas,sdhi-r9a09g057"; + reg = <0x0 0x92080000 0 0x10000>; + interrupts = , + ; + clocks = <&cpg CPG_MOD 1212>, + <&cpg CPG_CORE R9A09G087_SDHI_CLKHS>; + clock-names = "aclk", "clkh"; + power-domains = <&cpg>; + status = "disabled"; + + sdhi0_vqmmc: vqmmc-regulator { + regulator-name = "SDHI0-VQMMC"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + status = "disabled"; + }; + }; + + sdhi1: mmc@92090000 { + compatible = "renesas,sdhi-r9a09g087", + "renesas,sdhi-r9a09g057"; + reg = <0x0 0x92090000 0 0x10000>; + interrupts = , + ; + clocks = <&cpg CPG_MOD 1213>, + <&cpg CPG_CORE R9A09G087_SDHI_CLKHS>; + clock-names = "aclk", "clkh"; + power-domains = <&cpg>; + status = "disabled"; + + sdhi1_vqmmc: vqmmc-regulator { + regulator-name = "SDHI1-VQMMC"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + status = "disabled"; + }; + }; }; timer { From 0a0e0852f3f339afdc75ff62750eae3857437231 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 31 Jul 2025 10:36:59 +0200 Subject: [PATCH 00397/11391] arm64: dts: renesas: r9a09g057h48-kakip: Fix misplaced article Move the article "the" before the full name of the board. Signed-off-by: Geert Uytterhoeven Reviewed-by: Wolfram Sang Link: https://lore.kernel.org/280176885acf46d117a0ab9a02c314e2b5cf250f.1753950938.git.geert+renesas@glider.be --- arch/arm64/boot/dts/renesas/r9a09g057h48-kakip.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/renesas/r9a09g057h48-kakip.dts b/arch/arm64/boot/dts/renesas/r9a09g057h48-kakip.dts index d2586d278769..f6f2cb7d2d25 100644 --- a/arch/arm64/boot/dts/renesas/r9a09g057h48-kakip.dts +++ b/arch/arm64/boot/dts/renesas/r9a09g057h48-kakip.dts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) /* - * Device Tree Source for Yuridenki-Shokai the Kakip board + * Device Tree Source for the Yuridenki-Shokai Kakip board * * Copyright (C) 2024 Nobuhiro Iwamatsu */ From c44c51bc3566412075c66e0064e17c0c9cb5a638 Mon Sep 17 00:00:00 2001 From: Tommaso Merciai Date: Fri, 1 Aug 2025 10:48:23 +0200 Subject: [PATCH 00398/11391] arm64: dts: renesas: r9a09g047: Add DMAC nodes Add nodes for the DMAC IPs found on the Renesas RZ/G3E SoC. Signed-off-by: Tommaso Merciai Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250801084825.471011-4-tommaso.merciai.xr@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- arch/arm64/boot/dts/renesas/r9a09g047.dtsi | 170 +++++++++++++++++++++ 1 file changed, 170 insertions(+) diff --git a/arch/arm64/boot/dts/renesas/r9a09g047.dtsi b/arch/arm64/boot/dts/renesas/r9a09g047.dtsi index e4fac7e0d764..eeccd1345f71 100644 --- a/arch/arm64/boot/dts/renesas/r9a09g047.dtsi +++ b/arch/arm64/boot/dts/renesas/r9a09g047.dtsi @@ -301,6 +301,176 @@ xspi: spi@11030000 { status = "disabled"; }; + dmac0: dma-controller@11400000 { + compatible = "renesas,r9a09g047-dmac", + "renesas,r9a09g057-dmac"; + reg = <0 0x11400000 0 0x10000>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + interrupt-names = "error", + "ch0", "ch1", "ch2", "ch3", + "ch4", "ch5", "ch6", "ch7", + "ch8", "ch9", "ch10", "ch11", + "ch12", "ch13", "ch14", "ch15"; + clocks = <&cpg CPG_MOD 0x0>; + power-domains = <&cpg>; + resets = <&cpg 0x31>; + #dma-cells = <1>; + dma-channels = <16>; + renesas,icu = <&icu 4>; + }; + + dmac1: dma-controller@14830000 { + compatible = "renesas,r9a09g047-dmac", + "renesas,r9a09g057-dmac"; + reg = <0 0x14830000 0 0x10000>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + interrupt-names = "error", + "ch0", "ch1", "ch2", "ch3", + "ch4", "ch5", "ch6", "ch7", + "ch8", "ch9", "ch10", "ch11", + "ch12", "ch13", "ch14", "ch15"; + clocks = <&cpg CPG_MOD 0x1>; + power-domains = <&cpg>; + resets = <&cpg 0x32>; + #dma-cells = <1>; + dma-channels = <16>; + renesas,icu = <&icu 0>; + }; + + dmac2: dma-controller@14840000 { + compatible = "renesas,r9a09g047-dmac", + "renesas,r9a09g057-dmac"; + reg = <0 0x14840000 0 0x10000>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + interrupt-names = "error", + "ch0", "ch1", "ch2", "ch3", + "ch4", "ch5", "ch6", "ch7", + "ch8", "ch9", "ch10", "ch11", + "ch12", "ch13", "ch14", "ch15"; + clocks = <&cpg CPG_MOD 0x2>; + power-domains = <&cpg>; + resets = <&cpg 0x33>; + #dma-cells = <1>; + dma-channels = <16>; + renesas,icu = <&icu 1>; + }; + + dmac3: dma-controller@12000000 { + compatible = "renesas,r9a09g047-dmac", + "renesas,r9a09g057-dmac"; + reg = <0 0x12000000 0 0x10000>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + interrupt-names = "error", + "ch0", "ch1", "ch2", "ch3", + "ch4", "ch5", "ch6", "ch7", + "ch8", "ch9", "ch10", "ch11", + "ch12", "ch13", "ch14", "ch15"; + clocks = <&cpg CPG_MOD 0x3>; + power-domains = <&cpg>; + resets = <&cpg 0x34>; + #dma-cells = <1>; + dma-channels = <16>; + renesas,icu = <&icu 2>; + }; + + dmac4: dma-controller@12010000 { + compatible = "renesas,r9a09g047-dmac", + "renesas,r9a09g057-dmac"; + reg = <0 0x12010000 0 0x10000>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + interrupt-names = "error", + "ch0", "ch1", "ch2", "ch3", + "ch4", "ch5", "ch6", "ch7", + "ch8", "ch9", "ch10", "ch11", + "ch12", "ch13", "ch14", "ch15"; + clocks = <&cpg CPG_MOD 0x4>; + power-domains = <&cpg>; + resets = <&cpg 0x35>; + #dma-cells = <1>; + dma-channels = <16>; + renesas,icu = <&icu 3>; + }; + scif0: serial@11c01400 { compatible = "renesas,scif-r9a09g047", "renesas,scif-r9a09g057"; reg = <0 0x11c01400 0 0x400>; From ae014fbc99c7f986ee785233e7a5336834e39af4 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 1 Aug 2025 13:19:53 +0100 Subject: [PATCH 00399/11391] arm64: dts: renesas: rzg2lc-smarc: Disable CAN-FD channel0 On RZ/G2LC SMARC EVK, CAN-FD channel0 is not populated, and currently we are deleting a wrong and nonexistent node. Fixing the wrong node would invoke a dtb warning message, as channel0 is a required property. Disable CAN-FD channel0 instead of deleting the node. Fixes: 46da632734a5 ("arm64: dts: renesas: rzg2lc-smarc: Enable CANFD channel 1") Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250801121959.267424-1-biju.das.jz@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- arch/arm64/boot/dts/renesas/rzg2lc-smarc.dtsi | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/renesas/rzg2lc-smarc.dtsi b/arch/arm64/boot/dts/renesas/rzg2lc-smarc.dtsi index 345b779e4f60..f3d7eff0d2f2 100644 --- a/arch/arm64/boot/dts/renesas/rzg2lc-smarc.dtsi +++ b/arch/arm64/boot/dts/renesas/rzg2lc-smarc.dtsi @@ -48,7 +48,10 @@ sound_card { #if (SW_SCIF_CAN || SW_RSPI_CAN) &canfd { pinctrl-0 = <&can1_pins>; - /delete-node/ channel@0; + + channel0 { + status = "disabled"; + }; }; #else &canfd { From 95319aaa3ffc680cab9abe6e7197299561e890de Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 6 Aug 2025 17:00:36 +0200 Subject: [PATCH 00400/11391] arm64: dts: renesas: sparrow-hawk: Describe generic SPI NOR support Retronix R-Car V4H Sparrow Hawk EVTA1 is populated with Spansion S25FS512S, EVTB1 is populated with Winbond W77Q51NW. Describe the SPI NOR using the generic "jedec,spi-nor" compatible, because both FLASHes can be auto-detected based on their built-in IDs. Signed-off-by: Marek Vasut Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250806150048.9364-1-marek.vasut+renesas@mailbox.org Signed-off-by: Geert Uytterhoeven --- arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts b/arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts index 9ba23129e65e..1f44005e1a11 100644 --- a/arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts +++ b/arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts @@ -756,7 +756,11 @@ &rpc { status = "okay"; flash@0 { - compatible = "spansion,s25fs512s", "jedec,spi-nor"; + /* + * EVTA1 is populated with Spansion S25FS512S + * EVTB1 is populated with Winbond W77Q51NW + */ + compatible = "jedec,spi-nor"; reg = <0>; spi-max-frequency = <40000000>; spi-rx-bus-width = <4>; From 256feb5be482315a91c1bd1a1808276f57ef76dd Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 6 Aug 2025 17:04:27 +0200 Subject: [PATCH 00401/11391] ARM: dts: renesas: r7s72100: Add boot phase tags bootph-all as phase tag was added to dt-schema (dtschema/schemas/bootph.yaml) to describe various node usage during boot phases with DT. Add bootph-all for all nodes that are used in the bootloader on Renesas RZ/A1 SoCs. All SoCs require BSC bus, PFC pin control, and OSTM0 timer access during all stages of the boot process, those are marked using bootph-all property, and so is the SoC bus node which contains the PFC and OSTM IPs. Each board console UART is also marked as bootph-all to make it available in all stages of the boot process. Signed-off-by: Marek Vasut Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250806150448.9669-1-marek.vasut+renesas@mailbox.org Signed-off-by: Geert Uytterhoeven --- arch/arm/boot/dts/renesas/r7s72100-genmai.dts | 4 +++- arch/arm/boot/dts/renesas/r7s72100-gr-peach.dts | 4 +++- arch/arm/boot/dts/renesas/r7s72100-rskrza1.dts | 3 +++ arch/arm/boot/dts/renesas/r7s72100.dtsi | 3 +++ 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/renesas/r7s72100-genmai.dts b/arch/arm/boot/dts/renesas/r7s72100-genmai.dts index c81840dfb7da..3c3756509714 100644 --- a/arch/arm/boot/dts/renesas/r7s72100-genmai.dts +++ b/arch/arm/boot/dts/renesas/r7s72100-genmai.dts @@ -203,6 +203,7 @@ &mtu2 { }; &ostm0 { + bootph-all; status = "okay"; }; @@ -258,6 +259,7 @@ mmcif_pins: mmcif { }; scif2_pins: serial2 { + bootph-all; /* P3_0 as TxD2; P3_2 as RxD2 */ pinmux = , ; }; @@ -286,7 +288,7 @@ &rtc { &scif2 { pinctrl-names = "default"; pinctrl-0 = <&scif2_pins>; - + bootph-all; status = "okay"; }; diff --git a/arch/arm/boot/dts/renesas/r7s72100-gr-peach.dts b/arch/arm/boot/dts/renesas/r7s72100-gr-peach.dts index 9d29861f23f1..23ddec217685 100644 --- a/arch/arm/boot/dts/renesas/r7s72100-gr-peach.dts +++ b/arch/arm/boot/dts/renesas/r7s72100-gr-peach.dts @@ -59,6 +59,7 @@ led1 { &pinctrl { scif2_pins: serial2 { + bootph-all; /* P6_2 as RxD2; P6_3 as TxD2 */ pinmux = , ; }; @@ -99,6 +100,7 @@ &mtu2 { }; &ostm0 { + bootph-all; status = "okay"; }; @@ -109,7 +111,7 @@ &ostm1 { &scif2 { pinctrl-names = "default"; pinctrl-0 = <&scif2_pins>; - + bootph-all; status = "okay"; }; diff --git a/arch/arm/boot/dts/renesas/r7s72100-rskrza1.dts b/arch/arm/boot/dts/renesas/r7s72100-rskrza1.dts index 25c6d0c78828..91178fb9e721 100644 --- a/arch/arm/boot/dts/renesas/r7s72100-rskrza1.dts +++ b/arch/arm/boot/dts/renesas/r7s72100-rskrza1.dts @@ -199,6 +199,7 @@ keyboard_pins: keyboard { /* Serial Console */ scif2_pins: serial2 { + bootph-all; pinmux = , /* TxD2 */ ; /* RxD2 */ }; @@ -264,6 +265,7 @@ &sdhi1 { }; &ostm0 { + bootph-all; status = "okay"; }; @@ -278,6 +280,7 @@ &rtc { &scif2 { pinctrl-names = "default"; pinctrl-0 = <&scif2_pins>; + bootph-all; status = "okay"; }; diff --git a/arch/arm/boot/dts/renesas/r7s72100.dtsi b/arch/arm/boot/dts/renesas/r7s72100.dtsi index 1a866dbaf5e9..a1e4e9ac8f62 100644 --- a/arch/arm/boot/dts/renesas/r7s72100.dtsi +++ b/arch/arm/boot/dts/renesas/r7s72100.dtsi @@ -41,6 +41,7 @@ bsc: bus { #address-cells = <1>; #size-cells = <1>; ranges = <0 0 0x18000000>; + bootph-all; }; cpus { @@ -107,6 +108,7 @@ soc { #address-cells = <1>; #size-cells = <1>; ranges; + bootph-all; L2: cache-controller@3ffff000 { compatible = "arm,pl310-cache"; @@ -557,6 +559,7 @@ R7S72100_CLK_SDHI10 R7S72100_CLK_SDHI11 pinctrl: pinctrl@fcfe3000 { compatible = "renesas,r7s72100-ports"; + bootph-all; reg = <0xfcfe3000 0x4230>; From 58de1f91e033b1fface8d8948984583125f93736 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 24 Jul 2025 08:48:15 +0800 Subject: [PATCH 00402/11391] wifi: rtw88: sdio: use indirect IO for device registers before power-on The register REG_SYS_CFG1 is used to determine chip basic information as arguments of following flows, such as download firmware and load PHY parameters, so driver read the value early (before power-on). However, the direct IO is disallowed before power-on, or it causes wrong values, which driver recognizes a chip as a wrong type RF_1T1R, but actually RF_2T2R, causing driver warns: rtw88_8822cs mmc1:0001:1: unsupported rf path (1) Fix it by using indirect IO before power-on. Reported-by: Piotr Oniszczuk Closes: https://lore.kernel.org/linux-wireless/699C22B4-A3E3-4206-97D0-22AB3348EBF6@gmail.com/T/#t Suggested-by: Bitterblue Smith Tested-by: Piotr Oniszczuk Reviewed-by: Martin Blumenstingl Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250724004815.7043-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw88/sdio.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw88/sdio.c b/drivers/net/wireless/realtek/rtw88/sdio.c index cc2d4fef3587..99d7c629eac6 100644 --- a/drivers/net/wireless/realtek/rtw88/sdio.c +++ b/drivers/net/wireless/realtek/rtw88/sdio.c @@ -144,6 +144,10 @@ static u32 rtw_sdio_to_io_address(struct rtw_dev *rtwdev, u32 addr, static bool rtw_sdio_use_direct_io(struct rtw_dev *rtwdev, u32 addr) { + if (!test_bit(RTW_FLAG_POWERON, rtwdev->flags) && + !rtw_sdio_is_bus_addr(addr)) + return false; + return !rtw_sdio_is_sdio30_supported(rtwdev) || rtw_sdio_is_bus_addr(addr); } From 26a8bf978ae9cd7688af1d08bc8760674d372e22 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Fri, 1 Aug 2025 23:08:24 +0300 Subject: [PATCH 00403/11391] wifi: rtw88: Lock rtwdev->mutex before setting the LED Some users report that the LED blinking breaks AP mode somehow. Most likely the LED code and the dynamic mechanism are trying to access the hardware registers at the same time. Fix it by locking rtwdev->mutex before setting the LED and unlocking it after. Fixes: 4b6652bc6d8d ("wifi: rtw88: Add support for LED blinking") Closes: https://github.com/lwfinger/rtw88/issues/305 Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/ed69fa07-8678-4a40-af44-65e7b1862197@gmail.com --- drivers/net/wireless/realtek/rtw88/led.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/led.c b/drivers/net/wireless/realtek/rtw88/led.c index 25aa6cbaa728..7f9ace351a5b 100644 --- a/drivers/net/wireless/realtek/rtw88/led.c +++ b/drivers/net/wireless/realtek/rtw88/led.c @@ -6,13 +6,23 @@ #include "debug.h" #include "led.h" -static int rtw_led_set_blocking(struct led_classdev *led, - enum led_brightness brightness) +static void rtw_led_set(struct led_classdev *led, + enum led_brightness brightness) { struct rtw_dev *rtwdev = container_of(led, struct rtw_dev, led_cdev); + mutex_lock(&rtwdev->mutex); + rtwdev->chip->ops->led_set(led, brightness); + mutex_unlock(&rtwdev->mutex); +} + +static int rtw_led_set_blocking(struct led_classdev *led, + enum led_brightness brightness) +{ + rtw_led_set(led, brightness); + return 0; } @@ -37,7 +47,7 @@ void rtw_led_init(struct rtw_dev *rtwdev) return; if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_PCIE) - led->brightness_set = rtwdev->chip->ops->led_set; + led->brightness_set = rtw_led_set; else led->brightness_set_blocking = rtw_led_set_blocking; From 7e1c44fe4c2e1e01fa47d9490893d95309a99687 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 4 Aug 2025 09:22:33 +0800 Subject: [PATCH 00404/11391] wifi: rtw89: print just once for unknown C2H events When driver receives new or unknown C2H events, it print out messages repeatedly once events are received, like rtw89_8922ae 0000:81:00.0: PHY c2h class 2 not support To avoid the thousands of messages, use rtw89_info_once() instead. Also, print out class/func for unknown (undefined) class. Reported-by: Sean Anderson Closes: https://lore.kernel.org/linux-wireless/20250729204437.164320-1-sean.anderson@linux.dev/ Reviewed-by: Sean Anderson Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250804012234.8913-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/debug.h | 1 + drivers/net/wireless/realtek/rtw89/mac.c | 7 +++---- drivers/net/wireless/realtek/rtw89/phy.c | 7 +++---- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/debug.h b/drivers/net/wireless/realtek/rtw89/debug.h index fc690f7c55dc..a364e7adb079 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.h +++ b/drivers/net/wireless/realtek/rtw89/debug.h @@ -56,6 +56,7 @@ static inline void rtw89_debugfs_deinit(struct rtw89_dev *rtwdev) {} #endif #define rtw89_info(rtwdev, a...) dev_info((rtwdev)->dev, ##a) +#define rtw89_info_once(rtwdev, a...) dev_info_once((rtwdev)->dev, ##a) #define rtw89_warn(rtwdev, a...) dev_warn((rtwdev)->dev, ##a) #define rtw89_err(rtwdev, a...) dev_err((rtwdev)->dev, ##a) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 5a5da9d9c0c5..ef17a307b770 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -5813,12 +5813,11 @@ void rtw89_mac_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, case RTW89_MAC_C2H_CLASS_ROLE: return; default: - rtw89_info(rtwdev, "MAC c2h class %d not support\n", class); - return; + break; } if (!handler) { - rtw89_info(rtwdev, "MAC c2h class %d func %d not support\n", class, - func); + rtw89_info_once(rtwdev, "MAC c2h class %d func %d not support\n", + class, func); return; } handler(rtwdev, skb, len); diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index d607577b353c..01a03d2de3ff 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -3626,12 +3626,11 @@ void rtw89_phy_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, handler = rtw89_phy_c2h_dm_handler[func]; break; default: - rtw89_info(rtwdev, "PHY c2h class %d not support\n", class); - return; + break; } if (!handler) { - rtw89_info(rtwdev, "PHY c2h class %d func %d not support\n", class, - func); + rtw89_info_once(rtwdev, "PHY c2h class %d func %d not support\n", + class, func); return; } handler(rtwdev, skb, len); From 04a2de8cfc95076d6c65d4d6d06d0f9d964a2105 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 4 Aug 2025 09:22:34 +0800 Subject: [PATCH 00405/11391] wifi: rtw89: add dummy C2H handlers for BCN resend and update done Two C2H events are not listed, and driver throws MAC c2h class 0 func 6 not support MAC c2h class 1 func 3 not support Since the implementation in vendor driver does nothing, add two dummy functions for them. Reported-by: Bitterblue Smith Closes: https://lore.kernel.org/linux-wireless/d2d62793-046c-4b55-93ed-1d1f43cff7f2@gmail.com/ Reviewed-by: Sean Anderson Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250804012234.8913-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 13 ++++++++++++- drivers/net/wireless/realtek/rtw89/mac.h | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index ef17a307b770..33a7dd9d6f0e 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -5235,6 +5235,11 @@ rtw89_mac_c2h_bcn_cnt(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) { } +static void +rtw89_mac_c2h_bcn_upd_done(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) +{ +} + static void rtw89_mac_c2h_pkt_ofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h, u32 len) @@ -5257,6 +5262,11 @@ rtw89_mac_c2h_pkt_ofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h, rtw89_complete_cond(wait, cond, &data); } +static void +rtw89_mac_c2h_bcn_resend(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) +{ +} + static void rtw89_mac_c2h_tx_duty_rpt(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h, u32 len) { @@ -5646,7 +5656,7 @@ void (* const rtw89_mac_c2h_ofld_handler[])(struct rtw89_dev *rtwdev, [RTW89_MAC_C2H_FUNC_EFUSE_DUMP] = NULL, [RTW89_MAC_C2H_FUNC_READ_RSP] = NULL, [RTW89_MAC_C2H_FUNC_PKT_OFLD_RSP] = rtw89_mac_c2h_pkt_ofld_rsp, - [RTW89_MAC_C2H_FUNC_BCN_RESEND] = NULL, + [RTW89_MAC_C2H_FUNC_BCN_RESEND] = rtw89_mac_c2h_bcn_resend, [RTW89_MAC_C2H_FUNC_MACID_PAUSE] = rtw89_mac_c2h_macid_pause, [RTW89_MAC_C2H_FUNC_SCANOFLD_RSP] = rtw89_mac_c2h_scanofld_rsp, [RTW89_MAC_C2H_FUNC_TX_DUTY_RPT] = rtw89_mac_c2h_tx_duty_rpt, @@ -5661,6 +5671,7 @@ void (* const rtw89_mac_c2h_info_handler[])(struct rtw89_dev *rtwdev, [RTW89_MAC_C2H_FUNC_DONE_ACK] = rtw89_mac_c2h_done_ack, [RTW89_MAC_C2H_FUNC_C2H_LOG] = rtw89_mac_c2h_log, [RTW89_MAC_C2H_FUNC_BCN_CNT] = rtw89_mac_c2h_bcn_cnt, + [RTW89_MAC_C2H_FUNC_BCN_UPD_DONE] = rtw89_mac_c2h_bcn_upd_done, }; static diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 241e89983c4a..25fe5e5c8a97 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -419,6 +419,7 @@ enum rtw89_mac_c2h_info_func { RTW89_MAC_C2H_FUNC_DONE_ACK, RTW89_MAC_C2H_FUNC_C2H_LOG, RTW89_MAC_C2H_FUNC_BCN_CNT, + RTW89_MAC_C2H_FUNC_BCN_UPD_DONE = 0x06, RTW89_MAC_C2H_FUNC_INFO_MAX, }; From 5846154126541b27281fbc9aba0c8ee97e22597b Mon Sep 17 00:00:00 2001 From: Akhilesh Patil Date: Fri, 8 Aug 2025 11:09:18 +0530 Subject: [PATCH 00406/11391] wifi: rtw89: 8852bt: Use standard helper for string choice Use standard helper str_on_off() defined at string_choices.h in _dpk_information() to improve code reusability. Reduce hardcoding of repeated use of the same strings to save code space. Reported-by: kernel test robot Closes: https://lore.kernel.org/r/202507282341.drTGfLWA-lkp@intel.com/ Signed-off-by: Akhilesh Patil Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/aJWNhu9bAkcjEyb4@bhairav-test.ee.iitb.ac.in --- drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c index d0e299803225..b01f921b4224 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c @@ -1883,8 +1883,8 @@ static void _dpk_information(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d[%d] (PHY%d): TSSI %s/ DBCC %s/ %s/ CH%d/ %s\n", path, dpk->cur_idx[path], phy, - rtwdev->is_tssi_mode[path] ? "on" : "off", - rtwdev->dbcc_en ? "on" : "off", + str_on_off(rtwdev->is_tssi_mode[path]), + str_on_off(rtwdev->dbcc_en), dpk->bp[path][kidx].band == 0 ? "2G" : dpk->bp[path][kidx].band == 1 ? "5G" : "6G", dpk->bp[path][kidx].ch, From 78a474b5a31a25e0a77e50df42be925f7cb575e6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 11 Aug 2025 15:54:04 +0200 Subject: [PATCH 00407/11391] 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 bdf0f2c84332f1e1b9dc3b267061e263bfaff097 Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Mon, 11 Aug 2025 15:04:18 +0800 Subject: [PATCH 00408/11391] ASoC: fix "dependant"->"dependent" Trivial fix to spelling mistake in comment text. Signed-off-by: Xichao Zhao Link: https://patch.msgid.link/20250811070418.352104-1-zhao.xichao@vivo.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8994.h | 12 ++++++------ sound/soc/codecs/wm8996.c | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h index bc584b17bf28..b28398aa9e48 100644 --- a/sound/soc/codecs/wm8994.h +++ b/sound/soc/codecs/wm8994.h @@ -106,33 +106,33 @@ struct wm8994_priv { int vss_ena[3]; int enh_eq_ena[3]; - /* Platform dependant DRC configuration */ + /* Platform dependent DRC configuration */ const char **drc_texts; int drc_cfg[WM8994_NUM_DRC]; struct soc_enum drc_enum; - /* Platform dependant ReTune mobile configuration */ + /* Platform dependent ReTune mobile configuration */ int num_retune_mobile_texts; const char **retune_mobile_texts; int retune_mobile_cfg[WM8994_NUM_EQ]; struct soc_enum retune_mobile_enum; - /* Platform dependant MBC configuration */ + /* Platform dependent MBC configuration */ int mbc_cfg; const char **mbc_texts; struct soc_enum mbc_enum; - /* Platform dependant VSS configuration */ + /* Platform dependent VSS configuration */ int vss_cfg; const char **vss_texts; struct soc_enum vss_enum; - /* Platform dependant VSS HPF configuration */ + /* Platform dependent VSS HPF configuration */ int vss_hpf_cfg; const char **vss_hpf_texts; struct soc_enum vss_hpf_enum; - /* Platform dependant enhanced EQ configuration */ + /* Platform dependent enhanced EQ configuration */ int enh_eq_cfg; const char **enh_eq_texts; struct soc_enum enh_eq_enum; diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 459b39998307..ee2040782532 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -77,7 +77,7 @@ struct wm8996_priv { int rx_rate[WM8996_AIFS]; int bclk_rate[WM8996_AIFS]; - /* Platform dependant ReTune mobile configuration */ + /* Platform dependent ReTune mobile configuration */ int num_retune_mobile_texts; const char **retune_mobile_texts; int retune_mobile_cfg[2]; From 8c02c8353460f8630313aef6810f34e134a3c1ee Mon Sep 17 00:00:00 2001 From: Mahdi Khosravi Date: Mon, 11 Aug 2025 11:09:40 +0300 Subject: [PATCH 00409/11391] ASoC: dt-bindings: realtek,alc5623: convert to DT schema Convert alc5623 audio codec binding to DT schema. Also add "realtek,alc5621" to the compatible list for existing use in kirkwood-t5325.dts. Signed-off-by: Mahdi Khosravi Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250811080940.7909-1-mmk1776@gmail.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/alc5623.txt | 25 --------- .../bindings/sound/realtek,alc5623.yaml | 54 +++++++++++++++++++ 2 files changed, 54 insertions(+), 25 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/alc5623.txt create mode 100644 Documentation/devicetree/bindings/sound/realtek,alc5623.yaml diff --git a/Documentation/devicetree/bindings/sound/alc5623.txt b/Documentation/devicetree/bindings/sound/alc5623.txt deleted file mode 100644 index 26c86c98d671..000000000000 --- a/Documentation/devicetree/bindings/sound/alc5623.txt +++ /dev/null @@ -1,25 +0,0 @@ -ALC5621/ALC5622/ALC5623 audio Codec - -Required properties: - - - compatible: "realtek,alc5623" - - reg: the I2C address of the device. - -Optional properties: - - - add-ctrl: Default register value for Reg-40h, Additional Control - Register. If absent or has the value of 0, the - register is untouched. - - - jack-det-ctrl: Default register value for Reg-5Ah, Jack Detect - Control Register. If absent or has value 0, the - register is untouched. - -Example: - - alc5621: alc5621@1a { - compatible = "alc5621"; - reg = <0x1a>; - add-ctrl = <0x3700>; - jack-det-ctrl = <0x4810>; - }; diff --git a/Documentation/devicetree/bindings/sound/realtek,alc5623.yaml b/Documentation/devicetree/bindings/sound/realtek,alc5623.yaml new file mode 100644 index 000000000000..683c58c3ef50 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/realtek,alc5623.yaml @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/realtek,alc5623.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ALC5621/ALC5623 Audio Codec + +maintainers: + - Mahdi Khosravi + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - realtek,alc5621 + - realtek,alc5623 + + reg: + maxItems: 1 + + add-ctrl: + description: + Default register value for Reg-40h, Additional Control Register. + If absent or zero, the register is left untouched. + $ref: /schemas/types.yaml#/definitions/uint32 + + jack-det-ctrl: + description: + Default register value for Reg-5Ah, Jack Detect Control Register. + If absent or zero, the register is left untouched. + $ref: /schemas/types.yaml#/definitions/uint32 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + codec@1a { + compatible = "realtek,alc5623"; + reg = <0x1a>; + add-ctrl = <0x3700>; + jack-det-ctrl = <0x4810>; + }; + }; From 0ecc0e17f05bbb953b6ea3812e78bab224f08595 Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Tue, 12 Aug 2025 11:38:16 +0800 Subject: [PATCH 00410/11391] spi: bcm2835: Remove redundant semicolons Remove unnecessary semicolons after comments. Fixes: 3ecd37edaa2a6 ("spi: bcm2835: enable dma modes for transfers meeting certain conditions") Signed-off-by: Liao Yuanhong Link: https://patch.msgid.link/20250812033817.487565-2-liaoyuanhong@vivo.com Signed-off-by: Mark Brown --- drivers/spi/spi-bcm2835.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index 77de5a07639a..192cc5ef65fb 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -622,7 +622,7 @@ static void bcm2835_spi_dma_rx_done(void *data) /* reset fifo and HW */ bcm2835_spi_reset_hw(bs); - /* and mark as completed */; + /* and mark as completed */ spi_finalize_current_transfer(ctlr); } From 528a813a5d98702cc6fd51983484cf7eec9ebcac Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Tue, 12 Aug 2025 11:38:17 +0800 Subject: [PATCH 00411/11391] spi: mtk-snfi: Remove redundant semicolons Remove unnecessary semicolons. Fixes: 764f1b7481645 ("spi: add driver for MTK SPI NAND Flash Interface") Signed-off-by: Liao Yuanhong Link: https://patch.msgid.link/20250812033817.487565-3-liaoyuanhong@vivo.com Signed-off-by: Mark Brown --- drivers/spi/spi-mtk-snfi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/spi-mtk-snfi.c b/drivers/spi/spi-mtk-snfi.c index e82ee6dcf498..ae38c244e258 100644 --- a/drivers/spi/spi-mtk-snfi.c +++ b/drivers/spi/spi-mtk-snfi.c @@ -1139,7 +1139,6 @@ static int mtk_snand_write_page_cache(struct mtk_snand *snf, // Prepare for custom write interrupt nfi_write32(snf, NFI_INTR_EN, NFI_IRQ_INTR_EN | NFI_IRQ_CUS_PG); reinit_completion(&snf->op_done); - ; // Trigger NFI into custom mode nfi_write16(snf, NFI_CMD, NFI_CMD_DUMMY_WRITE); From b832b19318534bb4f1673b24d78037fee339c679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Mon, 11 Aug 2025 14:10:21 +0200 Subject: [PATCH 00412/11391] spi: loopback-test: Don't use %pK through printk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the past %pK was preferable to %p as it would not leak raw pointer values into the kernel log. Since commit ad67b74d2469 ("printk: hash addresses printed with %p") the regular %p has been improved to avoid this issue. Furthermore, restricted pointers ("%pK") were never meant to be used through printk(). They can still unintentionally leak raw pointers or acquire sleeping locks in atomic contexts. Switch to the regular pointer formatting which is safer and easier to reason about. There are still a few users of %pK left, but these use it through seq_file, for which its usage is safe. Signed-off-by: Thomas Weißschuh Link: https://patch.msgid.link/20250811-restricted-pointers-spi-v1-1-32c47f954e4d@linutronix.de Signed-off-by: Mark Brown --- drivers/spi/spi-loopback-test.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-loopback-test.c b/drivers/spi/spi-loopback-test.c index 7dd92deffe3f..e0b131aa29b6 100644 --- a/drivers/spi/spi-loopback-test.c +++ b/drivers/spi/spi-loopback-test.c @@ -446,7 +446,7 @@ static void spi_test_dump_message(struct spi_device *spi, int i; u8 b; - dev_info(&spi->dev, " spi_msg@%pK\n", msg); + dev_info(&spi->dev, " spi_msg@%p\n", msg); if (msg->status) dev_info(&spi->dev, " status: %i\n", msg->status); @@ -456,15 +456,15 @@ static void spi_test_dump_message(struct spi_device *spi, msg->actual_length); list_for_each_entry(xfer, &msg->transfers, transfer_list) { - dev_info(&spi->dev, " spi_transfer@%pK\n", xfer); + dev_info(&spi->dev, " spi_transfer@%p\n", xfer); dev_info(&spi->dev, " len: %i\n", xfer->len); - dev_info(&spi->dev, " tx_buf: %pK\n", xfer->tx_buf); + dev_info(&spi->dev, " tx_buf: %p\n", xfer->tx_buf); if (dump_data && xfer->tx_buf) spi_test_print_hex_dump(" TX: ", xfer->tx_buf, xfer->len); - dev_info(&spi->dev, " rx_buf: %pK\n", xfer->rx_buf); + dev_info(&spi->dev, " rx_buf: %p\n", xfer->rx_buf); if (dump_data && xfer->rx_buf) spi_test_print_hex_dump(" RX: ", xfer->rx_buf, @@ -558,7 +558,7 @@ static int spi_check_rx_ranges(struct spi_device *spi, /* if still not found then something has modified too much */ /* we could list the "closest" transfer here... */ dev_err(&spi->dev, - "loopback strangeness - rx changed outside of allowed range at: %pK\n", + "loopback strangeness - rx changed outside of allowed range at: %p\n", addr); /* do not return, only set ret, * so that we list all addresses @@ -696,7 +696,7 @@ static int spi_test_translate(struct spi_device *spi, } dev_err(&spi->dev, - "PointerRange [%pK:%pK[ not in range [%pK:%pK[ or [%pK:%pK[\n", + "PointerRange [%p:%p[ not in range [%p:%p[ or [%p:%p[\n", *ptr, *ptr + len, RX(0), RX(SPI_TEST_MAX_SIZE), TX(0), TX(SPI_TEST_MAX_SIZE)); From a84eeacbf9325fd7f604b80f246aaba157730cd5 Mon Sep 17 00:00:00 2001 From: Jeongjun Park Date: Thu, 17 Jul 2025 20:26:43 +0900 Subject: [PATCH 00413/11391] 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 00414/11391] 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 00415/11391] 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 f8328b7549e1faff45e32ab2ecc2573b90604e76 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 11 Aug 2025 22:16:29 -0500 Subject: [PATCH 00416/11391] arm64: dts: qcom: sc7280: Describe the first PCIe controller and PHY Only one PCIe controller has been described so far, but the SC7280 has two controllers/phys. Describe the second one as well. Signed-off-by: Bjorn Andersson Reviewed-by: Krzysztof Kozlowski Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250811-sc7280-pcie0-v1-1-6093e5b208f9@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc7280.dtsi | 134 +++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index 97bb8a42a7b6..e38c2fbbecd5 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -2200,6 +2200,135 @@ wifi: wifi@17a10040 { qcom,smem-state-names = "wlan-smp2p-out"; }; + pcie0: pcie@1c00000 { + compatible = "qcom,pcie-sc7280"; + reg = <0 0x01c00000 0 0x3000>, + <0 0x60000000 0 0xf1d>, + <0 0x60000f20 0 0xa8>, + <0 0x60001000 0 0x1000>, + <0 0x60100000 0 0x100000>, + <0 0x01c03000 0 0x1000>; + reg-names = "parf", "dbi", "elbi", "atu", "config", "mhi"; + device_type = "pci"; + linux,pci-domain = <0>; + bus-range = <0x00 0xff>; + num-lanes = <1>; + + #address-cells = <3>; + #size-cells = <2>; + + ranges = <0x01000000 0x0 0x00000000 0x0 0x60200000 0x0 0x100000>, + <0x02000000 0x0 0x60300000 0x0 0x60300000 0x0 0x3d00000>; + + interrupts = , + , + , + , + , + , + , + , + ; + interrupt-names = "msi0", + "msi1", + "msi2", + "msi3", + "msi4", + "msi5", + "msi6", + "msi7", + "global"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0x7>; + interrupt-map = <0 0 0 1 &intc 0 0 0 149 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 2 &intc 0 0 0 150 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 3 &intc 0 0 0 151 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 4 &intc 0 0 0 152 IRQ_TYPE_LEVEL_HIGH>; + + clocks = <&gcc GCC_PCIE_0_PIPE_CLK>, + <&gcc GCC_PCIE_0_PIPE_CLK_SRC>, + <&pcie0_phy>, + <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_PCIE_0_AUX_CLK>, + <&gcc GCC_PCIE_0_CFG_AHB_CLK>, + <&gcc GCC_PCIE_0_MSTR_AXI_CLK>, + <&gcc GCC_PCIE_0_SLV_AXI_CLK>, + <&gcc GCC_PCIE_0_SLV_Q2A_AXI_CLK>, + <&gcc GCC_AGGRE_NOC_PCIE_TBU_CLK>, + <&gcc GCC_DDRSS_PCIE_SF_CLK>, + <&gcc GCC_AGGRE_NOC_PCIE_CENTER_SF_AXI_CLK>, + <&gcc GCC_AGGRE_NOC_PCIE_0_AXI_CLK>; + clock-names = "pipe", + "pipe_mux", + "phy_pipe", + "ref", + "aux", + "cfg", + "bus_master", + "bus_slave", + "slave_q2a", + "tbu", + "ddrss_sf_tbu", + "aggre0", + "aggre1"; + + iommu-map = <0x0 &apps_smmu 0x1c00 0x1>, + <0x100 &apps_smmu 0x1c01 0x1>; + + resets = <&gcc GCC_PCIE_0_BCR>; + reset-names = "pci"; + + power-domains = <&gcc GCC_PCIE_0_GDSC>; + + phys = <&pcie0_phy>; + phy-names = "pciephy"; + + pinctrl-names = "default"; + pinctrl-0 = <&pcie0_clkreq_n>; + dma-coherent; + + status = "disabled"; + + pcie0_port: pcie@0 { + device_type = "pci"; + reg = <0x0 0x0 0x0 0x0 0x0>; + bus-range = <0x01 0xff>; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + }; + }; + + pcie0_phy: phy@1c06000 { + compatible = "qcom,sm8250-qmp-gen3x1-pcie-phy"; + reg = <0 0x01c06000 0 0x1000>; + + clocks = <&gcc GCC_PCIE_0_AUX_CLK>, + <&gcc GCC_PCIE_0_CFG_AHB_CLK>, + <&gcc GCC_PCIE_CLKREF_EN>, + <&gcc GCC_PCIE0_PHY_RCHNG_CLK>, + <&gcc GCC_PCIE_0_PIPE_CLK>; + clock-names = "aux", + "cfg_ahb", + "ref", + "refgen", + "pipe"; + + clock-output-names = "pcie_0_pipe_clk"; + #clock-cells = <0>; + + #phy-cells = <0>; + + resets = <&gcc GCC_PCIE_0_PHY_BCR>; + reset-names = "phy"; + + assigned-clocks = <&gcc GCC_PCIE0_PHY_RCHNG_CLK>; + assigned-clock-rates = <100000000>; + + status = "disabled"; + }; + pcie1: pcie@1c08000 { compatible = "qcom,pcie-sc7280"; reg = <0 0x01c08000 0 0x3000>, @@ -5279,6 +5408,11 @@ mi2s1_ws: mi2s1-ws-state { function = "mi2s1_ws"; }; + pcie0_clkreq_n: pcie0-clkreq-n-state { + pins = "gpio88"; + function = "pcie0_clkreqn"; + }; + pcie1_clkreq_n: pcie1-clkreq-n-state { pins = "gpio79"; function = "pcie1_clkreqn"; From 039a504cda2cb69354387aa453391ec89a9e0e49 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 11 Aug 2025 22:11:33 -0500 Subject: [PATCH 00417/11391] dt-bindings: clock: dispcc-sc7280: Add display resets Like other platforms the sc7280 display clock controller provides a couple of resets, add the defines to allow referring to them. Signed-off-by: Bjorn Andersson Reviewed-by: Taniya Das Link: https://lore.kernel.org/r/20250811-sc7280-mdss-reset-v1-1-83ceff1d48de@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- include/dt-bindings/clock/qcom,dispcc-sc7280.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/dt-bindings/clock/qcom,dispcc-sc7280.h b/include/dt-bindings/clock/qcom,dispcc-sc7280.h index a4a692c20acf..9f113f346be8 100644 --- a/include/dt-bindings/clock/qcom,dispcc-sc7280.h +++ b/include/dt-bindings/clock/qcom,dispcc-sc7280.h @@ -52,4 +52,8 @@ /* DISP_CC power domains */ #define DISP_CC_MDSS_CORE_GDSC 0 +/* DISPCC resets */ +#define DISP_CC_MDSS_CORE_BCR 0 +#define DISP_CC_MDSS_RSCC_BCR 1 + #endif From 5a5f478ed7c7394dadb65a96f409e0749caefed5 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 11 Aug 2025 22:11:34 -0500 Subject: [PATCH 00418/11391] 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 9cdb77e3103a449ee54f397d29321a5d4157bcb7 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 11 Aug 2025 22:11:35 -0500 Subject: [PATCH 00419/11391] arm64: dts: qcom: sc7280: Add MDSS_CORE reset to mdss Like on other platforms, if the OS does not support recovering the state left by the bootloader it needs access to MDSS_CORE, so that it can clear the MDSS configuration. Until now it seems no version of the bootloaders have done so, but e.g. the Particle Tachyon ships with a bootloader that does leave the display in a state that results in a series of iommu faults. So let's provide the reset, to allow the OS to clear that state. Signed-off-by: Bjorn Andersson Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250811-sc7280-mdss-reset-v1-3-83ceff1d48de@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc7280.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index e38c2fbbecd5..1a7679d38a42 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -4847,6 +4847,8 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, iommus = <&apps_smmu 0x900 0x402>; + resets = <&dispcc DISP_CC_MDSS_CORE_BCR>; + #address-cells = <2>; #size-cells = <2>; ranges; From 393d69df0fda903dc41e071fef76baf485510672 Mon Sep 17 00:00:00 2001 From: Pushpendra Singh Date: Wed, 2 Jul 2025 05:31:20 +0530 Subject: [PATCH 00420/11391] arm64: dts: qcom: sc7280: Add support for two additional DDR frequencies The SC7280 SoC now supports two additional frequencies. This patch add those frequencies to the BWMON OPP table and updates the frequency mapping table accordingly. These changes do not impact existing platforms, as the updated mapping only affects the highest OPP. On any given platform, this will continue to vote for the maximum available OPP. Signed-off-by: Pushpendra Singh Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250702000120.2902158-1-quic_pussin@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc7280.dtsi | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index 1a7679d38a42..0dd6a5c91d10 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -620,12 +620,12 @@ cpu4_opp_2208mhz: opp-2208000000 { cpu4_opp_2400mhz: opp-2400000000 { opp-hz = /bits/ 64 <2400000000>; - opp-peak-kBps = <8532000 48537600>; + opp-peak-kBps = <12787200 48537600>; }; cpu4_opp_2611mhz: opp-2611200000 { opp-hz = /bits/ 64 <2611200000>; - opp-peak-kBps = <8532000 48537600>; + opp-peak-kBps = <12787200 48537600>; }; }; @@ -685,22 +685,22 @@ cpu7_opp_2381mhz: opp-2380800000 { cpu7_opp_2400mhz: opp-2400000000 { opp-hz = /bits/ 64 <2400000000>; - opp-peak-kBps = <8532000 48537600>; + opp-peak-kBps = <12787200 48537600>; }; cpu7_opp_2515mhz: opp-2515200000 { opp-hz = /bits/ 64 <2515200000>; - opp-peak-kBps = <8532000 48537600>; + opp-peak-kBps = <12787200 48537600>; }; cpu7_opp_2707mhz: opp-2707200000 { opp-hz = /bits/ 64 <2707200000>; - opp-peak-kBps = <8532000 48537600>; + opp-peak-kBps = <12787200 48537600>; }; cpu7_opp_3014mhz: opp-3014400000 { opp-hz = /bits/ 64 <3014400000>; - opp-peak-kBps = <8532000 48537600>; + opp-peak-kBps = <12787200 48537600>; }; }; @@ -4142,6 +4142,12 @@ opp-6 { opp-7 { opp-peak-kBps = <8532000>; }; + opp-8 { + opp-peak-kBps = <10944000>; + }; + opp-9 { + opp-peak-kBps = <12787200>; + }; }; }; From d56ddcee0101a4b948be0d388e91f5f38f14d448 Mon Sep 17 00:00:00 2001 From: Kathiravan Thirumoorthy Date: Tue, 12 Aug 2025 16:02:41 +0530 Subject: [PATCH 00421/11391] arm64: dts: qcom: ipq5424: Describe the 4-wire UART SE QUPv3 in IPQ5424 consists of six Serial Engines (SEs). Describe the first SE, which supports a 4-wire UART configuration suitable for applications such as HS-UART. Note that the required initialization for this SE is not handled by the bootloader. Therefore, add the SE node in the device tree but keep it reserved. Enable it once Linux gains support for configuring the SE, allowing to use in relevant RDPs. Signed-off-by: Kathiravan Thirumoorthy Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250812-ipq5424_hsuart-v4-1-f1faa7704ea9@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/ipq5424-rdp466.dts | 18 ++++++++++++++++++ arch/arm64/boot/dts/qcom/ipq5424.dtsi | 9 +++++++++ 2 files changed, 27 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/ipq5424-rdp466.dts b/arch/arm64/boot/dts/qcom/ipq5424-rdp466.dts index 117f1785e8b8..738618551203 100644 --- a/arch/arm64/boot/dts/qcom/ipq5424-rdp466.dts +++ b/arch/arm64/boot/dts/qcom/ipq5424-rdp466.dts @@ -224,6 +224,13 @@ data-pins { }; }; + uart0_pins: uart0-default-state { + pins = "gpio10", "gpio11", "gpio12", "gpio13"; + function = "uart0"; + drive-strength = <8>; + bias-pull-down; + }; + pcie2_default_state: pcie2-default-state { pins = "gpio31"; function = "gpio"; @@ -239,6 +246,17 @@ pcie3_default_state: pcie3-default-state { }; }; +&uart0 { + pinctrl-0 = <&uart0_pins>; + pinctrl-names = "default"; + /* + * The required initialization for this SE is not handled by the + * bootloader. Therefore, keep the device in "reserved" state until + * linux gains support for configuring the SE. + */ + status = "reserved"; +}; + &uart1 { pinctrl-0 = <&uart1_pins>; pinctrl-names = "default"; diff --git a/arch/arm64/boot/dts/qcom/ipq5424.dtsi b/arch/arm64/boot/dts/qcom/ipq5424.dtsi index 2eea8a078595..bd891e39f33e 100644 --- a/arch/arm64/boot/dts/qcom/ipq5424.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq5424.dtsi @@ -442,6 +442,15 @@ qupv3: geniqup@1ac0000 { #address-cells = <2>; #size-cells = <2>; + uart0: serial@1a80000 { + compatible = "qcom,geni-uart"; + reg = <0 0x01a80000 0 0x4000>; + clocks = <&gcc GCC_QUPV3_UART0_CLK>; + clock-names = "se"; + interrupts = ; + status = "disabled"; + }; + uart1: serial@1a84000 { compatible = "qcom,geni-debug-uart"; reg = <0 0x01a84000 0 0x4000>; From 4ea55ecb4990aa4142ddae5f713289f4101f046f Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 11 Jun 2025 18:33:18 +0200 Subject: [PATCH 00422/11391] arm64: dts: qcom: sdm632-fairphone-fp3: Enable display and GPU Add the description for the display panel found on this phone. Unfortunately the LCDB module on PMI632 isn't yet supported upstream so we need to use a dummy regulator-fixed in the meantime. And with this done we can also enable the GPU and set the zap shader firmware path. Reviewed-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20250611-fp3-display-v4-4-ef67701e7687@lucaweiss.eu Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/msm8953.dtsi | 2 +- .../boot/dts/qcom/sdm632-fairphone-fp3.dts | 62 +++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi index 273e79fb7569..c5205d09c442 100644 --- a/arch/arm64/boot/dts/qcom/msm8953.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi @@ -1147,7 +1147,7 @@ &bimc SLV_EBI RPM_ALWAYS_TAG>, status = "disabled"; - zap-shader { + gpu_zap_shader: zap-shader { memory-region = <&zap_shader_region>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm632-fairphone-fp3.dts b/arch/arm64/boot/dts/qcom/sdm632-fairphone-fp3.dts index 31ed26c31e6e..55a45b528bd3 100644 --- a/arch/arm64/boot/dts/qcom/sdm632-fairphone-fp3.dts +++ b/arch/arm64/boot/dts/qcom/sdm632-fairphone-fp3.dts @@ -36,6 +36,14 @@ key-volume-up { }; }; + /* Dummy regulator until PMI632 has LCDB VSP/VSN support */ + lcdb_dummy: regulator-lcdb-dummy { + compatible = "regulator-fixed"; + regulator-name = "lcdb_dummy"; + regulator-min-microvolt = <5500000>; + regulator-max-microvolt = <5500000>; + }; + vph_pwr: vph-pwr-regulator { compatible = "regulator-fixed"; regulator-name = "vph_pwr"; @@ -44,6 +52,14 @@ vph_pwr: vph-pwr-regulator { }; }; +&gpu { + status = "okay"; +}; + +&gpu_zap_shader { + firmware-name = "qcom/msm8953/fairphone/fp3/a506_zap.mbn"; +}; + &hsusb_phy { vdd-supply = <&pm8953_l3>; vdda-pll-supply = <&pm8953_l7>; @@ -87,6 +103,45 @@ &lpass { status = "okay"; }; +&mdss { + status = "okay"; +}; + +&mdss_dsi0 { + vdda-supply = <&pm8953_s3>; + status = "okay"; + + panel@0 { + compatible = "djn,98-03057-6598b-i"; + reg = <0>; + + reset-gpios = <&tlmm 61 GPIO_ACTIVE_LOW>; + + iovcc-supply = <&pm8953_l6>; + vsn-supply = <&lcdb_dummy>; + vsp-supply = <&lcdb_dummy>; + + pinctrl-0 = <&mdss_te_default>; + pinctrl-names = "default"; + + port { + panel_in: endpoint { + remote-endpoint = <&mdss_dsi0_out>; + }; + }; + }; +}; + +&mdss_dsi0_out { + data-lanes = <0 1 2 3>; + remote-endpoint = <&panel_in>; +}; + +&mdss_dsi0_phy { + vcca-supply = <&pm8953_l3>; + status = "okay"; +}; + &mpss { firmware-name = "qcom/msm8953/fairphone/fp3/mba.mbn", "qcom/msm8953/fairphone/fp3/modem.mbn"; @@ -292,6 +347,13 @@ &tlmm { * 135-138: fingerprint reader (SPI) */ gpio-reserved-ranges = <0 4>, <135 4>; + + mdss_te_default: mdss-te-default-state { + pins = "gpio24"; + function = "mdp_vsync"; + drive-strength = <2>; + bias-pull-down; + }; }; &uart_0 { From ebfe5797ac3e6e9fb56340b6b228d2747fdec912 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eric=20Gon=C3=A7alves?= Date: Sun, 15 Jun 2025 20:44:37 +0000 Subject: [PATCH 00423/11391] dt-bindings: arm: qcom: document r0q board binding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds compatible for the Samsung Galaxy S22 (SM-S901E) (r0q), based on the Snapdragon 8 Gen 1 SoC. Signed-off-by: Eric Gonçalves Link: https://lore.kernel.org/r/20250615204438.1130213-1-ghatto404@gmail.com Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/arm/qcom.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml index b5acb0d26346..fa929698229e 100644 --- a/Documentation/devicetree/bindings/arm/qcom.yaml +++ b/Documentation/devicetree/bindings/arm/qcom.yaml @@ -1002,6 +1002,7 @@ properties: - qcom,sm8450-qrd - sony,pdx223 - sony,pdx224 + - samsung,r0q - const: qcom,sm8450 - items: From 46952305d2b64e9a2498c53046a832b51c93e5a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eric=20Gon=C3=A7alves?= Date: Sun, 15 Jun 2025 20:44:38 +0000 Subject: [PATCH 00424/11391] arm64: dts: qcom: sm8450: add initial device tree for Samsung Galaxy S22 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds new device support for the Samsung Galaxy S22 (SM-S901E) phone Working features: - simple-framebuffer - side buttons - storage - usb Signed-off-by: Eric Gonçalves Link: https://lore.kernel.org/r/20250615204438.1130213-2-ghatto404@gmail.com Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/sm8450-samsung-r0q.dts | 364 ++++++++++++++++++ 1 file changed, 364 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sm8450-samsung-r0q.dts diff --git a/arch/arm64/boot/dts/qcom/sm8450-samsung-r0q.dts b/arch/arm64/boot/dts/qcom/sm8450-samsung-r0q.dts new file mode 100644 index 000000000000..e9e21c25444a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8450-samsung-r0q.dts @@ -0,0 +1,364 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025, Eric Gonçalves + */ + +/dts-v1/; + +#include +#include +#include + +#include "sm8450.dtsi" +#include "pm8350.dtsi" +#include "pm8350b.dtsi" +#include "pm8350c.dtsi" +#include "pm8450.dtsi" +#include "pmk8350.dtsi" +#include "pmr735a.dtsi" + +/delete-node/ &xbl_ramdump_mem; +/delete-node/ &xbl_sc_mem; +/delete-node/ &adsp_mem; +/delete-node/ &rmtfs_mem; +/delete-node/ &mte_mem; +/delete-node/ &trusted_apps_mem; +/delete-node/ &trusted_apps_ext_mem; + +/ { + chassis-type = "handset"; + model = "Samsung Galaxy S22 (SM-S901E)"; + compatible = "samsung,r0q", "qcom,sm8450"; + + chosen { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + bootargs = "clk_ignore_unused pd_ignore_unused"; + linux,initrd-start = <0x00 0xb6915000>; + linux,initrd-end = <0x00 0xb7fff22c>; + stdout-path = "serial0:115200n8"; + + framebuffer: framebuffer@b8000000 { + compatible = "simple-framebuffer"; + reg = <0x0 0xb8000000 0x0 0x2b00000>; + width = <1080>; + height = <2340>; + stride = <(1080 * 4)>; + format = "a8r8g8b8"; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + autorepeat; + + pinctrl-0 = <&vol_up_n>; + pinctrl-names = "default"; + + key-vol-up { + label = "Volume Up"; + linux,code = ; + gpios = <&pm8350_gpios 6 GPIO_ACTIVE_LOW>; + debounce-interval = <15>; + }; + }; + + memory { + ddr_device_type = <0x08>; + device_type = "memory"; + reg = <0x00 0x80000000 0x00 0x6a000000 0x00 0xf1c00000 0x00 0xe400000 0x08 0x00 0x00 0x3ab00000 0x08 0x40000000 0x01 0x40000000 0x08 0x3b100000 0x00 0x1e00000>; + }; + + reserved-memory { + xbl_ramdump_mem: memory@a6b80000 { + reg = <0x0 0xa7d00000 0x0 0x300000>; + no-map; + }; + + xbl_sc_mem: memory@a6e00000 { + reg = <0x0 0xa6e00000 0x0 0x40000>; + no-map; + }; + + adsp_mem: memory@9fd00000 { + reg = <0x0 0x84500000 0x0 0x3b00000>; + no-map; + }; + + rmtfs_mem: memory@fe200000 { + compatible = "qcom,rmtfs-mem"; + reg = <0x0 0xfe200000 0x0 0x280000>; + reg-names = "rmtfs"; + qcom,client-id = <1>; + no-map; + + qcom,vmid = ; + }; + + splash_region@b8000000 { + reg = <0x0 0xb8000000 0x0 0x2b00000>; + no-map; + }; + }; + + vph_pwr: vph-pwr-regulator { + compatible = "regulator-fixed"; + regulator-name = "vph_pwr"; + regulator-min-microvolt = <3700000>; + regulator-max-microvolt = <3700000>; + + regulator-always-on; + regulator-boot-on; + }; +}; + +&tlmm { + gpio-reserved-ranges = <36 4>, <50 1>, <93 1>; + + dsi_default: dsi-default-state { + pins = "gpio6"; + function = "gpio"; + drive-strength = <8>; + bias-disable; + }; + + dsi_suspend: dsi-suspend-state { + pins = "gpio6"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; +}; + +&apps_rsc { + regulators-0 { + compatible = "qcom,pm8350-rpmh-regulators"; + qcom,pmic-id = "b"; + + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + vdd-s3-supply = <&vph_pwr>; + vdd-s4-supply = <&vph_pwr>; + vdd-s5-supply = <&vph_pwr>; + vdd-s6-supply = <&vph_pwr>; + vdd-s7-supply = <&vph_pwr>; + vdd-s8-supply = <&vph_pwr>; + vdd-s9-supply = <&vph_pwr>; + vdd-s10-supply = <&vph_pwr>; + vdd-s11-supply = <&vph_pwr>; + vdd-s12-supply = <&vph_pwr>; + + vdd-l1-l4-supply = <&vreg_s11b_0p95>; + vdd-l2-l7-supply = <&vreg_bob>; + vdd-l3-l5-supply = <&vreg_bob>; + vdd-l6-l9-l10-supply = <&vreg_s12b_1p25>; + vdd-l8-supply = <&vreg_s2h_0p95>; + + vreg_s11b_0p95: smps11 { + regulator-name = "vreg_s11b_0p95"; + regulator-min-microvolt = <848000>; + regulator-max-microvolt = <1104000>; + }; + + vreg_s12b_1p25: smps12 { + regulator-name = "vreg_s12b_1p25"; + regulator-min-microvolt = <1224000>; + regulator-max-microvolt = <1400000>; + }; + + vreg_l1b_0p91: ldo1 { + regulator-name = "vreg_l1b_0p91"; + regulator-min-microvolt = <912000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + + vreg_l2b_3p07: ldo2 { + regulator-name = "vreg_l2b_3p07"; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3072000>; + regulator-initial-mode = ; + }; + + vreg_l5b_0p88: ldo5 { + regulator-name = "vreg_l5b_0p88"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <888000>; + regulator-initial-mode = ; + }; + + vreg_l6b_1p2: ldo6 { + regulator-name = "vreg_l6b_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l7b_2p5: ldo7 { + regulator-name = "vreg_l7b_2p5"; + regulator-min-microvolt = <2504000>; + regulator-max-microvolt = <2504000>; + regulator-initial-mode = ; + }; + + vreg_l9b_1p2: ldo9 { + regulator-name = "vreg_l9b_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + }; + + regulators-1 { + compatible = "qcom,pm8350c-rpmh-regulators"; + qcom,pmic-id = "c"; + + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + vdd-s3-supply = <&vph_pwr>; + vdd-s4-supply = <&vph_pwr>; + vdd-s5-supply = <&vph_pwr>; + vdd-s6-supply = <&vph_pwr>; + vdd-s7-supply = <&vph_pwr>; + vdd-s8-supply = <&vph_pwr>; + vdd-s9-supply = <&vph_pwr>; + vdd-s10-supply = <&vph_pwr>; + + vdd-l1-l12-supply = <&vreg_bob>; + vdd-l2-l8-supply = <&vreg_bob>; + vdd-l3-l4-l5-l7-l13-supply = <&vreg_bob>; + vdd-l6-l9-l11-supply = <&vreg_bob>; + + vdd-bob-supply = <&vph_pwr>; + + vreg_s1c_1p86: smps1 { + regulator-name = "vreg_s1c_1p86"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2024000>; + }; + + vreg_bob: bob { + regulator-name = "vreg_bob"; + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3960000>; + regulator-initial-mode = ; + }; + + vreg_l1c_1p8: ldo1 { + regulator-name = "vreg_l1c_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + }; + + regulators-2 { + compatible = "qcom,pm8450-rpmh-regulators"; + qcom,pmic-id = "h"; + + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + vdd-s3-supply = <&vph_pwr>; + vdd-s4-supply = <&vph_pwr>; + vdd-s5-supply = <&vph_pwr>; + vdd-s6-supply = <&vph_pwr>; + + vdd-l2-supply = <&vreg_bob>; + vdd-l3-supply = <&vreg_bob>; + vdd-l4-supply = <&vreg_bob>; + + vreg_s2h_0p95: smps2 { + regulator-name = "vreg_s2h_0p95"; + regulator-min-microvolt = <848000>; + regulator-max-microvolt = <1104000>; + }; + }; + + regulators-3 { + compatible = "qcom,pmr735a-rpmh-regulators"; + qcom,pmic-id = "e"; + + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + vdd-s3-supply = <&vph_pwr>; + + vdd-l1-l2-supply = <&vreg_s2e_0p85>; + vdd-l3-supply = <&vreg_s1e_1p25>; + vdd-l4-supply = <&vreg_s1c_1p86>; + vdd-l5-l6-supply = <&vreg_s1c_1p86>; + vdd-l7-bob-supply = <&vreg_bob>; + + vreg_s1e_1p25: smps1 { + regulator-name = "vreg_s1e_1p25"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1296000>; + }; + + vreg_s2e_0p85: smps2 { + regulator-name = "vreg_s2e_0p85"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1040000>; + }; + }; +}; + +&pm8350_gpios { + vol_up_n: vol-up-n-state { + pins = "gpio6"; + function = "normal"; + power-source = <1>; + input-enable; + }; +}; + +&pon_pwrkey { + status = "okay"; +}; + +&pon_resin { + status = "okay"; + linux,code = ; +}; + +&usb_1 { + qcom,select-utmi-as-pipe-clk; + status = "okay"; +}; + +&usb_1_dwc3 { + dr_mode = "peripheral"; + maximum-speed = "high-speed"; + + phys = <&usb_1_hsphy>; + phy-names = "usb2-phy"; +}; + +&usb_1_hsphy { + status = "okay"; + vdda-pll-supply = <&vreg_l5b_0p88>; + vdda18-supply = <&vreg_l1c_1p8>; + vdda33-supply = <&vreg_l2b_3p07>; +}; + +&ufs_mem_hc { + reset-gpios = <&tlmm 210 GPIO_ACTIVE_LOW>; + + vcc-supply = <&vreg_l7b_2p5>; + vcc-max-microamp = <1100000>; + vccq-supply = <&vreg_l9b_1p2>; + vccq-max-microamp = <1200000>; + vccq2-supply = <&vreg_l9b_1p2>; + vccq2-max-microamp = <1200000>; + vdd-hba-supply = <&vreg_l9b_1p2>; + + status = "okay"; +}; + +&ufs_mem_phy { + status = "okay"; + + vdda-phy-supply = <&vreg_l5b_0p88>; + vdda-pll-supply = <&vreg_l6b_1p2>; +}; From d6111177f6504b013d0424657e131ae9a36ab5e2 Mon Sep 17 00:00:00 2001 From: Mrinmay Sarkar Date: Tue, 17 Jun 2025 17:08:20 +0530 Subject: [PATCH 00425/11391] arm64: dts: qcom: sa8775p: Remove max link speed property for PCIe EP The maximum link speed was previously restricted to Gen3 due to the absence of Gen4 equalization support in the driver. As Gen4 equalization is already supported by the PCIe controller driver, remove the max-link-speed property. Signed-off-by: Mrinmay Sarkar Link: https://lore.kernel.org/r/20250617-update_phy-v5-2-2df83ed6a373@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/lemans.dtsi | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi index 9b7fa4c932e3..64f5378c6a47 100644 --- a/arch/arm64/boot/dts/qcom/lemans.dtsi +++ b/arch/arm64/boot/dts/qcom/lemans.dtsi @@ -7711,7 +7711,6 @@ pcie0_ep: pcie-ep@1c00000 { power-domains = <&gcc PCIE_0_GDSC>; phys = <&pcie0_phy>; phy-names = "pciephy"; - max-link-speed = <3>; /* FIXME: Limiting the Gen speed due to stability issues */ num-lanes = <2>; linux,pci-domain = <0>; @@ -7882,7 +7881,6 @@ pcie1_ep: pcie-ep@1c10000 { power-domains = <&gcc PCIE_1_GDSC>; phys = <&pcie1_phy>; phy-names = "pciephy"; - max-link-speed = <3>; /* FIXME: Limiting the Gen speed due to stability issues */ num-lanes = <4>; linux,pci-domain = <1>; From 4e4afd6bb9657d7cf23f6becf23706882b9822c0 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Wed, 2 Jul 2025 14:34:30 +0530 Subject: [PATCH 00426/11391] arm64: defconfig: Enable QCS615 clock controllers Enable the QCS615 display, video, camera and graphics clock controller for their respective functionalities on the Qualcomm QCS615 ride platform. Reviewed-by: Dmitry Baryshkov Signed-off-by: Taniya Das Link: https://lore.kernel.org/r/20250702-qcs615-mm-v10-clock-controllers-v11-10-9c216e1615ab@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/configs/defconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 58f87d09366c..68a024fadd78 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -1385,11 +1385,15 @@ CONFIG_MSM_GCC_8998=y CONFIG_MSM_MMCC_8998=m CONFIG_QCM_GCC_2290=y CONFIG_QCM_DISPCC_2290=m +CONFIG_QCS_DISPCC_615=m +CONFIG_QCS_CAMCC_615=m CONFIG_QCS_GCC_404=y CONFIG_QCS_GCC_615=y CONFIG_QCS_GCC_8300=y CONFIG_SC_CAMCC_7280=m CONFIG_SA_CAMCC_8775P=m +CONFIG_QCS_GPUCC_615=m +CONFIG_QCS_VIDEOCC_615=m CONFIG_QDU_GCC_1000=y CONFIG_SC_CAMCC_8280XP=m CONFIG_SC_DISPCC_7280=m From 6af515c9f3ccec3eb8a262ca86bef2c499d07951 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 23 Jul 2025 11:21:52 -0400 Subject: [PATCH 00427/11391] dlm: check for defined force value in dlm_lockspace_release Force values over 3 are undefined, so don't treat them as 3. Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/lockspace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index 1929327ffbe1..ee11a70def92 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -730,7 +730,7 @@ static int release_lockspace(struct dlm_ls *ls, int force) dlm_device_deregister(ls); - if (force < 3 && dlm_user_daemon_available()) + if (force != 3 && dlm_user_daemon_available()) do_uevent(ls, 0); dlm_recoverd_stop(ls); From a8a5ea012471dd19ea9cb4d668c27ac678e84a3e Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 9 Jul 2025 12:08:58 +0200 Subject: [PATCH 00428/11391] arm64: dts: qcom: x1e80100: Add videocc Add the video clock controller for X1E80100, similar to sm8550.dtsi. It provides the needed clocks/power domains for the iris video codec. Reviewed-by: Bryan O'Donoghue Signed-off-by: Stephan Gerhold Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250709-x1e-videocc-v2-6-ad1acf5674b4@linaro.org Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/x1e80100.dtsi | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/x1e80100.dtsi b/arch/arm64/boot/dts/qcom/x1e80100.dtsi index 4dba9f2b64f7..f293b13ecc0c 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100.dtsi +++ b/arch/arm64/boot/dts/qcom/x1e80100.dtsi @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -5182,6 +5183,20 @@ usb_1_ss1_dwc3_ss: endpoint { }; }; + videocc: clock-controller@aaf0000 { + compatible = "qcom,x1e80100-videocc"; + reg = <0 0x0aaf0000 0 0x10000>; + clocks = <&bi_tcxo_div2>, + <&gcc GCC_VIDEO_AHB_CLK>; + power-domains = <&rpmhpd RPMHPD_MMCX>, + <&rpmhpd RPMHPD_MXC>; + required-opps = <&rpmhpd_opp_low_svs>, + <&rpmhpd_opp_low_svs>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; + mdss: display-subsystem@ae00000 { compatible = "qcom,x1e80100-mdss"; reg = <0 0x0ae00000 0 0x1000>; From bea90085dcb0f9a75748e73d723bde557a5ebf1a Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 23 Jul 2025 11:21:53 -0400 Subject: [PATCH 00429/11391] dlm: use defines for force values in dlm_release_lockspace Clarify the use of the force parameter by renaming it to "release_option" and adding defines (with descriptions) for each of the accepted values. Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- drivers/md/md-cluster.c | 4 ++-- fs/dlm/lockspace.c | 20 +++++++++----------- fs/dlm/user.c | 6 +++--- fs/gfs2/lock_dlm.c | 4 ++-- fs/ocfs2/stack_user.c | 2 +- include/linux/dlm.h | 26 +++++++++++++++++++++++++- 6 files changed, 42 insertions(+), 20 deletions(-) diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c index 5497eaee96e7..6e9a0045f0ff 100644 --- a/drivers/md/md-cluster.c +++ b/drivers/md/md-cluster.c @@ -979,7 +979,7 @@ static int join(struct mddev *mddev, int nodes) lockres_free(cinfo->resync_lockres); lockres_free(cinfo->bitmap_lockres); if (cinfo->lockspace) - dlm_release_lockspace(cinfo->lockspace, 2); + dlm_release_lockspace(cinfo->lockspace, DLM_RELEASE_NORMAL); mddev->cluster_info = NULL; kfree(cinfo); return ret; @@ -1042,7 +1042,7 @@ static int leave(struct mddev *mddev) lockres_free(cinfo->resync_lockres); lockres_free(cinfo->bitmap_lockres); unlock_all_bitmaps(mddev); - dlm_release_lockspace(cinfo->lockspace, 2); + dlm_release_lockspace(cinfo->lockspace, DLM_RELEASE_NORMAL); kfree(cinfo); return 0; } diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index ee11a70def92..be8dbf482229 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -671,19 +671,20 @@ int dlm_new_user_lockspace(const char *name, const char *cluster, This is because there may be LKBs queued as ASTs that have been unlinked from their RSBs and are pending deletion once the AST has been delivered */ -static int lockspace_busy(struct dlm_ls *ls, int force) +static int lockspace_busy(struct dlm_ls *ls, int release_option) { struct dlm_lkb *lkb; unsigned long id; int rv = 0; read_lock_bh(&ls->ls_lkbxa_lock); - if (force == 0) { + if (release_option == DLM_RELEASE_NO_LOCKS) { xa_for_each(&ls->ls_lkbxa, id, lkb) { rv = 1; break; } - } else if (force == 1) { + } else if (release_option == DLM_RELEASE_UNUSED) { + /* TODO: handle this UNUSED option as NO_LOCKS in later patch */ xa_for_each(&ls->ls_lkbxa, id, lkb) { if (lkb->lkb_nodeid == 0 && lkb->lkb_grmode != DLM_LOCK_IV) { @@ -698,11 +699,11 @@ static int lockspace_busy(struct dlm_ls *ls, int force) return rv; } -static int release_lockspace(struct dlm_ls *ls, int force) +static int release_lockspace(struct dlm_ls *ls, int release_option) { int busy, rv; - busy = lockspace_busy(ls, force); + busy = lockspace_busy(ls, release_option); spin_lock_bh(&lslist_lock); if (ls->ls_create_count == 1) { @@ -730,7 +731,8 @@ static int release_lockspace(struct dlm_ls *ls, int force) dlm_device_deregister(ls); - if (force != 3 && dlm_user_daemon_available()) + if (release_option != DLM_RELEASE_NO_EVENT && + dlm_user_daemon_available()) do_uevent(ls, 0); dlm_recoverd_stop(ls); @@ -782,11 +784,7 @@ static int release_lockspace(struct dlm_ls *ls, int force) * lockspace must continue to function as usual, participating in recoveries, * until this returns. * - * Force has 4 possible values: - * 0 - don't destroy lockspace if it has any LKBs - * 1 - destroy lockspace if it has remote LKBs but not if it has local LKBs - * 2 - destroy lockspace regardless of LKBs - * 3 - destroy lockspace as part of a forced shutdown + * See DLM_RELEASE defines for release_option values and their meaning. */ int dlm_release_lockspace(void *lockspace, int force) diff --git a/fs/dlm/user.c b/fs/dlm/user.c index 5cb3896be826..51daf4acbe31 100644 --- a/fs/dlm/user.c +++ b/fs/dlm/user.c @@ -425,7 +425,7 @@ static int device_create_lockspace(struct dlm_lspace_params *params) dlm_put_lockspace(ls); if (error) - dlm_release_lockspace(lockspace, 0); + dlm_release_lockspace(lockspace, DLM_RELEASE_NO_LOCKS); else error = ls->ls_device.minor; @@ -436,7 +436,7 @@ static int device_remove_lockspace(struct dlm_lspace_params *params) { dlm_lockspace_t *lockspace; struct dlm_ls *ls; - int error, force = 0; + int error, force = DLM_RELEASE_NO_LOCKS; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -446,7 +446,7 @@ static int device_remove_lockspace(struct dlm_lspace_params *params) return -ENOENT; if (params->flags & DLM_USER_LSFLG_FORCEFREE) - force = 2; + force = DLM_RELEASE_NORMAL; lockspace = ls; dlm_put_lockspace(ls); diff --git a/fs/gfs2/lock_dlm.c b/fs/gfs2/lock_dlm.c index cee5d199d2d8..aac4dd6d0381 100644 --- a/fs/gfs2/lock_dlm.c +++ b/fs/gfs2/lock_dlm.c @@ -1400,7 +1400,7 @@ static int gdlm_mount(struct gfs2_sbd *sdp, const char *table) return 0; fail_release: - dlm_release_lockspace(ls->ls_dlm, 2); + dlm_release_lockspace(ls->ls_dlm, DLM_RELEASE_NORMAL); fail_free: free_recover_size(ls); fail: @@ -1437,7 +1437,7 @@ static void gdlm_unmount(struct gfs2_sbd *sdp) /* mounted_lock and control_lock will be purged in dlm recovery */ release: if (ls->ls_dlm) { - dlm_release_lockspace(ls->ls_dlm, 2); + dlm_release_lockspace(ls->ls_dlm, DLM_RELEASE_NORMAL); ls->ls_dlm = NULL; } diff --git a/fs/ocfs2/stack_user.c b/fs/ocfs2/stack_user.c index 0f045e45fa0c..765105f1ff8a 100644 --- a/fs/ocfs2/stack_user.c +++ b/fs/ocfs2/stack_user.c @@ -952,7 +952,7 @@ static const struct dlm_lockspace_ops ocfs2_ls_ops = { static int user_cluster_disconnect(struct ocfs2_cluster_connection *conn) { version_unlock(conn); - dlm_release_lockspace(conn->cc_lockspace, 2); + dlm_release_lockspace(conn->cc_lockspace, DLM_RELEASE_NORMAL); conn->cc_lockspace = NULL; ocfs2_live_connection_drop(conn->cc_private); conn->cc_private = NULL; diff --git a/include/linux/dlm.h b/include/linux/dlm.h index bacda9898f2b..cc7a36244893 100644 --- a/include/linux/dlm.h +++ b/include/linux/dlm.h @@ -87,13 +87,37 @@ int dlm_new_lockspace(const char *name, const char *cluster, const struct dlm_lockspace_ops *ops, void *ops_arg, int *ops_result, dlm_lockspace_t **lockspace); +/* + * dlm_release_lockspace() release_option values: + * + * DLM_RELEASE_NO_LOCKS returns -EBUSY if any locks (lkb's) + * exist in the local lockspace. + * + * DLM_RELEASE_UNUSED previous value that is no longer used. + * + * DLM_RELEASE_NORMAL releases the lockspace regardless of any + * locks managed in the local lockspace. + * + * DLM_RELEASE_NO_EVENT release the lockspace regardless of any + * locks managed in the local lockspace, and does not submit + * a leave event to the cluster manager, so other nodes will + * not be notified that the node should be removed from the + * list of lockspace members. + */ +#define DLM_RELEASE_NO_LOCKS 0 +#define DLM_RELEASE_UNUSED 1 +#define DLM_RELEASE_NORMAL 2 +#define DLM_RELEASE_NO_EVENT 3 + /* * dlm_release_lockspace * * Stop a lockspace. + * + * release_option: see DLM_RELEASE values above. */ -int dlm_release_lockspace(dlm_lockspace_t *lockspace, int force); +int dlm_release_lockspace(dlm_lockspace_t *lockspace, int release_option); /* * dlm_lock From 5665374c7246159dbca1a80a0b54ad27e3379bcb Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 23 Jul 2025 11:21:54 -0400 Subject: [PATCH 00430/11391] dlm: add new RELEASE_RECOVER uevent attribute for release_lockspace RELEASE_RECOVER=0|1 is passed to user space as part of the OFFLINE uevent for leaving a lockspace, and used by subsequent patches. RELEASE_RECOVER=1 tells user space that the release_lockspace/leave should be handled by the remaining lockspace members as if the leaving node had failed. Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/lockspace.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index be8dbf482229..6ff666a511c7 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -186,12 +186,17 @@ static struct kobj_type dlm_ktype = { static struct kset *dlm_kset; -static int do_uevent(struct dlm_ls *ls, int in) +static int do_uevent(struct dlm_ls *ls, int in, unsigned int release_recover) { - if (in) + char message[512] = {}; + char *envp[] = { message, NULL }; + + if (in) { kobject_uevent(&ls->ls_kobj, KOBJ_ONLINE); - else - kobject_uevent(&ls->ls_kobj, KOBJ_OFFLINE); + } else { + snprintf(message, 511, "RELEASE_RECOVER=%u", release_recover); + kobject_uevent_env(&ls->ls_kobj, KOBJ_OFFLINE, envp); + } log_rinfo(ls, "%s the lockspace group...", in ? "joining" : "leaving"); @@ -575,7 +580,7 @@ static int new_lockspace(const char *name, const char *cluster, current lockspace members are (via configfs) and then tells the lockspace to start running (via sysfs) in dlm_ls_start(). */ - error = do_uevent(ls, 1); + error = do_uevent(ls, 1, 0); if (error < 0) goto out_recoverd; @@ -592,7 +597,7 @@ static int new_lockspace(const char *name, const char *cluster, return 0; out_members: - do_uevent(ls, 0); + do_uevent(ls, 0, 0); dlm_clear_members(ls); kfree(ls->ls_node_array); out_recoverd: @@ -733,7 +738,7 @@ static int release_lockspace(struct dlm_ls *ls, int release_option) if (release_option != DLM_RELEASE_NO_EVENT && dlm_user_daemon_available()) - do_uevent(ls, 0); + do_uevent(ls, 0, 0); dlm_recoverd_stop(ls); From de7b4869b4ecf5790b0e7875c5522d43d7a61d79 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 23 Jul 2025 11:21:55 -0400 Subject: [PATCH 00431/11391] dlm: add new configfs entry release_recover for lockspace members A new configfs entry is added for a lockspace member: /config/dlm//spaces//nodes//release_recover release_recover can be set to 1 by userspace (dlm_controld process) prior to removing the lockspace member (rmdir of the ). This tells the kernel to handle the removed member as if it had failed, i.e. recovery steps for a failed node should be perfomed, as opposed to the recovery steps for a node doing a controlled leave. Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/config.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++-- fs/dlm/config.h | 2 ++ fs/dlm/member.c | 7 ++++-- 3 files changed, 69 insertions(+), 4 deletions(-) diff --git a/fs/dlm/config.c b/fs/dlm/config.c index a23fd524a6ee..a0d75b5c83c6 100644 --- a/fs/dlm/config.c +++ b/fs/dlm/config.c @@ -26,6 +26,7 @@ /* * /config/dlm//spaces//nodes//nodeid (refers to ) * /config/dlm//spaces//nodes//weight + * /config/dlm//spaces//nodes//release_recover * /config/dlm//comms//nodeid (refers to ) * /config/dlm//comms//local * /config/dlm//comms//addr (write only) @@ -267,6 +268,7 @@ enum { enum { NODE_ATTR_NODEID = 0, NODE_ATTR_WEIGHT, + NODE_ATTR_RELEASE_RECOVER, }; struct dlm_clusters { @@ -280,6 +282,8 @@ struct dlm_spaces { struct dlm_space { struct config_group group; struct list_head members; + struct list_head members_gone; + int members_gone_count; struct mutex members_lock; int members_count; struct dlm_nodes *nds; @@ -310,6 +314,14 @@ struct dlm_node { int weight; int new; int comm_seq; /* copy of cm->seq when nd->nodeid is set */ + unsigned int release_recover; +}; + +struct dlm_member_gone { + int nodeid; + unsigned int release_recover; + + struct list_head list; /* space->members_gone */ }; static struct configfs_group_operations clusters_ops = { @@ -480,6 +492,7 @@ static struct config_group *make_space(struct config_group *g, const char *name) configfs_add_default_group(&nds->ns_group, &sp->group); INIT_LIST_HEAD(&sp->members); + INIT_LIST_HEAD(&sp->members_gone); mutex_init(&sp->members_lock); sp->members_count = 0; sp->nds = nds; @@ -587,10 +600,20 @@ static void drop_node(struct config_group *g, struct config_item *i) { struct dlm_space *sp = config_item_to_space(g->cg_item.ci_parent); struct dlm_node *nd = config_item_to_node(i); + struct dlm_member_gone *mb_gone; + + mb_gone = kzalloc(sizeof(*mb_gone), GFP_KERNEL); + if (!mb_gone) + return; mutex_lock(&sp->members_lock); list_del(&nd->list); sp->members_count--; + + mb_gone->nodeid = nd->nodeid; + mb_gone->release_recover = nd->release_recover; + list_add(&mb_gone->list, &sp->members_gone); + sp->members_gone_count++; mutex_unlock(&sp->members_lock); config_item_put(i); @@ -815,12 +838,34 @@ static ssize_t node_weight_store(struct config_item *item, const char *buf, return len; } +static ssize_t node_release_recover_show(struct config_item *item, char *buf) +{ + struct dlm_node *n = config_item_to_node(item); + + return sprintf(buf, "%u\n", n->release_recover); +} + +static ssize_t node_release_recover_store(struct config_item *item, + const char *buf, size_t len) +{ + struct dlm_node *n = config_item_to_node(item); + int rc; + + rc = kstrtouint(buf, 0, &n->release_recover); + if (rc) + return rc; + + return len; +} + CONFIGFS_ATTR(node_, nodeid); CONFIGFS_ATTR(node_, weight); +CONFIGFS_ATTR(node_, release_recover); static struct configfs_attribute *node_attrs[] = { [NODE_ATTR_NODEID] = &node_attr_nodeid, [NODE_ATTR_WEIGHT] = &node_attr_weight, + [NODE_ATTR_RELEASE_RECOVER] = &node_attr_release_recover, NULL, }; @@ -882,9 +927,10 @@ static void put_comm(struct dlm_comm *cm) int dlm_config_nodes(char *lsname, struct dlm_config_node **nodes_out, int *count_out) { + struct dlm_member_gone *mb_gone, *mb_safe; + struct dlm_config_node *nodes, *node; struct dlm_space *sp; struct dlm_node *nd; - struct dlm_config_node *nodes, *node; int rv, count; sp = get_space(lsname); @@ -898,7 +944,7 @@ int dlm_config_nodes(char *lsname, struct dlm_config_node **nodes_out, goto out; } - count = sp->members_count; + count = sp->members_count + sp->members_gone_count; nodes = kcalloc(count, sizeof(struct dlm_config_node), GFP_NOFS); if (!nodes) { @@ -917,6 +963,20 @@ int dlm_config_nodes(char *lsname, struct dlm_config_node **nodes_out, nd->new = 0; } + /* we delay the remove on nodes until here as configfs does + * not support addtional attributes for rmdir(). + */ + list_for_each_entry_safe(mb_gone, mb_safe, &sp->members_gone, list) { + node->nodeid = mb_gone->nodeid; + node->release_recover = mb_gone->release_recover; + node->gone = true; + node++; + + list_del(&mb_gone->list); + sp->members_gone_count--; + kfree(mb_gone); + } + *count_out = count; *nodes_out = nodes; rv = 0; diff --git a/fs/dlm/config.h b/fs/dlm/config.h index 13a3d0b26194..4ebd45f75276 100644 --- a/fs/dlm/config.h +++ b/fs/dlm/config.h @@ -17,8 +17,10 @@ struct dlm_config_node { int nodeid; int weight; + bool gone; int new; uint32_t comm_seq; + unsigned int release_recover; }; extern const struct rhashtable_params dlm_rhash_rsb_params; diff --git a/fs/dlm/member.c b/fs/dlm/member.c index b0864c93230f..152d2cb16f59 100644 --- a/fs/dlm/member.c +++ b/fs/dlm/member.c @@ -569,10 +569,10 @@ int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out) list_for_each_entry_safe(memb, safe, &ls->ls_nodes, list) { node = find_config_node(rv, memb->nodeid); - if (node && !node->new) + if (node && !node->new && !node->gone) continue; - if (!node) { + if (node->gone) { log_rinfo(ls, "remove member %d", memb->nodeid); } else { /* removed and re-added */ @@ -591,6 +591,9 @@ int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out) for (i = 0; i < rv->nodes_count; i++) { node = &rv->nodes[i]; + if (node->gone) + continue; + if (dlm_is_member(ls, node->nodeid)) continue; error = dlm_add_member(ls, node); From 6f4f4ca5caf73de5e86329547d4527b3e0c08488 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 23 Jul 2025 11:21:56 -0400 Subject: [PATCH 00432/11391] dlm: add new flag DLM_RELEASE_RECOVER for dlm_lockspace_release When dlm_lockspace_release() is passed DLM_RELEASE_RECOVER, it tells the dlm to handle the release/leave as if the node had failed, i.e. perform recovery steps for a failed node, like recover_slot(). When DLM_RELEASE_RECOVER is set: - dlm_release_lockspace() includes RELEASE_RECOVER=1 in the OFFLINE uevent sent to userspace. - userspace/dlm_controld sends a message to all lockspace members indicating that the subsequent node removal should be handled as if the node had failed. - when dlm_controld on all nodes receives the new message, it sets the release_recover configfs entry to 1 for the node. - when the dlm/kernel next performs recovery and removes the node, it will see that release_recover has been set, and will perform recovery steps for the node as if it had failed, e.g. the recover_slot() callback is called to notify the fs. Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/lockspace.c | 2 +- fs/dlm/member.c | 14 ++++++++++---- include/linux/dlm.h | 5 +++++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index 6ff666a511c7..d986b7ef153d 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -738,7 +738,7 @@ static int release_lockspace(struct dlm_ls *ls, int release_option) if (release_option != DLM_RELEASE_NO_EVENT && dlm_user_daemon_available()) - do_uevent(ls, 0, 0); + do_uevent(ls, 0, (release_option == DLM_RELEASE_RECOVER)); dlm_recoverd_stop(ls); diff --git a/fs/dlm/member.c b/fs/dlm/member.c index 152d2cb16f59..356337102015 100644 --- a/fs/dlm/member.c +++ b/fs/dlm/member.c @@ -478,7 +478,8 @@ static void dlm_lsop_recover_prep(struct dlm_ls *ls) ls->ls_ops->recover_prep(ls->ls_ops_arg); } -static void dlm_lsop_recover_slot(struct dlm_ls *ls, struct dlm_member *memb) +static void dlm_lsop_recover_slot(struct dlm_ls *ls, struct dlm_member *memb, + unsigned int release_recover) { struct dlm_slot slot; uint32_t seq; @@ -495,7 +496,7 @@ static void dlm_lsop_recover_slot(struct dlm_ls *ls, struct dlm_member *memb) error = dlm_comm_seq(memb->nodeid, &seq, false); - if (!error && seq == memb->comm_seq) + if (!release_recover && !error && seq == memb->comm_seq) return; slot.nodeid = memb->nodeid; @@ -552,6 +553,7 @@ int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out) struct dlm_member *memb, *safe; struct dlm_config_node *node; int i, error, neg = 0, low = -1; + unsigned int release_recover; /* previously removed members that we've not finished removing need to * count as a negative change so the "neg" recovery steps will happen @@ -572,8 +574,12 @@ int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out) if (node && !node->new && !node->gone) continue; + release_recover = 0; + if (node->gone) { - log_rinfo(ls, "remove member %d", memb->nodeid); + release_recover = node->release_recover; + log_rinfo(ls, "remove member %d%s", memb->nodeid, + release_recover ? " (release_recover)" : ""); } else { /* removed and re-added */ log_rinfo(ls, "remove member %d comm_seq %u %u", @@ -584,7 +590,7 @@ int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out) list_move(&memb->list, &ls->ls_nodes_gone); remove_remote_member(memb->nodeid); ls->ls_num_nodes--; - dlm_lsop_recover_slot(ls, memb); + dlm_lsop_recover_slot(ls, memb, release_recover); } /* add new members to ls_nodes */ diff --git a/include/linux/dlm.h b/include/linux/dlm.h index cc7a36244893..108eb953eb18 100644 --- a/include/linux/dlm.h +++ b/include/linux/dlm.h @@ -103,11 +103,16 @@ int dlm_new_lockspace(const char *name, const char *cluster, * a leave event to the cluster manager, so other nodes will * not be notified that the node should be removed from the * list of lockspace members. + * + * DLM_RELEASE_RECOVER like DLM_RELEASE_NORMAL, but the remaining + * nodes will handle the removal of the node as if the node + * had failed, e.g. the recover_slot() callback would be used. */ #define DLM_RELEASE_NO_LOCKS 0 #define DLM_RELEASE_UNUSED 1 #define DLM_RELEASE_NORMAL 2 #define DLM_RELEASE_NO_EVENT 3 +#define DLM_RELEASE_RECOVER 4 /* * dlm_release_lockspace From 8b63fee9f62361a7d96394611ba05734ec21e2eb Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Fri, 25 Jul 2025 18:11:00 +0800 Subject: [PATCH 00433/11391] 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 77abf70ee126d40dba9ada0a4ccb4c7743f6a3e6 Mon Sep 17 00:00:00 2001 From: Sricharan Ramabadhran Date: Mon, 11 Aug 2025 14:39:54 +0530 Subject: [PATCH 00434/11391] arm64: dts: qcom: ipq5424: Enable cpufreq Add the qfprom, cpu clocks, A53 PLL and cpu-opp-table required for CPU clock scaling. Signed-off-by: Sricharan Ramabadhran [ Added interconnect related entries, fix dt-bindings errors ] Reviewed-by: Konrad Dybcio Signed-off-by: Varadarajan Narayanan Link: https://lore.kernel.org/r/20250811090954.2854440-5-quic_varada@quicinc.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/ipq5424.dtsi | 69 +++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/ipq5424.dtsi b/arch/arm64/boot/dts/qcom/ipq5424.dtsi index bd891e39f33e..bbb539dbdf5c 100644 --- a/arch/arm64/boot/dts/qcom/ipq5424.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq5424.dtsi @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -52,6 +53,11 @@ cpu0: cpu@0 { reg = <0x0>; enable-method = "psci"; next-level-cache = <&l2_0>; + clocks = <&apss_clk APSS_SILVER_CORE_CLK>; + clock-names = "cpu"; + operating-points-v2 = <&cpu_opp_table>; + interconnects = <&apss_clk MASTER_CPU &apss_clk SLAVE_L3>; + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; @@ -72,6 +78,10 @@ cpu1: cpu@100 { enable-method = "psci"; reg = <0x100>; next-level-cache = <&l2_100>; + clocks = <&apss_clk APSS_SILVER_CORE_CLK>; + clock-names = "cpu"; + operating-points-v2 = <&cpu_opp_table>; + interconnects = <&apss_clk MASTER_CPU &apss_clk SLAVE_L3>; l2_100: l2-cache { compatible = "cache"; @@ -87,6 +97,10 @@ cpu2: cpu@200 { enable-method = "psci"; reg = <0x200>; next-level-cache = <&l2_200>; + clocks = <&apss_clk APSS_SILVER_CORE_CLK>; + clock-names = "cpu"; + operating-points-v2 = <&cpu_opp_table>; + interconnects = <&apss_clk MASTER_CPU &apss_clk SLAVE_L3>; l2_200: l2-cache { compatible = "cache"; @@ -102,6 +116,10 @@ cpu3: cpu@300 { enable-method = "psci"; reg = <0x300>; next-level-cache = <&l2_300>; + clocks = <&apss_clk APSS_SILVER_CORE_CLK>; + clock-names = "cpu"; + operating-points-v2 = <&cpu_opp_table>; + interconnects = <&apss_clk MASTER_CPU &apss_clk SLAVE_L3>; l2_300: l2-cache { compatible = "cache"; @@ -119,6 +137,36 @@ scm { }; }; + cpu_opp_table: opp-table-cpu { + compatible = "operating-points-v2-kryo-cpu"; + opp-shared; + nvmem-cells = <&cpu_speed_bin>; + + opp-816000000 { + opp-hz = /bits/ 64 <816000000>; + opp-microvolt = <850000>; + opp-supported-hw = <0x3>; + clock-latency-ns = <200000>; + opp-peak-kBps = <816000>; + }; + + opp-1416000000 { + opp-hz = /bits/ 64 <1416000000>; + opp-microvolt = <850000>; + opp-supported-hw = <0x3>; + clock-latency-ns = <200000>; + opp-peak-kBps = <984000>; + }; + + opp-1800000000 { + opp-hz = /bits/ 64 <1800000000>; + opp-microvolt = <1000000>; + opp-supported-hw = <0x1>; + clock-latency-ns = <200000>; + opp-peak-kBps = <1272000>; + }; + }; + memory@80000000 { device_type = "memory"; /* We expect the bootloader to fill in the size */ @@ -388,6 +436,18 @@ system-cache-controller@800000 { interrupts = ; }; + qfprom@a6000 { + compatible = "qcom,ipq5424-qfprom", "qcom,qfprom"; + reg = <0x0 0x000a6000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + cpu_speed_bin: cpu-speed-bin@234 { + reg = <0x234 0x1>; + bits = <0 8>; + }; + }; + tlmm: pinctrl@1000000 { compatible = "qcom,ipq5424-tlmm"; reg = <0 0x01000000 0 0x300000>; @@ -739,6 +799,15 @@ frame@f42d000 { }; }; + apss_clk: clock-controller@fa80000 { + compatible = "qcom,ipq5424-apss-clk"; + reg = <0x0 0x0fa80000 0x0 0x20000>; + clocks = <&xo_board>, + <&gcc GPLL0>; + #clock-cells = <1>; + #interconnect-cells = <1>; + }; + pcie3: pcie@40000000 { compatible = "qcom,pcie-ipq5424", "qcom,pcie-ipq9574"; reg = <0x0 0x40000000 0x0 0xf1c>, From f20e70a341dd67ac4aca23f93b6acdca6779e69d Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Thu, 7 Aug 2025 22:05:45 +0800 Subject: [PATCH 00435/11391] selinux: 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 Acked-by: Stephen Smalley [PM: fixed horizontal spacing / alignment, line wraps] Signed-off-by: Paul Moore --- security/selinux/avc.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 4b4837a20225..430b0e23ee00 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -292,27 +292,26 @@ static struct avc_xperms_decision_node struct avc_xperms_decision_node *xpd_node; struct extended_perms_decision *xpd; - xpd_node = kmem_cache_zalloc(avc_xperms_decision_cachep, - GFP_NOWAIT | __GFP_NOWARN); + xpd_node = kmem_cache_zalloc(avc_xperms_decision_cachep, GFP_NOWAIT); if (!xpd_node) return NULL; xpd = &xpd_node->xpd; if (which & XPERMS_ALLOWED) { xpd->allowed = kmem_cache_zalloc(avc_xperms_data_cachep, - GFP_NOWAIT | __GFP_NOWARN); + GFP_NOWAIT); if (!xpd->allowed) goto error; } if (which & XPERMS_AUDITALLOW) { xpd->auditallow = kmem_cache_zalloc(avc_xperms_data_cachep, - GFP_NOWAIT | __GFP_NOWARN); + GFP_NOWAIT); if (!xpd->auditallow) goto error; } if (which & XPERMS_DONTAUDIT) { xpd->dontaudit = kmem_cache_zalloc(avc_xperms_data_cachep, - GFP_NOWAIT | __GFP_NOWARN); + GFP_NOWAIT); if (!xpd->dontaudit) goto error; } @@ -340,7 +339,7 @@ static struct avc_xperms_node *avc_xperms_alloc(void) { struct avc_xperms_node *xp_node; - xp_node = kmem_cache_zalloc(avc_xperms_cachep, GFP_NOWAIT | __GFP_NOWARN); + xp_node = kmem_cache_zalloc(avc_xperms_cachep, GFP_NOWAIT); if (!xp_node) return xp_node; INIT_LIST_HEAD(&xp_node->xpd_head); @@ -495,7 +494,7 @@ static struct avc_node *avc_alloc_node(void) { struct avc_node *node; - node = kmem_cache_zalloc(avc_node_cachep, GFP_NOWAIT | __GFP_NOWARN); + node = kmem_cache_zalloc(avc_node_cachep, GFP_NOWAIT); if (!node) goto out; From 1f54d5e5cd2a03cb6dd8326db576f8763f9b6785 Mon Sep 17 00:00:00 2001 From: Daniel Almeida Date: Mon, 11 Aug 2025 13:03:39 -0300 Subject: [PATCH 00436/11391] rust: irq: add irq module Add the IRQ module. Future patches will then introduce support for IRQ registrations and handlers. Reviewed-by: Alice Ryhl Tested-by: Joel Fernandes Tested-by: Dirk Behme Signed-off-by: Daniel Almeida Link: https://lore.kernel.org/r/20250811-topics-tyr-request_irq2-v9-1-0485dcd9bcbf@collabora.com Signed-off-by: Danilo Krummrich --- rust/kernel/irq.rs | 11 +++++++++++ rust/kernel/lib.rs | 1 + 2 files changed, 12 insertions(+) create mode 100644 rust/kernel/irq.rs diff --git a/rust/kernel/irq.rs b/rust/kernel/irq.rs new file mode 100644 index 000000000000..fae7b15effc8 --- /dev/null +++ b/rust/kernel/irq.rs @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! IRQ abstractions. +//! +//! An IRQ is an interrupt request from a device. It is used to get the CPU's +//! attention so it can service a hardware event in a timely manner. +//! +//! The current abstractions handle IRQ requests and handlers, i.e.: it allows +//! drivers to register a handler for a given IRQ line. +//! +//! C header: [`include/linux/device.h`](srctree/include/linux/interrupt.h) diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index ed53169e795c..f8db761c5c95 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -92,6 +92,7 @@ pub mod init; pub mod io; pub mod ioctl; +pub mod irq; pub mod jump_label; #[cfg(CONFIG_KUNIT)] pub mod kunit; From 746680ec6696585e30db3e18c93a63df9cbec39c Mon Sep 17 00:00:00 2001 From: Daniel Almeida Date: Mon, 11 Aug 2025 13:03:40 -0300 Subject: [PATCH 00437/11391] rust: irq: add flags module Manipulating IRQ flags (i.e.: IRQF_*) will soon be necessary, specially to register IRQ handlers through bindings::request_irq(). Add a kernel::irq::Flags for that purpose. Reviewed-by: Alice Ryhl Tested-by: Joel Fernandes Tested-by: Dirk Behme Signed-off-by: Daniel Almeida Link: https://lore.kernel.org/r/20250811-topics-tyr-request_irq2-v9-2-0485dcd9bcbf@collabora.com [ Use expect(dead_code) for into_inner(), fix broken intra-doc link and typo. - Danilo ] Signed-off-by: Danilo Krummrich --- rust/kernel/irq.rs | 5 ++ rust/kernel/irq/flags.rs | 125 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 rust/kernel/irq/flags.rs diff --git a/rust/kernel/irq.rs b/rust/kernel/irq.rs index fae7b15effc8..068df2fea31d 100644 --- a/rust/kernel/irq.rs +++ b/rust/kernel/irq.rs @@ -9,3 +9,8 @@ //! drivers to register a handler for a given IRQ line. //! //! C header: [`include/linux/device.h`](srctree/include/linux/interrupt.h) + +/// Flags to be used when registering IRQ handlers. +mod flags; + +pub use flags::Flags; diff --git a/rust/kernel/irq/flags.rs b/rust/kernel/irq/flags.rs new file mode 100644 index 000000000000..d769d68e8edc --- /dev/null +++ b/rust/kernel/irq/flags.rs @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: Copyright 2025 Collabora ltd. + +use crate::bindings; +use crate::prelude::*; + +/// Flags to be used when registering IRQ handlers. +/// +/// Flags can be used to request specific behaviors when registering an IRQ +/// handler, and can be combined using the `|`, `&`, and `!` operators to +/// further control the system's behavior. +/// +/// A common use case is to register a shared interrupt, as sharing the line +/// between devices is increasingly common in modern systems and is even +/// required for some buses. This requires setting [`Flags::SHARED`] when +/// requesting the interrupt. Other use cases include setting the trigger type +/// through `Flags::TRIGGER_*`, which determines when the interrupt fires, or +/// controlling whether the interrupt is masked after the handler runs by using +/// [`Flags::ONESHOT`]. +/// +/// If an invalid combination of flags is provided, the system will refuse to +/// register the handler, and lower layers will enforce certain flags when +/// necessary. This means, for example, that all the +/// `crate::irq::Registration` for a shared interrupt have to agree on +/// [`Flags::SHARED`] and on the same trigger type, if set. +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct Flags(c_ulong); + +impl Flags { + /// Use the interrupt line as already configured. + pub const TRIGGER_NONE: Flags = Flags::new(bindings::IRQF_TRIGGER_NONE); + + /// The interrupt is triggered when the signal goes from low to high. + pub const TRIGGER_RISING: Flags = Flags::new(bindings::IRQF_TRIGGER_RISING); + + /// The interrupt is triggered when the signal goes from high to low. + pub const TRIGGER_FALLING: Flags = Flags::new(bindings::IRQF_TRIGGER_FALLING); + + /// The interrupt is triggered while the signal is held high. + pub const TRIGGER_HIGH: Flags = Flags::new(bindings::IRQF_TRIGGER_HIGH); + + /// The interrupt is triggered while the signal is held low. + pub const TRIGGER_LOW: Flags = Flags::new(bindings::IRQF_TRIGGER_LOW); + + /// Allow sharing the IRQ among several devices. + pub const SHARED: Flags = Flags::new(bindings::IRQF_SHARED); + + /// Set by callers when they expect sharing mismatches to occur. + pub const PROBE_SHARED: Flags = Flags::new(bindings::IRQF_PROBE_SHARED); + + /// Flag to mark this interrupt as timer interrupt. + pub const TIMER: Flags = Flags::new(bindings::IRQF_TIMER); + + /// Interrupt is per CPU. + pub const PERCPU: Flags = Flags::new(bindings::IRQF_PERCPU); + + /// Flag to exclude this interrupt from irq balancing. + pub const NOBALANCING: Flags = Flags::new(bindings::IRQF_NOBALANCING); + + /// Interrupt is used for polling (only the interrupt that is registered + /// first in a shared interrupt is considered for performance reasons). + pub const IRQPOLL: Flags = Flags::new(bindings::IRQF_IRQPOLL); + + /// Interrupt is not re-enabled after the hardirq handler finished. Used by + /// threaded interrupts which need to keep the irq line disabled until the + /// threaded handler has been run. + pub const ONESHOT: Flags = Flags::new(bindings::IRQF_ONESHOT); + + /// Do not disable this IRQ during suspend. Does not guarantee that this + /// interrupt will wake the system from a suspended state. + pub const NO_SUSPEND: Flags = Flags::new(bindings::IRQF_NO_SUSPEND); + + /// Force enable it on resume even if [`Flags::NO_SUSPEND`] is set. + pub const FORCE_RESUME: Flags = Flags::new(bindings::IRQF_FORCE_RESUME); + + /// Interrupt cannot be threaded. + pub const NO_THREAD: Flags = Flags::new(bindings::IRQF_NO_THREAD); + + /// Resume IRQ early during syscore instead of at device resume time. + pub const EARLY_RESUME: Flags = Flags::new(bindings::IRQF_EARLY_RESUME); + + /// If the IRQ is shared with a [`Flags::NO_SUSPEND`] user, execute this + /// interrupt handler after suspending interrupts. For system wakeup devices + /// users need to implement wakeup detection in their interrupt handlers. + pub const COND_SUSPEND: Flags = Flags::new(bindings::IRQF_COND_SUSPEND); + + /// Don't enable IRQ or NMI automatically when users request it. Users will + /// enable it explicitly by `enable_irq` or `enable_nmi` later. + pub const NO_AUTOEN: Flags = Flags::new(bindings::IRQF_NO_AUTOEN); + + /// Exclude from runnaway detection for IPI and similar handlers, depends on + /// `PERCPU`. + pub const NO_DEBUG: Flags = Flags::new(bindings::IRQF_NO_DEBUG); + + #[expect(dead_code)] + pub(crate) fn into_inner(self) -> c_ulong { + self.0 + } + + const fn new(value: u32) -> Self { + build_assert!(value as u64 <= c_ulong::MAX as u64); + Self(value as c_ulong) + } +} + +impl core::ops::BitOr for Flags { + type Output = Self; + fn bitor(self, rhs: Self) -> Self::Output { + Self(self.0 | rhs.0) + } +} + +impl core::ops::BitAnd for Flags { + type Output = Self; + fn bitand(self, rhs: Self) -> Self::Output { + Self(self.0 & rhs.0) + } +} + +impl core::ops::Not for Flags { + type Output = Self; + fn not(self) -> Self::Output { + Self(!self.0) + } +} From 0851d34a8cc3a0a43acd79a5c4980d45c6471aab Mon Sep 17 00:00:00 2001 From: Daniel Almeida Date: Mon, 11 Aug 2025 13:03:41 -0300 Subject: [PATCH 00438/11391] rust: irq: add support for non-threaded IRQs and handlers This patch adds support for non-threaded IRQs and handlers through irq::Registration and the irq::Handler trait. Registering an irq is dependent upon having a IrqRequest that was previously allocated by a given device. This will be introduced in subsequent patches. Tested-by: Joel Fernandes Tested-by: Dirk Behme Reviewed-by: Alice Ryhl Signed-off-by: Daniel Almeida Link: https://lore.kernel.org/r/20250811-topics-tyr-request_irq2-v9-3-0485dcd9bcbf@collabora.com [ Remove expect(dead_code) from Flags::into_inner(), add expect(dead_code) to IrqRequest::new(), fix intra-doc links. - Danilo ] Signed-off-by: Danilo Krummrich --- rust/bindings/bindings_helper.h | 1 + rust/helpers/helpers.c | 1 + rust/helpers/irq.c | 9 ++ rust/kernel/irq.rs | 5 + rust/kernel/irq/flags.rs | 3 +- rust/kernel/irq/request.rs | 265 ++++++++++++++++++++++++++++++++ 6 files changed, 282 insertions(+), 2 deletions(-) create mode 100644 rust/helpers/irq.c create mode 100644 rust/kernel/irq/request.rs diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 84d60635e8a9..69a975da829f 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index 7cf7fe95e41d..44b2005d5014 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -22,6 +22,7 @@ #include "dma.c" #include "drm.c" #include "err.c" +#include "irq.c" #include "fs.c" #include "io.c" #include "jump_label.c" diff --git a/rust/helpers/irq.c b/rust/helpers/irq.c new file mode 100644 index 000000000000..1faca428e2c0 --- /dev/null +++ b/rust/helpers/irq.c @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +int rust_helper_request_irq(unsigned int irq, irq_handler_t handler, + unsigned long flags, const char *name, void *dev) +{ + return request_irq(irq, handler, flags, name, dev); +} diff --git a/rust/kernel/irq.rs b/rust/kernel/irq.rs index 068df2fea31d..c1019bc36ad1 100644 --- a/rust/kernel/irq.rs +++ b/rust/kernel/irq.rs @@ -13,4 +13,9 @@ /// Flags to be used when registering IRQ handlers. mod flags; +/// IRQ allocation and handling. +mod request; + pub use flags::Flags; + +pub use request::{Handler, IrqRequest, IrqReturn, Registration}; diff --git a/rust/kernel/irq/flags.rs b/rust/kernel/irq/flags.rs index d769d68e8edc..adfde96ec47c 100644 --- a/rust/kernel/irq/flags.rs +++ b/rust/kernel/irq/flags.rs @@ -21,7 +21,7 @@ /// If an invalid combination of flags is provided, the system will refuse to /// register the handler, and lower layers will enforce certain flags when /// necessary. This means, for example, that all the -/// `crate::irq::Registration` for a shared interrupt have to agree on +/// [`crate::irq::Registration`] for a shared interrupt have to agree on /// [`Flags::SHARED`] and on the same trigger type, if set. #[derive(Clone, Copy, PartialEq, Eq)] pub struct Flags(c_ulong); @@ -92,7 +92,6 @@ impl Flags { /// `PERCPU`. pub const NO_DEBUG: Flags = Flags::new(bindings::IRQF_NO_DEBUG); - #[expect(dead_code)] pub(crate) fn into_inner(self) -> c_ulong { self.0 } diff --git a/rust/kernel/irq/request.rs b/rust/kernel/irq/request.rs new file mode 100644 index 000000000000..c585811cfdfb --- /dev/null +++ b/rust/kernel/irq/request.rs @@ -0,0 +1,265 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: Copyright 2025 Collabora ltd. + +//! This module provides types like [`Registration`] which allow users to +//! register handlers for a given IRQ line. + +use core::marker::PhantomPinned; + +use crate::alloc::Allocator; +use crate::device::{Bound, Device}; +use crate::devres::Devres; +use crate::error::to_result; +use crate::irq::flags::Flags; +use crate::prelude::*; +use crate::str::CStr; +use crate::sync::Arc; + +/// The value that can be returned from a [`Handler`] or a `ThreadedHandler`. +#[repr(u32)] +pub enum IrqReturn { + /// The interrupt was not from this device or was not handled. + None = bindings::irqreturn_IRQ_NONE, + + /// The interrupt was handled by this device. + Handled = bindings::irqreturn_IRQ_HANDLED, +} + +/// Callbacks for an IRQ handler. +pub trait Handler: Sync { + /// The hard IRQ handler. + /// + /// This is executed in interrupt context, hence all corresponding + /// limitations do apply. + /// + /// All work that does not necessarily need to be executed from + /// interrupt context, should be deferred to a threaded handler. + /// See also `ThreadedRegistration`. + fn handle(&self) -> IrqReturn; +} + +impl Handler for Arc { + fn handle(&self) -> IrqReturn { + T::handle(self) + } +} + +impl Handler for Box { + fn handle(&self) -> IrqReturn { + T::handle(self) + } +} + +/// # Invariants +/// +/// - `self.irq` is the same as the one passed to `request_{threaded}_irq`. +/// - `cookie` was passed to `request_{threaded}_irq` as the cookie. It is guaranteed to be unique +/// by the type system, since each call to `new` will return a different instance of +/// `Registration`. +#[pin_data(PinnedDrop)] +struct RegistrationInner { + irq: u32, + cookie: *mut c_void, +} + +impl RegistrationInner { + fn synchronize(&self) { + // SAFETY: safe as per the invariants of `RegistrationInner` + unsafe { bindings::synchronize_irq(self.irq) }; + } +} + +#[pinned_drop] +impl PinnedDrop for RegistrationInner { + fn drop(self: Pin<&mut Self>) { + // SAFETY: + // + // Safe as per the invariants of `RegistrationInner` and: + // + // - The containing struct is `!Unpin` and was initialized using + // pin-init, so it occupied the same memory location for the entirety of + // its lifetime. + // + // Notice that this will block until all handlers finish executing, + // i.e.: at no point will &self be invalid while the handler is running. + unsafe { bindings::free_irq(self.irq, self.cookie) }; + } +} + +// SAFETY: We only use `inner` on drop, which called at most once with no +// concurrent access. +unsafe impl Sync for RegistrationInner {} + +// SAFETY: It is safe to send `RegistrationInner` across threads. +unsafe impl Send for RegistrationInner {} + +/// A request for an IRQ line for a given device. +/// +/// # Invariants +/// +/// - `ìrq` is the number of an interrupt source of `dev`. +/// - `irq` has not been registered yet. +pub struct IrqRequest<'a> { + dev: &'a Device, + irq: u32, +} + +impl<'a> IrqRequest<'a> { + /// Creates a new IRQ request for the given device and IRQ number. + /// + /// # Safety + /// + /// - `irq` should be a valid IRQ number for `dev`. + #[expect(dead_code)] + pub(crate) unsafe fn new(dev: &'a Device, irq: u32) -> Self { + // INVARIANT: `irq` is a valid IRQ number for `dev`. + IrqRequest { dev, irq } + } + + /// Returns the IRQ number of an [`IrqRequest`]. + pub fn irq(&self) -> u32 { + self.irq + } +} + +/// A registration of an IRQ handler for a given IRQ line. +/// +/// # Examples +/// +/// The following is an example of using `Registration`. It uses a +/// [`Completion`] to coordinate between the IRQ +/// handler and process context. [`Completion`] uses interior mutability, so the +/// handler can signal with [`Completion::complete_all()`] and the process +/// context can wait with [`Completion::wait_for_completion()`] even though +/// there is no way to get a mutable reference to the any of the fields in +/// `Data`. +/// +/// [`Completion`]: kernel::sync::Completion +/// [`Completion::complete_all()`]: kernel::sync::Completion::complete_all +/// [`Completion::wait_for_completion()`]: kernel::sync::Completion::wait_for_completion +/// +/// ``` +/// use kernel::c_str; +/// use kernel::device::Bound; +/// use kernel::irq::{self, Flags, IrqRequest, IrqReturn, Registration}; +/// use kernel::prelude::*; +/// use kernel::sync::{Arc, Completion}; +/// +/// // Data shared between process and IRQ context. +/// #[pin_data] +/// struct Data { +/// #[pin] +/// completion: Completion, +/// } +/// +/// impl irq::Handler for Data { +/// // Executed in IRQ context. +/// fn handle(&self) -> IrqReturn { +/// self.completion.complete_all(); +/// IrqReturn::Handled +/// } +/// } +/// +/// // Registers an IRQ handler for the given IrqRequest. +/// // +/// // This runs in process context and assumes `request` was previously acquired from a device. +/// fn register_irq( +/// handler: impl PinInit, +/// request: IrqRequest<'_>, +/// ) -> Result>> { +/// let registration = Registration::new(request, Flags::SHARED, c_str!("my_device"), handler); +/// +/// let registration = Arc::pin_init(registration, GFP_KERNEL)?; +/// +/// registration.handler().completion.wait_for_completion(); +/// +/// Ok(registration) +/// } +/// # Ok::<(), Error>(()) +/// ``` +/// +/// # Invariants +/// +/// * We own an irq handler using `&self.handler` as its private data. +#[pin_data] +pub struct Registration { + #[pin] + inner: Devres, + + #[pin] + handler: T, + + /// Pinned because we need address stability so that we can pass a pointer + /// to the callback. + #[pin] + _pin: PhantomPinned, +} + +impl Registration { + /// Registers the IRQ handler with the system for the given IRQ number. + pub fn new<'a>( + request: IrqRequest<'a>, + flags: Flags, + name: &'static CStr, + handler: impl PinInit + 'a, + ) -> impl PinInit + 'a { + try_pin_init!(&this in Self { + handler <- handler, + inner <- Devres::new( + request.dev, + try_pin_init!(RegistrationInner { + // SAFETY: `this` is a valid pointer to the `Registration` instance + cookie: unsafe { &raw mut (*this.as_ptr()).handler }.cast(), + irq: { + // SAFETY: + // - The callbacks are valid for use with request_irq. + // - If this succeeds, the slot is guaranteed to be valid until the + // destructor of Self runs, which will deregister the callbacks + // before the memory location becomes invalid. + to_result(unsafe { + bindings::request_irq( + request.irq, + Some(handle_irq_callback::), + flags.into_inner(), + name.as_char_ptr(), + (&raw mut (*this.as_ptr()).handler).cast(), + ) + })?; + request.irq + } + }) + ), + _pin: PhantomPinned, + }) + } + + /// Returns a reference to the handler that was registered with the system. + pub fn handler(&self) -> &T { + &self.handler + } + + /// Wait for pending IRQ handlers on other CPUs. + /// + /// This will attempt to access the inner [`Devres`] container. + pub fn try_synchronize(&self) -> Result { + let inner = self.inner.try_access().ok_or(ENODEV)?; + inner.synchronize(); + Ok(()) + } + + /// Wait for pending IRQ handlers on other CPUs. + pub fn synchronize(&self, dev: &Device) -> Result { + let inner = self.inner.access(dev)?; + inner.synchronize(); + Ok(()) + } +} + +/// # Safety +/// +/// This function should be only used as the callback in `request_irq`. +unsafe extern "C" fn handle_irq_callback(_irq: i32, ptr: *mut c_void) -> c_uint { + // SAFETY: `ptr` is a pointer to T set in `Registration::new` + let handler = unsafe { &*(ptr as *const T) }; + T::handle(handler) as c_uint +} From 135d40523244dcad3c64eb2ce131cf018db5cff4 Mon Sep 17 00:00:00 2001 From: Daniel Almeida Date: Mon, 11 Aug 2025 13:03:42 -0300 Subject: [PATCH 00439/11391] rust: irq: add support for threaded IRQs and handlers This patch adds support for threaded IRQs and handlers through irq::ThreadedRegistration and the irq::ThreadedHandler trait. Threaded interrupts are more permissive in the sense that further processing is possible in a kthread. This means that said execution takes place outside of interrupt context, which is rather restrictive in many ways. Registering a threaded irq is dependent upon having an IrqRequest that was previously allocated by a given device. This will be introduced in subsequent patches. Tested-by: Joel Fernandes Tested-by: Dirk Behme Reviewed-by: Alice Ryhl Signed-off-by: Daniel Almeida Link: https://lore.kernel.org/r/20250811-topics-tyr-request_irq2-v9-4-0485dcd9bcbf@collabora.com [ Add now available intra-doc links back in. - Danilo ] Signed-off-by: Danilo Krummrich --- rust/kernel/irq.rs | 5 +- rust/kernel/irq/request.rs | 232 ++++++++++++++++++++++++++++++++++++- 2 files changed, 232 insertions(+), 5 deletions(-) diff --git a/rust/kernel/irq.rs b/rust/kernel/irq.rs index c1019bc36ad1..20abd4056655 100644 --- a/rust/kernel/irq.rs +++ b/rust/kernel/irq.rs @@ -18,4 +18,7 @@ pub use flags::Flags; -pub use request::{Handler, IrqRequest, IrqReturn, Registration}; +pub use request::{ + Handler, IrqRequest, IrqReturn, Registration, ThreadedHandler, ThreadedIrqReturn, + ThreadedRegistration, +}; diff --git a/rust/kernel/irq/request.rs b/rust/kernel/irq/request.rs index c585811cfdfb..7a956566f503 100644 --- a/rust/kernel/irq/request.rs +++ b/rust/kernel/irq/request.rs @@ -1,8 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 // SPDX-FileCopyrightText: Copyright 2025 Collabora ltd. -//! This module provides types like [`Registration`] which allow users to -//! register handlers for a given IRQ line. +//! This module provides types like [`Registration`] and +//! [`ThreadedRegistration`], which allow users to register handlers for a given +//! IRQ line. use core::marker::PhantomPinned; @@ -15,7 +16,7 @@ use crate::str::CStr; use crate::sync::Arc; -/// The value that can be returned from a [`Handler`] or a `ThreadedHandler`. +/// The value that can be returned from a [`Handler`] or a [`ThreadedHandler`]. #[repr(u32)] pub enum IrqReturn { /// The interrupt was not from this device or was not handled. @@ -34,7 +35,7 @@ pub trait Handler: Sync { /// /// All work that does not necessarily need to be executed from /// interrupt context, should be deferred to a threaded handler. - /// See also `ThreadedRegistration`. + /// See also [`ThreadedRegistration`]. fn handle(&self) -> IrqReturn; } @@ -263,3 +264,226 @@ pub fn synchronize(&self, dev: &Device) -> Result { let handler = unsafe { &*(ptr as *const T) }; T::handle(handler) as c_uint } + +/// The value that can be returned from [`ThreadedHandler::handle`]. +#[repr(u32)] +pub enum ThreadedIrqReturn { + /// The interrupt was not from this device or was not handled. + None = bindings::irqreturn_IRQ_NONE, + + /// The interrupt was handled by this device. + Handled = bindings::irqreturn_IRQ_HANDLED, + + /// The handler wants the handler thread to wake up. + WakeThread = bindings::irqreturn_IRQ_WAKE_THREAD, +} + +/// Callbacks for a threaded IRQ handler. +pub trait ThreadedHandler: Sync { + /// The hard IRQ handler. + /// + /// This is executed in interrupt context, hence all corresponding + /// limitations do apply. All work that does not necessarily need to be + /// executed from interrupt context, should be deferred to the threaded + /// handler, i.e. [`ThreadedHandler::handle_threaded`]. + /// + /// The default implementation returns [`ThreadedIrqReturn::WakeThread`]. + fn handle(&self) -> ThreadedIrqReturn { + ThreadedIrqReturn::WakeThread + } + + /// The threaded IRQ handler. + /// + /// This is executed in process context. The kernel creates a dedicated + /// `kthread` for this purpose. + fn handle_threaded(&self) -> IrqReturn; +} + +impl ThreadedHandler for Arc { + fn handle(&self) -> ThreadedIrqReturn { + T::handle(self) + } + + fn handle_threaded(&self) -> IrqReturn { + T::handle_threaded(self) + } +} + +impl ThreadedHandler for Box { + fn handle(&self) -> ThreadedIrqReturn { + T::handle(self) + } + + fn handle_threaded(&self) -> IrqReturn { + T::handle_threaded(self) + } +} + +/// A registration of a threaded IRQ handler for a given IRQ line. +/// +/// Two callbacks are required: one to handle the IRQ, and one to handle any +/// other work in a separate thread. +/// +/// The thread handler is only called if the IRQ handler returns +/// [`ThreadedIrqReturn::WakeThread`]. +/// +/// # Examples +/// +/// The following is an example of using [`ThreadedRegistration`]. It uses a +/// [`Mutex`](kernel::sync::Mutex) to provide interior mutability. +/// +/// ``` +/// use kernel::c_str; +/// use kernel::device::Bound; +/// use kernel::irq::{ +/// self, Flags, IrqRequest, IrqReturn, ThreadedHandler, ThreadedIrqReturn, +/// ThreadedRegistration, +/// }; +/// use kernel::prelude::*; +/// use kernel::sync::{Arc, Mutex}; +/// +/// // Declare a struct that will be passed in when the interrupt fires. The u32 +/// // merely serves as an example of some internal data. +/// // +/// // [`irq::ThreadedHandler::handle`] takes `&self`. This example +/// // illustrates how interior mutability can be used when sharing the data +/// // between process context and IRQ context. +/// #[pin_data] +/// struct Data { +/// #[pin] +/// value: Mutex, +/// } +/// +/// impl ThreadedHandler for Data { +/// // This will run (in a separate kthread) if and only if +/// // [`ThreadedHandler::handle`] returns [`WakeThread`], which it does by +/// // default. +/// fn handle_threaded(&self) -> IrqReturn { +/// let mut data = self.value.lock(); +/// *data += 1; +/// IrqReturn::Handled +/// } +/// } +/// +/// // Registers a threaded IRQ handler for the given [`IrqRequest`]. +/// // +/// // This is executing in process context and assumes that `request` was +/// // previously acquired from a device. +/// fn register_threaded_irq( +/// handler: impl PinInit, +/// request: IrqRequest<'_>, +/// ) -> Result>> { +/// let registration = +/// ThreadedRegistration::new(request, Flags::SHARED, c_str!("my_device"), handler); +/// +/// let registration = Arc::pin_init(registration, GFP_KERNEL)?; +/// +/// { +/// // The data can be accessed from process context too. +/// let mut data = registration.handler().value.lock(); +/// *data += 1; +/// } +/// +/// Ok(registration) +/// } +/// # Ok::<(), Error>(()) +/// ``` +/// +/// # Invariants +/// +/// * We own an irq handler using `&T` as its private data. +#[pin_data] +pub struct ThreadedRegistration { + #[pin] + inner: Devres, + + #[pin] + handler: T, + + /// Pinned because we need address stability so that we can pass a pointer + /// to the callback. + #[pin] + _pin: PhantomPinned, +} + +impl ThreadedRegistration { + /// Registers the IRQ handler with the system for the given IRQ number. + pub fn new<'a>( + request: IrqRequest<'a>, + flags: Flags, + name: &'static CStr, + handler: impl PinInit + 'a, + ) -> impl PinInit + 'a { + try_pin_init!(&this in Self { + handler <- handler, + inner <- Devres::new( + request.dev, + try_pin_init!(RegistrationInner { + // SAFETY: `this` is a valid pointer to the `ThreadedRegistration` instance. + cookie: unsafe { &raw mut (*this.as_ptr()).handler }.cast(), + irq: { + // SAFETY: + // - The callbacks are valid for use with request_threaded_irq. + // - If this succeeds, the slot is guaranteed to be valid until the + // destructor of Self runs, which will deregister the callbacks + // before the memory location becomes invalid. + to_result(unsafe { + bindings::request_threaded_irq( + request.irq, + Some(handle_threaded_irq_callback::), + Some(thread_fn_callback::), + flags.into_inner(), + name.as_char_ptr(), + (&raw mut (*this.as_ptr()).handler).cast(), + ) + })?; + request.irq + } + }) + ), + _pin: PhantomPinned, + }) + } + + /// Returns a reference to the handler that was registered with the system. + pub fn handler(&self) -> &T { + &self.handler + } + + /// Wait for pending IRQ handlers on other CPUs. + /// + /// This will attempt to access the inner [`Devres`] container. + pub fn try_synchronize(&self) -> Result { + let inner = self.inner.try_access().ok_or(ENODEV)?; + inner.synchronize(); + Ok(()) + } + + /// Wait for pending IRQ handlers on other CPUs. + pub fn synchronize(&self, dev: &Device) -> Result { + let inner = self.inner.access(dev)?; + inner.synchronize(); + Ok(()) + } +} + +/// # Safety +/// +/// This function should be only used as the callback in `request_threaded_irq`. +unsafe extern "C" fn handle_threaded_irq_callback( + _irq: i32, + ptr: *mut c_void, +) -> c_uint { + // SAFETY: `ptr` is a pointer to T set in `ThreadedRegistration::new` + let handler = unsafe { &*(ptr as *const T) }; + T::handle(handler) as c_uint +} + +/// # Safety +/// +/// This function should be only used as the callback in `request_threaded_irq`. +unsafe extern "C" fn thread_fn_callback(_irq: i32, ptr: *mut c_void) -> c_uint { + // SAFETY: `ptr` is a pointer to T set in `ThreadedRegistration::new` + let handler = unsafe { &*(ptr as *const T) }; + T::handle_threaded(handler) as c_uint +} From 17e70f0c549f4a19da7d681d60b552901833f8f3 Mon Sep 17 00:00:00 2001 From: Daniel Almeida Date: Mon, 11 Aug 2025 13:03:43 -0300 Subject: [PATCH 00440/11391] rust: platform: add irq accessors These accessors can be used to retrieve a irq::Registration and irq::ThreadedRegistration from a platform device by index or name. Alternatively, drivers can retrieve an IrqRequest from a bound platform device for later use. These accessors ensure that only valid IRQ lines can ever be registered. Reviewed-by: Alice Ryhl Tested-by: Joel Fernandes Tested-by: Dirk Behme Signed-off-by: Daniel Almeida Link: https://lore.kernel.org/r/20250811-topics-tyr-request_irq2-v9-5-0485dcd9bcbf@collabora.com [ Remove expect(dead_code) from IrqRequest::new(), re-format macros and macro invocations to not exceed 100 characters line length. - Danilo ] Signed-off-by: Danilo Krummrich --- rust/kernel/irq/request.rs | 1 - rust/kernel/platform.rs | 176 +++++++++++++++++++++++++++++++++++++ 2 files changed, 176 insertions(+), 1 deletion(-) diff --git a/rust/kernel/irq/request.rs b/rust/kernel/irq/request.rs index 7a956566f503..4033df7d0dce 100644 --- a/rust/kernel/irq/request.rs +++ b/rust/kernel/irq/request.rs @@ -111,7 +111,6 @@ impl<'a> IrqRequest<'a> { /// # Safety /// /// - `irq` should be a valid IRQ number for `dev`. - #[expect(dead_code)] pub(crate) unsafe fn new(dev: &'a Device, irq: u32) -> Self { // INVARIANT: `irq` is a valid IRQ number for `dev`. IrqRequest { dev, irq } diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 8f028c76f9fa..ce2bb4d4e882 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -10,6 +10,7 @@ driver, error::{from_result, to_result, Result}, io::{mem::IoRequest, Resource}, + irq::{self, IrqRequest}, of, prelude::*, types::Opaque, @@ -284,6 +285,181 @@ pub fn io_request_by_name(&self, name: &CStr) -> Option> { } } +macro_rules! define_irq_accessor_by_index { + ( + $(#[$meta:meta])* $fn_name:ident, + $request_fn:ident, + $reg_type:ident, + $handler_trait:ident + ) => { + $(#[$meta])* + pub fn $fn_name<'a, T: irq::$handler_trait + 'static>( + &'a self, + flags: irq::Flags, + index: u32, + name: &'static CStr, + handler: impl PinInit + 'a, + ) -> Result, Error> + 'a> { + let request = self.$request_fn(index)?; + + Ok(irq::$reg_type::::new( + request, + flags, + name, + handler, + )) + } + }; +} + +macro_rules! define_irq_accessor_by_name { + ( + $(#[$meta:meta])* $fn_name:ident, + $request_fn:ident, + $reg_type:ident, + $handler_trait:ident + ) => { + $(#[$meta])* + pub fn $fn_name<'a, T: irq::$handler_trait + 'static>( + &'a self, + flags: irq::Flags, + irq_name: &CStr, + name: &'static CStr, + handler: impl PinInit + 'a, + ) -> Result, Error> + 'a> { + let request = self.$request_fn(irq_name)?; + + Ok(irq::$reg_type::::new( + request, + flags, + name, + handler, + )) + } + }; +} + +impl Device { + /// Returns an [`IrqRequest`] for the IRQ at the given index, if any. + pub fn irq_by_index(&self, index: u32) -> Result> { + // SAFETY: `self.as_raw` returns a valid pointer to a `struct platform_device`. + let irq = unsafe { bindings::platform_get_irq(self.as_raw(), index) }; + + if irq < 0 { + return Err(Error::from_errno(irq)); + } + + // SAFETY: `irq` is guaranteed to be a valid IRQ number for `&self`. + Ok(unsafe { IrqRequest::new(self.as_ref(), irq as u32) }) + } + + /// Returns an [`IrqRequest`] for the IRQ at the given index, but does not + /// print an error if the IRQ cannot be obtained. + pub fn optional_irq_by_index(&self, index: u32) -> Result> { + // SAFETY: `self.as_raw` returns a valid pointer to a `struct platform_device`. + let irq = unsafe { bindings::platform_get_irq_optional(self.as_raw(), index) }; + + if irq < 0 { + return Err(Error::from_errno(irq)); + } + + // SAFETY: `irq` is guaranteed to be a valid IRQ number for `&self`. + Ok(unsafe { IrqRequest::new(self.as_ref(), irq as u32) }) + } + + /// Returns an [`IrqRequest`] for the IRQ with the given name, if any. + pub fn irq_by_name(&self, name: &CStr) -> Result> { + // SAFETY: `self.as_raw` returns a valid pointer to a `struct platform_device`. + let irq = unsafe { bindings::platform_get_irq_byname(self.as_raw(), name.as_char_ptr()) }; + + if irq < 0 { + return Err(Error::from_errno(irq)); + } + + // SAFETY: `irq` is guaranteed to be a valid IRQ number for `&self`. + Ok(unsafe { IrqRequest::new(self.as_ref(), irq as u32) }) + } + + /// Returns an [`IrqRequest`] for the IRQ with the given name, but does not + /// print an error if the IRQ cannot be obtained. + pub fn optional_irq_by_name(&self, name: &CStr) -> Result> { + // SAFETY: `self.as_raw` returns a valid pointer to a `struct platform_device`. + let irq = unsafe { + bindings::platform_get_irq_byname_optional(self.as_raw(), name.as_char_ptr()) + }; + + if irq < 0 { + return Err(Error::from_errno(irq)); + } + + // SAFETY: `irq` is guaranteed to be a valid IRQ number for `&self`. + Ok(unsafe { IrqRequest::new(self.as_ref(), irq as u32) }) + } + + define_irq_accessor_by_index!( + /// Returns a [`irq::Registration`] for the IRQ at the given index. + request_irq_by_index, + irq_by_index, + Registration, + Handler + ); + define_irq_accessor_by_name!( + /// Returns a [`irq::Registration`] for the IRQ with the given name. + request_irq_by_name, + irq_by_name, + Registration, + Handler + ); + define_irq_accessor_by_index!( + /// Does the same as [`Self::request_irq_by_index`], except that it does + /// not print an error message if the IRQ cannot be obtained. + request_optional_irq_by_index, + optional_irq_by_index, + Registration, + Handler + ); + define_irq_accessor_by_name!( + /// Does the same as [`Self::request_irq_by_name`], except that it does + /// not print an error message if the IRQ cannot be obtained. + request_optional_irq_by_name, + optional_irq_by_name, + Registration, + Handler + ); + + define_irq_accessor_by_index!( + /// Returns a [`irq::ThreadedRegistration`] for the IRQ at the given index. + request_threaded_irq_by_index, + irq_by_index, + ThreadedRegistration, + ThreadedHandler + ); + define_irq_accessor_by_name!( + /// Returns a [`irq::ThreadedRegistration`] for the IRQ with the given name. + request_threaded_irq_by_name, + irq_by_name, + ThreadedRegistration, + ThreadedHandler + ); + define_irq_accessor_by_index!( + /// Does the same as [`Self::request_threaded_irq_by_index`], except + /// that it does not print an error message if the IRQ cannot be + /// obtained. + request_optional_threaded_irq_by_index, + optional_irq_by_index, + ThreadedRegistration, + ThreadedHandler + ); + define_irq_accessor_by_name!( + /// Does the same as [`Self::request_threaded_irq_by_name`], except that + /// it does not print an error message if the IRQ cannot be obtained. + request_optional_threaded_irq_by_name, + optional_irq_by_name, + ThreadedRegistration, + ThreadedHandler + ); +} + // 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 }); From 9b6d4fb9804febb1ae75e7259bb475cea58e28a7 Mon Sep 17 00:00:00 2001 From: Daniel Almeida Date: Mon, 11 Aug 2025 13:03:44 -0300 Subject: [PATCH 00441/11391] rust: pci: add irq accessors These accessors can be used to retrieve a irq::Registration or a irq::ThreadedRegistration from a pci device. Alternatively, drivers can retrieve an IrqRequest from a bound PCI device for later use. These accessors ensure that only valid IRQ lines can ever be registered. Reviewed-by: Alice Ryhl Tested-by: Joel Fernandes Tested-by: Dirk Behme Signed-off-by: Daniel Almeida Link: https://lore.kernel.org/r/20250811-topics-tyr-request_irq2-v9-6-0485dcd9bcbf@collabora.com Signed-off-by: Danilo Krummrich --- rust/helpers/pci.c | 8 ++++++++ rust/kernel/pci.rs | 45 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/rust/helpers/pci.c b/rust/helpers/pci.c index ef9cb38c81a6..5bf56004478c 100644 --- a/rust/helpers/pci.c +++ b/rust/helpers/pci.c @@ -11,3 +11,11 @@ bool rust_helper_dev_is_pci(const struct device *dev) { return dev_is_pci(dev); } + +#ifndef CONFIG_PCI_MSI +int rust_helper_pci_irq_vector(struct pci_dev *pdev, unsigned int nvec) +{ + return pci_irq_vector(pdev, nvec); +} + +#endif diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index 887ee611b553..3bf1737635a9 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -10,8 +10,8 @@ devres::Devres, driver, error::{from_result, to_result, Result}, - io::Io, - io::IoRaw, + io::{Io, IoRaw}, + irq::{self, IrqRequest}, str::CStr, types::{ARef, Opaque}, ThisModule, @@ -431,6 +431,47 @@ pub fn iomap_region<'a>( ) -> impl PinInit, Error> + 'a { self.iomap_region_sized::<0>(bar, name) } + + /// Returns an [`IrqRequest`] for the IRQ vector at the given index, if any. + pub fn irq_vector(&self, index: u32) -> Result> { + // SAFETY: `self.as_raw` returns a valid pointer to a `struct pci_dev`. + let irq = unsafe { crate::bindings::pci_irq_vector(self.as_raw(), index) }; + if irq < 0 { + return Err(crate::error::Error::from_errno(irq)); + } + // SAFETY: `irq` is guaranteed to be a valid IRQ number for `&self`. + Ok(unsafe { IrqRequest::new(self.as_ref(), irq as u32) }) + } + + /// Returns a [`kernel::irq::Registration`] for the IRQ vector at the given + /// index. + pub fn request_irq<'a, T: crate::irq::Handler + 'static>( + &'a self, + index: u32, + flags: irq::Flags, + name: &'static CStr, + handler: impl PinInit + 'a, + ) -> Result, Error> + 'a> { + let request = self.irq_vector(index)?; + + Ok(irq::Registration::::new(request, flags, name, handler)) + } + + /// Returns a [`kernel::irq::ThreadedRegistration`] for the IRQ vector at + /// the given index. + pub fn request_threaded_irq<'a, T: crate::irq::ThreadedHandler + 'static>( + &'a self, + index: u32, + flags: irq::Flags, + name: &'static CStr, + handler: impl PinInit + 'a, + ) -> Result, Error> + 'a> { + let request = self.irq_vector(index)?; + + Ok(irq::ThreadedRegistration::::new( + request, flags, name, handler, + )) + } } impl Device { From 29e16fcd67ee5b1d0417a657294cf96fdf2f8df9 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Mon, 11 Aug 2025 13:03:45 -0300 Subject: [PATCH 00442/11391] rust: irq: add &Device argument to irq callbacks When working with a bus device, many operations are only possible while the device is still bound. The &Device type represents a proof in the type system that you are in a scope where the device is guaranteed to still be bound. Since we deregister irq callbacks when unbinding a device, if an irq callback is running, that implies that the device has not yet been unbound. To allow drivers to take advantage of that, add an additional argument to irq callbacks. Signed-off-by: Alice Ryhl Reviewed-by: Boqun Feng Signed-off-by: Daniel Almeida Link: https://lore.kernel.org/r/20250811-topics-tyr-request_irq2-v9-7-0485dcd9bcbf@collabora.com Signed-off-by: Danilo Krummrich --- rust/kernel/irq/request.rs | 95 +++++++++++++++++++++++--------------- 1 file changed, 57 insertions(+), 38 deletions(-) diff --git a/rust/kernel/irq/request.rs b/rust/kernel/irq/request.rs index 4033df7d0dce..b150563fdef8 100644 --- a/rust/kernel/irq/request.rs +++ b/rust/kernel/irq/request.rs @@ -36,18 +36,18 @@ pub trait Handler: Sync { /// All work that does not necessarily need to be executed from /// interrupt context, should be deferred to a threaded handler. /// See also [`ThreadedRegistration`]. - fn handle(&self) -> IrqReturn; + fn handle(&self, device: &Device) -> IrqReturn; } impl Handler for Arc { - fn handle(&self) -> IrqReturn { - T::handle(self) + fn handle(&self, device: &Device) -> IrqReturn { + T::handle(self, device) } } impl Handler for Box { - fn handle(&self) -> IrqReturn { - T::handle(self) + fn handle(&self, device: &Device) -> IrqReturn { + T::handle(self, device) } } @@ -140,7 +140,7 @@ pub fn irq(&self) -> u32 { /// /// ``` /// use kernel::c_str; -/// use kernel::device::Bound; +/// use kernel::device::{Bound, Device}; /// use kernel::irq::{self, Flags, IrqRequest, IrqReturn, Registration}; /// use kernel::prelude::*; /// use kernel::sync::{Arc, Completion}; @@ -154,7 +154,7 @@ pub fn irq(&self) -> u32 { /// /// impl irq::Handler for Data { /// // Executed in IRQ context. -/// fn handle(&self) -> IrqReturn { +/// fn handle(&self, _dev: &Device) -> IrqReturn { /// self.completion.complete_all(); /// IrqReturn::Handled /// } @@ -180,7 +180,7 @@ pub fn irq(&self) -> u32 { /// /// # Invariants /// -/// * We own an irq handler using `&self.handler` as its private data. +/// * We own an irq handler whose cookie is a pointer to `Self`. #[pin_data] pub struct Registration { #[pin] @@ -208,21 +208,24 @@ pub fn new<'a>( inner <- Devres::new( request.dev, try_pin_init!(RegistrationInner { - // SAFETY: `this` is a valid pointer to the `Registration` instance - cookie: unsafe { &raw mut (*this.as_ptr()).handler }.cast(), + // INVARIANT: `this` is a valid pointer to the `Registration` instance + cookie: this.as_ptr().cast::(), irq: { // SAFETY: // - The callbacks are valid for use with request_irq. // - If this succeeds, the slot is guaranteed to be valid until the // destructor of Self runs, which will deregister the callbacks // before the memory location becomes invalid. + // - When request_irq is called, everything that handle_irq_callback will + // touch has already been initialized, so it's safe for the callback to + // be called immediately. to_result(unsafe { bindings::request_irq( request.irq, Some(handle_irq_callback::), flags.into_inner(), name.as_char_ptr(), - (&raw mut (*this.as_ptr()).handler).cast(), + this.as_ptr().cast::(), ) })?; request.irq @@ -259,9 +262,13 @@ pub fn synchronize(&self, dev: &Device) -> Result { /// /// This function should be only used as the callback in `request_irq`. unsafe extern "C" fn handle_irq_callback(_irq: i32, ptr: *mut c_void) -> c_uint { - // SAFETY: `ptr` is a pointer to T set in `Registration::new` - let handler = unsafe { &*(ptr as *const T) }; - T::handle(handler) as c_uint + // SAFETY: `ptr` is a pointer to `Registration` set in `Registration::new` + let registration = unsafe { &*(ptr as *const Registration) }; + // SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq + // callback is running implies that the device has not yet been unbound. + let device = unsafe { registration.inner.device().as_bound() }; + + T::handle(®istration.handler, device) as c_uint } /// The value that can be returned from [`ThreadedHandler::handle`]. @@ -287,7 +294,8 @@ pub trait ThreadedHandler: Sync { /// handler, i.e. [`ThreadedHandler::handle_threaded`]. /// /// The default implementation returns [`ThreadedIrqReturn::WakeThread`]. - fn handle(&self) -> ThreadedIrqReturn { + #[expect(unused_variables)] + fn handle(&self, device: &Device) -> ThreadedIrqReturn { ThreadedIrqReturn::WakeThread } @@ -295,26 +303,26 @@ fn handle(&self) -> ThreadedIrqReturn { /// /// This is executed in process context. The kernel creates a dedicated /// `kthread` for this purpose. - fn handle_threaded(&self) -> IrqReturn; + fn handle_threaded(&self, device: &Device) -> IrqReturn; } impl ThreadedHandler for Arc { - fn handle(&self) -> ThreadedIrqReturn { - T::handle(self) + fn handle(&self, device: &Device) -> ThreadedIrqReturn { + T::handle(self, device) } - fn handle_threaded(&self) -> IrqReturn { - T::handle_threaded(self) + fn handle_threaded(&self, device: &Device) -> IrqReturn { + T::handle_threaded(self, device) } } impl ThreadedHandler for Box { - fn handle(&self) -> ThreadedIrqReturn { - T::handle(self) + fn handle(&self, device: &Device) -> ThreadedIrqReturn { + T::handle(self, device) } - fn handle_threaded(&self) -> IrqReturn { - T::handle_threaded(self) + fn handle_threaded(&self, device: &Device) -> IrqReturn { + T::handle_threaded(self, device) } } @@ -333,7 +341,7 @@ fn handle_threaded(&self) -> IrqReturn { /// /// ``` /// use kernel::c_str; -/// use kernel::device::Bound; +/// use kernel::device::{Bound, Device}; /// use kernel::irq::{ /// self, Flags, IrqRequest, IrqReturn, ThreadedHandler, ThreadedIrqReturn, /// ThreadedRegistration, @@ -357,7 +365,7 @@ fn handle_threaded(&self) -> IrqReturn { /// // This will run (in a separate kthread) if and only if /// // [`ThreadedHandler::handle`] returns [`WakeThread`], which it does by /// // default. -/// fn handle_threaded(&self) -> IrqReturn { +/// fn handle_threaded(&self, _dev: &Device) -> IrqReturn { /// let mut data = self.value.lock(); /// *data += 1; /// IrqReturn::Handled @@ -390,7 +398,7 @@ fn handle_threaded(&self) -> IrqReturn { /// /// # Invariants /// -/// * We own an irq handler using `&T` as its private data. +/// * We own an irq handler whose cookie is a pointer to `Self`. #[pin_data] pub struct ThreadedRegistration { #[pin] @@ -418,14 +426,17 @@ pub fn new<'a>( inner <- Devres::new( request.dev, try_pin_init!(RegistrationInner { - // SAFETY: `this` is a valid pointer to the `ThreadedRegistration` instance. - cookie: unsafe { &raw mut (*this.as_ptr()).handler }.cast(), + // INVARIANT: `this` is a valid pointer to the `ThreadedRegistration` instance. + cookie: this.as_ptr().cast::(), irq: { // SAFETY: // - The callbacks are valid for use with request_threaded_irq. // - If this succeeds, the slot is guaranteed to be valid until the - // destructor of Self runs, which will deregister the callbacks - // before the memory location becomes invalid. + // destructor of Self runs, which will deregister the callbacks + // before the memory location becomes invalid. + // - When request_threaded_irq is called, everything that the two callbacks + // will touch has already been initialized, so it's safe for the + // callbacks to be called immediately. to_result(unsafe { bindings::request_threaded_irq( request.irq, @@ -433,7 +444,7 @@ pub fn new<'a>( Some(thread_fn_callback::), flags.into_inner(), name.as_char_ptr(), - (&raw mut (*this.as_ptr()).handler).cast(), + this.as_ptr().cast::(), ) })?; request.irq @@ -473,16 +484,24 @@ pub fn synchronize(&self, dev: &Device) -> Result { _irq: i32, ptr: *mut c_void, ) -> c_uint { - // SAFETY: `ptr` is a pointer to T set in `ThreadedRegistration::new` - let handler = unsafe { &*(ptr as *const T) }; - T::handle(handler) as c_uint + // SAFETY: `ptr` is a pointer to `ThreadedRegistration` set in `ThreadedRegistration::new` + let registration = unsafe { &*(ptr as *const ThreadedRegistration) }; + // SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq + // callback is running implies that the device has not yet been unbound. + let device = unsafe { registration.inner.device().as_bound() }; + + T::handle(®istration.handler, device) as c_uint } /// # Safety /// /// This function should be only used as the callback in `request_threaded_irq`. unsafe extern "C" fn thread_fn_callback(_irq: i32, ptr: *mut c_void) -> c_uint { - // SAFETY: `ptr` is a pointer to T set in `ThreadedRegistration::new` - let handler = unsafe { &*(ptr as *const T) }; - T::handle_threaded(handler) as c_uint + // SAFETY: `ptr` is a pointer to `ThreadedRegistration` set in `ThreadedRegistration::new` + let registration = unsafe { &*(ptr as *const ThreadedRegistration) }; + // SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq + // callback is running implies that the device has not yet been unbound. + let device = unsafe { registration.inner.device().as_bound() }; + + T::handle_threaded(®istration.handler, device) as c_uint } From 377c2b3c46c6ff33cb6559b98c44e22f1ff9fefc Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Fri, 25 Jul 2025 22:28:40 +0200 Subject: [PATCH 00443/11391] MAINTAINERS: add "DEVICE I/O & IRQ [RUST]" entry This entry will handle device I/O patches and abstractions (such as memory-mapped IO and system resources series [1]), as well as IRQ ones (such as the `request_irq` series [2]). Patches will flow through driver-core, at least for the time being. Danilo, Alice and Daniel will maintain it. Cc: Danilo Krummrich Cc: Alice Ryhl Cc: Daniel Almeida Link: https://lore.kernel.org/rust-for-linux/20250717-topics-tyr-platform_iomem-v15-0-beca780b77e3@collabora.com/ [1] Link: https://lore.kernel.org/rust-for-linux/20250715-topics-tyr-request_irq2-v7-0-d469c0f37c07@collabora.com/ [2] Signed-off-by: Miguel Ojeda Acked-by: Daniel Almeida Acked-by: Alice Ryhl Acked-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250725202840.2251768-1-ojeda@kernel.org Signed-off-by: Danilo Krummrich --- MAINTAINERS | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index fe168477caa4..38b90f3a04dd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7021,6 +7021,21 @@ F: drivers/devfreq/event/ F: include/dt-bindings/pmu/exynos_ppmu.h F: include/linux/devfreq-event.h +DEVICE I/O & IRQ [RUST] +M: Danilo Krummrich +M: Alice Ryhl +M: Daniel Almeida +L: rust-for-linux@vger.kernel.org +S: Supported +W: https://rust-for-linux.com +B: https://github.com/Rust-for-Linux/linux/issues +C: https://rust-for-linux.zulipchat.com +T: git git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core.git +F: rust/kernel/io.rs +F: rust/kernel/io/ +F: rust/kernel/irq.rs +F: rust/kernel/irq/ + DEVICE RESOURCE MANAGEMENT HELPERS M: Hans de Goede R: Matti Vaittinen From 6bed0a50235aaeae2c33f3cfee5ffa5d040be570 Mon Sep 17 00:00:00 2001 From: Dongliang Mu Date: Tue, 12 Aug 2025 13:07:10 +0800 Subject: [PATCH 00444/11391] MAINTAINERS: add File entry for scripts/checktransupdate.py to DOCUMENTATION As suggested by Nathan, add a File entry for scripts/checktransupdate.py to the DOCUMENTATION section to maintain this script. Link: https://lore.kernel.org/all/20250811212446.GA924610@ax162/ Signed-off-by: Dongliang Mu Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250812050711.2515173-1-dzm91@hust.edu.cn --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 39d5e4e09273..dafc11712544 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7302,6 +7302,7 @@ P: Documentation/doc-guide/maintainer-profile.rst T: git git://git.lwn.net/linux.git docs-next F: Documentation/ F: scripts/check-variable-fonts.sh +F: scripts/checktransupdate.py F: scripts/documentation-file-ref-check F: scripts/get_abi.py F: scripts/kernel-doc* From 0e6bb6888791656c3973f26da3288323524573c0 Mon Sep 17 00:00:00 2001 From: Gopi Krishna Menon Date: Mon, 11 Aug 2025 05:23:44 +0530 Subject: [PATCH 00445/11391] docs: folio_queue: Fix minor typo in folio_queue page Specifically, fix typo 'hese'-> 'these' Signed-off-by: Gopi Krishna Menon Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250810235346.4153-1-krishnagopi487@gmail.com --- Documentation/core-api/folio_queue.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/core-api/folio_queue.rst b/Documentation/core-api/folio_queue.rst index 83cfbc157e49..b7628896d2b6 100644 --- a/Documentation/core-api/folio_queue.rst +++ b/Documentation/core-api/folio_queue.rst @@ -44,7 +44,7 @@ Each segment in the list also stores: * the size of each folio and * three 1-bit marks per folio, -but hese should not be accessed directly as the underlying data structure may +but these should not be accessed directly as the underlying data structure may change, but rather the access functions outlined below should be used. The facility can be made accessible by:: From 70d476b63a1494337f2b9fec1e9b1cab2e6116d3 Mon Sep 17 00:00:00 2001 From: Gopi Krishna Menon Date: Sun, 10 Aug 2025 16:42:48 +0530 Subject: [PATCH 00446/11391] Documentation/rv: Fix minor typo in monitor_synthesis page Specifically, fix spelling of "practice" Signed-off-by: Gopi Krishna Menon Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250810111249.93181-1-krishnagopi487@gmail.com --- Documentation/trace/rv/monitor_synthesis.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/trace/rv/monitor_synthesis.rst b/Documentation/trace/rv/monitor_synthesis.rst index ac808a7554f5..3a7d7b2f6cb6 100644 --- a/Documentation/trace/rv/monitor_synthesis.rst +++ b/Documentation/trace/rv/monitor_synthesis.rst @@ -181,7 +181,7 @@ which is the list of atomic propositions present in the LTL specification functions interacting with the Buchi automaton. While generating code, `rvgen` cannot understand the meaning of the atomic -propositions. Thus, that task is left for manual work. The recommended pratice +propositions. Thus, that task is left for manual work. The recommended practice is adding tracepoints to places where the atomic propositions change; and in the tracepoints' handlers: the Buchi automaton is executed using:: From a49eebfa8ba1a90cbe01371f852b8da805d3aa55 Mon Sep 17 00:00:00 2001 From: Akshaykumar Gunari Date: Thu, 7 Aug 2025 20:21:19 +0530 Subject: [PATCH 00447/11391] docs: arm: stm32: fix typo "busses" -> "buses" Fix the spelling of "busses" to the preferred form "buses" in STM32 ARM architecture documentation. Signed-off-by: Akshaykumar Gunari Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250807145119.2214-1-akshaygunari@gmail.com --- Documentation/arch/arm/stm32/stm32f746-overview.rst | 2 +- Documentation/arch/arm/stm32/stm32f769-overview.rst | 2 +- Documentation/arch/arm/stm32/stm32h743-overview.rst | 2 +- Documentation/arch/arm/stm32/stm32h750-overview.rst | 2 +- Documentation/arch/arm/stm32/stm32mp13-overview.rst | 2 +- Documentation/arch/arm/stm32/stm32mp151-overview.rst | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Documentation/arch/arm/stm32/stm32f746-overview.rst b/Documentation/arch/arm/stm32/stm32f746-overview.rst index 78befddc7740..335f0855a858 100644 --- a/Documentation/arch/arm/stm32/stm32f746-overview.rst +++ b/Documentation/arch/arm/stm32/stm32f746-overview.rst @@ -15,7 +15,7 @@ It features: - SD/MMC/SDIO support - Ethernet controller - USB OTFG FS & HS controllers -- I2C, SPI, CAN busses support +- I2C, SPI, CAN buses support - Several 16 & 32 bits general purpose timers - Serial Audio interface - LCD controller diff --git a/Documentation/arch/arm/stm32/stm32f769-overview.rst b/Documentation/arch/arm/stm32/stm32f769-overview.rst index e482980ddf21..ef31aadee68f 100644 --- a/Documentation/arch/arm/stm32/stm32f769-overview.rst +++ b/Documentation/arch/arm/stm32/stm32f769-overview.rst @@ -15,7 +15,7 @@ It features: - SD/MMC/SDIO support*2 - Ethernet controller - USB OTFG FS & HS controllers -- I2C*4, SPI*6, CAN*3 busses support +- I2C*4, SPI*6, CAN*3 buses support - Several 16 & 32 bits general purpose timers - Serial Audio interface*2 - LCD controller diff --git a/Documentation/arch/arm/stm32/stm32h743-overview.rst b/Documentation/arch/arm/stm32/stm32h743-overview.rst index 4e15f1a42730..7659df24d362 100644 --- a/Documentation/arch/arm/stm32/stm32h743-overview.rst +++ b/Documentation/arch/arm/stm32/stm32h743-overview.rst @@ -15,7 +15,7 @@ It features: - SD/MMC/SDIO support - Ethernet controller - USB OTFG FS & HS controllers -- I2C, SPI, CAN busses support +- I2C, SPI, CAN buses support - Several 16 & 32 bits general purpose timers - Serial Audio interface - LCD controller diff --git a/Documentation/arch/arm/stm32/stm32h750-overview.rst b/Documentation/arch/arm/stm32/stm32h750-overview.rst index 0e51235c9547..be032b77d1f1 100644 --- a/Documentation/arch/arm/stm32/stm32h750-overview.rst +++ b/Documentation/arch/arm/stm32/stm32h750-overview.rst @@ -15,7 +15,7 @@ It features: - SD/MMC/SDIO support - Ethernet controller - USB OTFG FS & HS controllers -- I2C, SPI, CAN busses support +- I2C, SPI, CAN buses support - Several 16 & 32 bits general purpose timers - Serial Audio interface - LCD controller diff --git a/Documentation/arch/arm/stm32/stm32mp13-overview.rst b/Documentation/arch/arm/stm32/stm32mp13-overview.rst index 3bb9492dad49..b5e9589fb06f 100644 --- a/Documentation/arch/arm/stm32/stm32mp13-overview.rst +++ b/Documentation/arch/arm/stm32/stm32mp13-overview.rst @@ -24,7 +24,7 @@ More details: - ADC/DAC - USB EHCI/OHCI controllers - USB OTG -- I2C, SPI, CAN busses support +- I2C, SPI, CAN buses support - Several general purpose timers - Serial Audio interface - LCD controller diff --git a/Documentation/arch/arm/stm32/stm32mp151-overview.rst b/Documentation/arch/arm/stm32/stm32mp151-overview.rst index f42a2ac309c0..b58c256ede9a 100644 --- a/Documentation/arch/arm/stm32/stm32mp151-overview.rst +++ b/Documentation/arch/arm/stm32/stm32mp151-overview.rst @@ -23,7 +23,7 @@ More details: - ADC/DAC - USB EHCI/OHCI controllers - USB OTG -- I2C, SPI busses support +- I2C, SPI buses support - Several general purpose timers - Serial Audio interface - LCD-TFT controller From 8a013ec9cb7af9921656c0e78c73510c9e4a0cc1 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Tue, 12 Aug 2025 13:50:35 +0200 Subject: [PATCH 00448/11391] cgroup: Replace deprecated strcpy() with strscpy() strcpy() is deprecated; use strscpy() instead. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Signed-off-by: Tejun Heo --- kernel/cgroup/cgroup-v1.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c index 2a4a387f867a..763343fbd5a1 100644 --- a/kernel/cgroup/cgroup-v1.c +++ b/kernel/cgroup/cgroup-v1.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -1133,7 +1134,7 @@ int cgroup1_reconfigure(struct fs_context *fc) if (ctx->release_agent) { spin_lock(&release_agent_path_lock); - strcpy(root->release_agent_path, ctx->release_agent); + strscpy(root->release_agent_path, ctx->release_agent); spin_unlock(&release_agent_path_lock); } From 526c2530cbf84428a0a2b5ca7800986c0912ac35 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Sun, 10 Aug 2025 15:29:40 +0800 Subject: [PATCH 00449/11391] tcp: cdg: remove redundant __GFP_NOWARN GFP_NOWAIT already includes __GFP_NOWARN, so let's remove the redundant __GFP_NOWARN. Signed-off-by: Qianfeng Rong Reviewed-by: Eric Dumazet Link: https://patch.msgid.link/20250810072944.438574-2-rongqianfeng@vivo.com Signed-off-by: Jakub Kicinski --- net/ipv4/tcp_cdg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp_cdg.c b/net/ipv4/tcp_cdg.c index ba4d98e510e0..fbad6c35dee9 100644 --- a/net/ipv4/tcp_cdg.c +++ b/net/ipv4/tcp_cdg.c @@ -379,7 +379,7 @@ static void tcp_cdg_init(struct sock *sk) /* We silently fall back to window = 1 if allocation fails. */ if (window > 1) ca->gradients = kcalloc(window, sizeof(ca->gradients[0]), - GFP_NOWAIT | __GFP_NOWARN); + GFP_NOWAIT); ca->rtt_seq = tp->snd_nxt; ca->shadow_wnd = tcp_snd_cwnd(tp); } From 7792232a4ea1a8b6fe34d0d99a1e02aac185e633 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Sun, 10 Aug 2025 15:29:41 +0800 Subject: [PATCH 00450/11391] RDS: remove redundant __GFP_NOWARN GFP_NOWAIT already includes __GFP_NOWARN, so let's remove the redundant __GFP_NOWARN. Signed-off-by: Qianfeng Rong Reviewed-by: Allison Henderson Link: https://patch.msgid.link/20250810072944.438574-3-rongqianfeng@vivo.com Signed-off-by: Jakub Kicinski --- net/rds/ib_recv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/rds/ib_recv.c b/net/rds/ib_recv.c index e53b7f266bd7..4248dfa816eb 100644 --- a/net/rds/ib_recv.c +++ b/net/rds/ib_recv.c @@ -1034,7 +1034,7 @@ void rds_ib_recv_cqe_handler(struct rds_ib_connection *ic, rds_ib_stats_inc(s_ib_rx_ring_empty); if (rds_ib_ring_low(&ic->i_recv_ring)) { - rds_ib_recv_refill(conn, 0, GFP_NOWAIT | __GFP_NOWARN); + rds_ib_recv_refill(conn, 0, GFP_NOWAIT); rds_ib_stats_inc(s_ib_rx_refill_from_cq); } } From 63fe077c21d323cbc8d56114e9139bbadab33ce5 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 11 Aug 2025 11:34:40 +0200 Subject: [PATCH 00451/11391] caif: Replace memset(0) + strscpy() with strscpy_pad() Replace memset(0) followed by strscpy() with strscpy_pad() to improve cfctrl_linkup_request(). 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. Signed-off-by: Thorsten Blum Link: https://patch.msgid.link/20250811093442.5075-2-thorsten.blum@linux.dev Signed-off-by: Jakub Kicinski --- net/caif/cfctrl.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/caif/cfctrl.c b/net/caif/cfctrl.c index 06b604cf9d58..2aa1e7d46eb2 100644 --- a/net/caif/cfctrl.c +++ b/net/caif/cfctrl.c @@ -257,9 +257,7 @@ int cfctrl_linkup_request(struct cflayer *layer, cfpkt_add_body(pkt, &tmp16, 2); tmp16 = cpu_to_le16(param->u.utility.fifosize_bufs); cfpkt_add_body(pkt, &tmp16, 2); - memset(utility_name, 0, sizeof(utility_name)); - strscpy(utility_name, param->u.utility.name, - UTILITY_NAME_LENGTH); + strscpy_pad(utility_name, param->u.utility.name); cfpkt_add_body(pkt, utility_name, UTILITY_NAME_LENGTH); tmp8 = param->u.utility.paramlen; cfpkt_add_body(pkt, &tmp8, 1); From 11b99886d1948503ccc3f24548b3dfb7ff0a5261 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 11 Aug 2025 12:12:11 +0100 Subject: [PATCH 00452/11391] net: stmmac: make variable data a u32 Make data a u32 instead of an unsigned long, this way it is explicitly the same width as the operations performed on it and the same width as a writel store, and it cleans up sign extention warnings when 64 bit static analysis is performed on the code. Signed-off-by: Colin Ian King Reviewed-by: Russell King (Oracle) Link: https://patch.msgid.link/20250811111211.1646600-1-colin.i.king@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c index 4846bf49c576..467f1a05747e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c @@ -251,7 +251,7 @@ void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr) void stmmac_set_mac_addr(void __iomem *ioaddr, const u8 addr[6], unsigned int high, unsigned int low) { - unsigned long data; + u32 data; data = (addr[5] << 8) | addr[4]; /* For MAC Addr registers we have to set the Address Enable (AE) From f8262b8dadfa635cc8f203c40eb0b75b8625f44c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 11 Aug 2025 16:22:36 +0200 Subject: [PATCH 00453/11391] dt-bindings: nfc: ti,trf7970a: 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://patch.msgid.link/20250811142235.170407-2-krzysztof.kozlowski@linaro.org Signed-off-by: Jakub Kicinski --- Documentation/devicetree/bindings/net/nfc/ti,trf7970a.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/net/nfc/ti,trf7970a.yaml b/Documentation/devicetree/bindings/net/nfc/ti,trf7970a.yaml index 5f49bd9ac5e6..783a85b84893 100644 --- a/Documentation/devicetree/bindings/net/nfc/ti,trf7970a.yaml +++ b/Documentation/devicetree/bindings/net/nfc/ti,trf7970a.yaml @@ -56,7 +56,6 @@ properties: Regulator for supply voltage to VIN pin ti,rx-gain-reduction-db: - $ref: /schemas/types.yaml#/definitions/uint32 description: | Specify an RX gain reduction to reduce antenna sensitivity with 5dB per increment, with a maximum of 15dB. Supported values: [0, 5, 10, 15]. From 86e3d52bd3e919181d5f7e5107065d16e694c8d8 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 11 Aug 2025 14:52:52 +0000 Subject: [PATCH 00454/11391] phonet: add __rcu annotations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removes following sparse errors. make C=2 net/phonet/socket.o net/phonet/af_phonet.o CHECK net/phonet/socket.c net/phonet/socket.c:619:14: error: incompatible types in comparison expression (different address spaces): net/phonet/socket.c:619:14: struct sock [noderef] __rcu * net/phonet/socket.c:619:14: struct sock * net/phonet/socket.c:642:17: error: incompatible types in comparison expression (different address spaces): net/phonet/socket.c:642:17: struct sock [noderef] __rcu * net/phonet/socket.c:642:17: struct sock * net/phonet/socket.c:658:17: error: incompatible types in comparison expression (different address spaces): net/phonet/socket.c:658:17: struct sock [noderef] __rcu * net/phonet/socket.c:658:17: struct sock * net/phonet/socket.c:677:25: error: incompatible types in comparison expression (different address spaces): net/phonet/socket.c:677:25: struct sock [noderef] __rcu * net/phonet/socket.c:677:25: struct sock * net/phonet/socket.c:726:21: warning: context imbalance in 'pn_res_seq_start' - wrong count at exit net/phonet/socket.c:741:13: warning: context imbalance in 'pn_res_seq_stop' - wrong count at exit CHECK net/phonet/af_phonet.c net/phonet/af_phonet.c:35:14: error: incompatible types in comparison expression (different address spaces): net/phonet/af_phonet.c:35:14: struct phonet_protocol const [noderef] __rcu * net/phonet/af_phonet.c:35:14: struct phonet_protocol const * net/phonet/af_phonet.c:474:17: error: incompatible types in comparison expression (different address spaces): net/phonet/af_phonet.c:474:17: struct phonet_protocol const [noderef] __rcu * net/phonet/af_phonet.c:474:17: struct phonet_protocol const * net/phonet/af_phonet.c:486:9: error: incompatible types in comparison expression (different address spaces): net/phonet/af_phonet.c:486:9: struct phonet_protocol const [noderef] __rcu * net/phonet/af_phonet.c:486:9: struct phonet_protocol const * Signed-off-by: Eric Dumazet Acked-by: Rémi Denis-Courmont Link: https://patch.msgid.link/20250811145252.1007242-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/phonet/af_phonet.c | 4 ++-- net/phonet/socket.c | 23 ++++++++++++----------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c index a27efa4faa4e..238a9638d2b0 100644 --- a/net/phonet/af_phonet.c +++ b/net/phonet/af_phonet.c @@ -22,7 +22,7 @@ #include /* Transport protocol registration */ -static const struct phonet_protocol *proto_tab[PHONET_NPROTO] __read_mostly; +static const struct phonet_protocol __rcu *proto_tab[PHONET_NPROTO] __read_mostly; static const struct phonet_protocol *phonet_proto_get(unsigned int protocol) { @@ -482,7 +482,7 @@ void phonet_proto_unregister(unsigned int protocol, const struct phonet_protocol *pp) { mutex_lock(&proto_tab_lock); - BUG_ON(proto_tab[protocol] != pp); + BUG_ON(rcu_access_pointer(proto_tab[protocol]) != pp); RCU_INIT_POINTER(proto_tab[protocol], NULL); mutex_unlock(&proto_tab_lock); synchronize_rcu(); diff --git a/net/phonet/socket.c b/net/phonet/socket.c index ea4d5e6533db..2b61a40b568e 100644 --- a/net/phonet/socket.c +++ b/net/phonet/socket.c @@ -602,7 +602,7 @@ const struct seq_operations pn_sock_seq_ops = { #endif static struct { - struct sock *sk[256]; + struct sock __rcu *sk[256]; } pnres; /* @@ -654,7 +654,7 @@ int pn_sock_unbind_res(struct sock *sk, u8 res) return -EPERM; mutex_lock(&resource_mutex); - if (pnres.sk[res] == sk) { + if (rcu_access_pointer(pnres.sk[res]) == sk) { RCU_INIT_POINTER(pnres.sk[res], NULL); ret = 0; } @@ -673,7 +673,7 @@ void pn_sock_unbind_all_res(struct sock *sk) mutex_lock(&resource_mutex); for (res = 0; res < 256; res++) { - if (pnres.sk[res] == sk) { + if (rcu_access_pointer(pnres.sk[res]) == sk) { RCU_INIT_POINTER(pnres.sk[res], NULL); match++; } @@ -688,7 +688,7 @@ void pn_sock_unbind_all_res(struct sock *sk) } #ifdef CONFIG_PROC_FS -static struct sock **pn_res_get_idx(struct seq_file *seq, loff_t pos) +static struct sock __rcu **pn_res_get_idx(struct seq_file *seq, loff_t pos) { struct net *net = seq_file_net(seq); unsigned int i; @@ -697,7 +697,7 @@ static struct sock **pn_res_get_idx(struct seq_file *seq, loff_t pos) return NULL; for (i = 0; i < 256; i++) { - if (pnres.sk[i] == NULL) + if (rcu_access_pointer(pnres.sk[i]) == NULL) continue; if (!pos) return pnres.sk + i; @@ -706,7 +706,7 @@ static struct sock **pn_res_get_idx(struct seq_file *seq, loff_t pos) return NULL; } -static struct sock **pn_res_get_next(struct seq_file *seq, struct sock **sk) +static struct sock __rcu **pn_res_get_next(struct seq_file *seq, struct sock __rcu **sk) { struct net *net = seq_file_net(seq); unsigned int i; @@ -728,7 +728,7 @@ static void *pn_res_seq_start(struct seq_file *seq, loff_t *pos) static void *pn_res_seq_next(struct seq_file *seq, void *v, loff_t *pos) { - struct sock **sk; + struct sock __rcu **sk; if (v == SEQ_START_TOKEN) sk = pn_res_get_idx(seq, 0); @@ -747,11 +747,12 @@ static void pn_res_seq_stop(struct seq_file *seq, void *v) static int pn_res_seq_show(struct seq_file *seq, void *v) { seq_setwidth(seq, 63); - if (v == SEQ_START_TOKEN) + if (v == SEQ_START_TOKEN) { seq_puts(seq, "rs uid inode"); - else { - struct sock **psk = v; - struct sock *sk = *psk; + } else { + struct sock __rcu **psk = v; + struct sock *sk = rcu_dereference_protected(*psk, + lockdep_is_held(&resource_mutex)); seq_printf(seq, "%02X %5u %lu", (int) (psk - pnres.sk), From bab4ab484a6ca170847da9bffe86f1fa90df4bbe Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Tue, 12 Aug 2025 15:33:55 -0500 Subject: [PATCH 00455/11391] ASoC: dt-bindings: Convert brcm,bcm2835-i2s to DT schema Convert the Broadcom BCM2835 I2S/PCM binding to DT schema format. It's a straightforward conversion. Signed-off-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250812203356.735234-1-robh@kernel.org Signed-off-by: Mark Brown --- .../bindings/sound/brcm,bcm2835-i2s.txt | 24 --------- .../bindings/sound/brcm,bcm2835-i2s.yaml | 51 +++++++++++++++++++ 2 files changed, 51 insertions(+), 24 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/brcm,bcm2835-i2s.txt create mode 100644 Documentation/devicetree/bindings/sound/brcm,bcm2835-i2s.yaml diff --git a/Documentation/devicetree/bindings/sound/brcm,bcm2835-i2s.txt b/Documentation/devicetree/bindings/sound/brcm,bcm2835-i2s.txt deleted file mode 100644 index 7bb0362828ec..000000000000 --- a/Documentation/devicetree/bindings/sound/brcm,bcm2835-i2s.txt +++ /dev/null @@ -1,24 +0,0 @@ -* Broadcom BCM2835 SoC I2S/PCM module - -Required properties: -- compatible: "brcm,bcm2835-i2s" -- reg: Should contain PCM registers location and length. -- clocks: the (PCM) clock to use -- dmas: List of DMA controller phandle and DMA request line ordered pairs. -- dma-names: Identifier string for each DMA request line in the dmas property. - These strings correspond 1:1 with the ordered pairs in dmas. - - One of the DMA channels will be responsible for transmission (should be - named "tx") and one for reception (should be named "rx"). - -Example: - -bcm2835_i2s: i2s@7e203000 { - compatible = "brcm,bcm2835-i2s"; - reg = <0x7e203000 0x24>; - clocks = <&clocks BCM2835_CLOCK_PCM>; - - dmas = <&dma 2>, - <&dma 3>; - dma-names = "tx", "rx"; -}; diff --git a/Documentation/devicetree/bindings/sound/brcm,bcm2835-i2s.yaml b/Documentation/devicetree/bindings/sound/brcm,bcm2835-i2s.yaml new file mode 100644 index 000000000000..f3cfe92684d0 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/brcm,bcm2835-i2s.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/brcm,bcm2835-i2s.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Broadcom BCM2835 SoC I2S/PCM module + +maintainers: + - Florian Fainelli + +properties: + compatible: + const: brcm,bcm2835-i2s + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + dmas: + items: + - description: Transmission DMA controller phandle and request line. + - description: Reception DMA controller phandle and request line. + + dma-names: + items: + - const: tx + - const: rx + +required: + - compatible + - reg + - clocks + - dmas + - dma-names + +additionalProperties: false + +examples: + - | + #include + + i2s@7e203000 { + compatible = "brcm,bcm2835-i2s"; + reg = <0x7e203000 0x24>; + clocks = <&clocks BCM2835_CLOCK_PCM>; + dmas = <&dma 2>, <&dma 3>; + dma-names = "tx", "rx"; + }; From 22fb4ad898853323f4943de3e0dc555915547ccc Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Mon, 11 Aug 2025 20:25:19 +0800 Subject: [PATCH 00456/11391] 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 00457/11391] 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 00458/11391] 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 00459/11391] 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 3e2b799008a78c21c648328bed9f566335f0394e Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Mon, 4 Aug 2025 20:27:30 +0800 Subject: [PATCH 00460/11391] bpf: 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 Signed-off-by: Andrii Nakryiko Acked-by: Jiri Olsa Link: https://lore.kernel.org/bpf/20250804122731.460158-1-rongqianfeng@vivo.com --- kernel/bpf/devmap.c | 2 +- kernel/bpf/local_storage.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c index 482d284a1553..2625601de76e 100644 --- a/kernel/bpf/devmap.c +++ b/kernel/bpf/devmap.c @@ -865,7 +865,7 @@ static struct bpf_dtab_netdev *__dev_map_alloc_node(struct net *net, struct bpf_dtab_netdev *dev; dev = bpf_map_kmalloc_node(&dtab->map, sizeof(*dev), - GFP_NOWAIT | __GFP_NOWARN, + GFP_NOWAIT, dtab->map.numa_node); if (!dev) return ERR_PTR(-ENOMEM); diff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c index 632d51b05fe9..c93a756e035c 100644 --- a/kernel/bpf/local_storage.c +++ b/kernel/bpf/local_storage.c @@ -165,7 +165,7 @@ static long cgroup_storage_update_elem(struct bpf_map *map, void *key, } new = bpf_map_kmalloc_node(map, struct_size(new, data, map->value_size), - __GFP_ZERO | GFP_NOWAIT | __GFP_NOWARN, + __GFP_ZERO | GFP_NOWAIT, map->numa_node); if (!new) return -ENOMEM; From c93c59baa5ab57e94b874000cec56e26611b7a23 Mon Sep 17 00:00:00 2001 From: Paul Chaignon Date: Mon, 11 Aug 2025 20:58:20 +0200 Subject: [PATCH 00461/11391] bpf: Tidy verifier bug message Yonghong noticed that error messages for potential verifier bugs often have a '(1)' at the end. This is happening because verifier_bug_if(cond, env, fmt, args...) prints "(" #cond ")\n" as part of the message and verifier_bug() is defined as: #define verifier_bug(env, fmt, args...) verifier_bug_if(1, env, fmt, ##args) Hence, verifier_bug() always ends up displaying '(1)'. This small patch fixes it by having verifier_bug_if conditionally call verifier_bug instead of the other way around. Fixes: 1cb0f56d9618 ("bpf: WARN_ONCE on verifier bugs") Reported-by: Yonghong Song Signed-off-by: Paul Chaignon Signed-off-by: Andrii Nakryiko Tested-by: Eduard Zingerman Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/aJo9THBrzo8jFXsh@mail.gmail.com --- include/linux/bpf_verifier.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index c823f8efe3ed..020de62bd09c 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -875,13 +875,15 @@ __printf(3, 4) void verbose_linfo(struct bpf_verifier_env *env, #define verifier_bug_if(cond, env, fmt, args...) \ ({ \ bool __cond = (cond); \ - if (unlikely(__cond)) { \ - BPF_WARN_ONCE(1, "verifier bug: " fmt "(" #cond ")\n", ##args); \ - bpf_log(&env->log, "verifier bug: " fmt "(" #cond ")\n", ##args); \ - } \ + if (unlikely(__cond)) \ + verifier_bug(env, fmt " (" #cond ")", ##args); \ (__cond); \ }) -#define verifier_bug(env, fmt, args...) verifier_bug_if(1, env, fmt, ##args) +#define verifier_bug(env, fmt, args...) \ + ({ \ + BPF_WARN_ONCE(1, "verifier bug: " fmt "\n", ##args); \ + bpf_log(&env->log, "verifier bug: " fmt "\n", ##args); \ + }) static inline struct bpf_func_state *cur_func(struct bpf_verifier_env *env) { From f7cc3caea0005972162813e24892c49f2364f2fd Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Fri, 6 Jun 2025 14:48:40 -0700 Subject: [PATCH 00462/11391] .gitignore: ignore compile_commands.json globally compile_commands.json can be used with clangd to enable language server protocol-based assistance. For kernel itself this can be built with scripts/gen_compile_commands.py, but other projects (e.g., libbpf, or BPF selftests) can benefit from their own compilation database file, which can be generated successfully using external tools, like bear [0]. So, instead of adding compile_commands.json to .gitignore in respective individual projects, let's just ignore it globally anywhere in Linux repo. While at it, remove exactly such a local .gitignore rule under tools/power/cpupower. [0] https://github.com/rizsotto/Bear Reviewed-by: Nathan Chancellor Suggested-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Reviewed-by: Miguel Ojeda Link: https://lore.kernel.org/r/20250606214840.3165754-1-andrii@kernel.org Signed-off-by: Nathan Chancellor --- .gitignore | 2 +- tools/power/cpupower/.gitignore | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 929054df5212..86a1ba0d9035 100644 --- a/.gitignore +++ b/.gitignore @@ -176,7 +176,7 @@ x509.genkey *.kdev4 # Clang's compilation database file -/compile_commands.json +compile_commands.json # Documentation toolchain sphinx_*/ diff --git a/tools/power/cpupower/.gitignore b/tools/power/cpupower/.gitignore index 5113d5a7aee0..7677329c42a6 100644 --- a/tools/power/cpupower/.gitignore +++ b/tools/power/cpupower/.gitignore @@ -27,6 +27,3 @@ debug/i386/intel_gsic debug/i386/powernow-k8-decode debug/x86_64/centrino-decode debug/x86_64/powernow-k8-decode - -# Clang's compilation database file -compile_commands.json From bf0c2a84df9fb0f7779eb24c30198ef93f292e66 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Mon, 11 Aug 2025 20:39:49 +0800 Subject: [PATCH 00463/11391] bpf: Replace kvfree with kfree for kzalloc memory The 'backedge' pointer is allocated with kzalloc(), which returns physically contiguous memory. Using kvfree() to deallocate such memory is functionally safe but semantically incorrect. Replace kvfree() with kfree() to avoid unnecessary is_vmalloc_addr() check in kvfree(). Signed-off-by: Qianfeng Rong Signed-off-by: Andrii Nakryiko Acked-by: Eduard Zingerman Link: https://lore.kernel.org/bpf/20250811123949.552885-1-rongqianfeng@vivo.com --- kernel/bpf/verifier.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 3c2e7f36a09c..3a3982fe20d4 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -19553,7 +19553,7 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx) err = err ?: add_scc_backedge(env, &sl->state, backedge); if (err) { free_verifier_state(&backedge->state, false); - kvfree(backedge); + kfree(backedge); return err; } } From 524b2b76f365fb90a7f894ac17261ea760464e2c Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Mon, 4 Aug 2025 01:00:09 -0700 Subject: [PATCH 00464/11391] 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 00465/11391] 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 00466/11391] 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 00467/11391] 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 00468/11391] 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 b3ba7d929ce197ff2651046798b94bd62eb0e680 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 11 Aug 2025 18:40:38 +0200 Subject: [PATCH 00469/11391] net/sched: Remove redundant memset(0) call in reset_policy() The call to nla_strscpy() already zero-pads the tail of the destination buffer which makes the additional memset(0) call redundant. Remove it. Signed-off-by: Thorsten Blum Reviewed-by: Joe Damato Link: https://patch.msgid.link/20250811164039.43250-1-thorsten.blum@linux.dev Signed-off-by: Jakub Kicinski --- net/sched/act_simple.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c index f3abe0545989..8e69a919b4fe 100644 --- a/net/sched/act_simple.c +++ b/net/sched/act_simple.c @@ -72,7 +72,6 @@ static int reset_policy(struct tc_action *a, const struct nlattr *defdata, d = to_defact(a); spin_lock_bh(&d->tcf_lock); goto_ch = tcf_action_set_ctrlact(a, p->action, goto_ch); - memset(d->tcfd_defdata, 0, SIMP_MAX_DATA); nla_strscpy(d->tcfd_defdata, defdata, SIMP_MAX_DATA); spin_unlock_bh(&d->tcf_lock); if (goto_ch) From 75f26257667588260d067fa022ebd6ac39b4a9c1 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 11 Aug 2025 09:59:21 -0700 Subject: [PATCH 00470/11391] net: mdio: mdio-bcm-unimac: Refine incorrect clock message In light of a81649a4efd3 ("net: mdio: mdio-bcm-unimac: Correct rate fallback logic"), it became clear that the warning should be specific to the MDIO controller instance, and there should be further information provided to indicate what is wrong, whether the requested clock frequency or the rate calculation. Clarify the message accordingly. Signed-off-by: Florian Fainelli Link: https://patch.msgid.link/20250811165921.392030-1-florian.fainelli@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/mdio/mdio-bcm-unimac.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/mdio/mdio-bcm-unimac.c b/drivers/net/mdio/mdio-bcm-unimac.c index 7baab230008a..37e35f282d9a 100644 --- a/drivers/net/mdio/mdio-bcm-unimac.c +++ b/drivers/net/mdio/mdio-bcm-unimac.c @@ -215,7 +215,9 @@ static int unimac_mdio_clk_set(struct unimac_mdio_priv *priv) div = (rate / (2 * priv->clk_freq)) - 1; if (div & ~MDIO_CLK_DIV_MASK) { - pr_warn("Incorrect MDIO clock frequency, ignoring\n"); + dev_warn(priv->mii_bus->parent, + "Ignoring MDIO clock frequency request: %d vs. rate: %ld\n", + priv->clk_freq, rate); ret = 0; goto out; } From fa38524ca5a783aa0cfc8ffa5730c5012edfccf4 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Mon, 11 Aug 2025 11:13:25 -0700 Subject: [PATCH 00471/11391] netconsole: move netpoll_parse_ip_addr() earlier for reuse Move netpoll_parse_ip_addr() earlier in the file to be reused in other functions, such as local_ip_store(). This avoids duplicate address parsing logic and centralizes validation for both IPv4 and IPv6 string input. No functional changes intended. Signed-off-by: Breno Leitao Reviewed-by: Simon Horman Link: https://patch.msgid.link/20250811-netconsole_ref-v4-1-9c510d8713a2@debian.org Signed-off-by: Jakub Kicinski --- drivers/net/netconsole.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index e3722de08ea9..8d1b93264e0f 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -300,6 +300,26 @@ static void netconsole_print_banner(struct netpoll *np) np_info(np, "remote ethernet address %pM\n", np->remote_mac); } +static int netpoll_parse_ip_addr(const char *str, union inet_addr *addr) +{ + const char *end; + + if (!strchr(str, ':') && + in4_pton(str, -1, (void *)addr, -1, &end) > 0) { + if (!*end) + return 0; + } + if (in6_pton(str, -1, addr->in6.s6_addr, -1, &end) > 0) { +#if IS_ENABLED(CONFIG_IPV6) + if (!*end) + return 1; +#else + return -1; +#endif + } + return -1; +} + #ifdef CONFIG_NETCONSOLE_DYNAMIC /* @@ -1742,26 +1762,6 @@ static void write_msg(struct console *con, const char *msg, unsigned int len) spin_unlock_irqrestore(&target_list_lock, flags); } -static int netpoll_parse_ip_addr(const char *str, union inet_addr *addr) -{ - const char *end; - - if (!strchr(str, ':') && - in4_pton(str, -1, (void *)addr, -1, &end) > 0) { - if (!*end) - return 0; - } - if (in6_pton(str, -1, addr->in6.s6_addr, -1, &end) > 0) { -#if IS_ENABLED(CONFIG_IPV6) - if (!*end) - return 1; -#else - return -1; -#endif - } - return -1; -} - static int netconsole_parser_cmdline(struct netpoll *np, char *opt) { bool ipversion_set = false; From 364213b736e313fab963b272ebe5a2ffeb888831 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Mon, 11 Aug 2025 11:13:26 -0700 Subject: [PATCH 00472/11391] netconsole: add support for strings with new line in netpoll_parse_ip_addr The current IP address parsing logic fails when the input string contains a trailing newline character. This can occur when IP addresses are provided through configfs, which contains newlines in a const buffer. Teach netpoll_parse_ip_addr() how to ignore newlines at the end of the IPs. Also, simplify the code by: * No need to check for separators. Try to parse ipv4, if it fails try ipv6 similarly to ceph_pton() * If ipv6 is not supported, don't call in6_pton() at all. Signed-off-by: Breno Leitao Link: https://patch.msgid.link/20250811-netconsole_ref-v4-2-9c510d8713a2@debian.org Signed-off-by: Jakub Kicinski --- drivers/net/netconsole.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 8d1b93264e0f..2919522d963e 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -300,23 +300,30 @@ static void netconsole_print_banner(struct netpoll *np) np_info(np, "remote ethernet address %pM\n", np->remote_mac); } +/* Parse the string and populate the `inet_addr` union. Return 0 if IPv4 is + * populated, 1 if IPv6 is populated, and -1 upon failure. + */ static int netpoll_parse_ip_addr(const char *str, union inet_addr *addr) { - const char *end; + const char *end = NULL; + int len; - if (!strchr(str, ':') && - in4_pton(str, -1, (void *)addr, -1, &end) > 0) { - if (!*end) - return 0; - } - if (in6_pton(str, -1, addr->in6.s6_addr, -1, &end) > 0) { -#if IS_ENABLED(CONFIG_IPV6) - if (!*end) - return 1; -#else + len = strlen(str); + if (!len) return -1; -#endif - } + + if (str[len - 1] == '\n') + len -= 1; + + if (in4_pton(str, len, (void *)addr, -1, &end) > 0 && + (!end || *end == 0 || *end == '\n')) + return 0; + + if (IS_ENABLED(CONFIG_IPV6) && + in6_pton(str, len, (void *)addr, -1, &end) > 0 && + (!end || *end == 0 || *end == '\n')) + return 1; + return -1; } From 60cb69214148fbe7fc50239c28e4d052eec6ae61 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Mon, 11 Aug 2025 11:13:27 -0700 Subject: [PATCH 00473/11391] netconsole: use netpoll_parse_ip_addr in local_ip_store Replace manual IP address parsing with a call to netpoll_parse_ip_addr in local_ip_store(), simplifying the code and reducing the chance of errors. Also, remove the pr_err() if the user enters an invalid value in configfs entries. pr_err() is not the best way to alert user that the configuration is invalid. Signed-off-by: Breno Leitao Reviewed-by: Simon Horman Signed-off-by: Jakub Kicinski --- drivers/net/netconsole.c | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 2919522d963e..a9b30b5891d7 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -757,6 +757,7 @@ static ssize_t local_ip_store(struct config_item *item, const char *buf, { struct netconsole_target *nt = to_target(item); ssize_t ret = -EINVAL; + int ipv6; mutex_lock(&dynamic_netconsole_mutex); if (nt->enabled) { @@ -765,23 +766,10 @@ static ssize_t local_ip_store(struct config_item *item, const char *buf, goto out_unlock; } - if (strnchr(buf, count, ':')) { - const char *end; - - if (in6_pton(buf, count, nt->np.local_ip.in6.s6_addr, -1, &end) > 0) { - if (*end && *end != '\n') { - pr_err("invalid IPv6 address at: <%c>\n", *end); - goto out_unlock; - } - nt->np.ipv6 = true; - } else - goto out_unlock; - } else { - if (!nt->np.ipv6) - nt->np.local_ip.ip = in_aton(buf); - else - goto out_unlock; - } + ipv6 = netpoll_parse_ip_addr(buf, &nt->np.local_ip); + if (ipv6 == -1) + goto out_unlock; + nt->np.ipv6 = !!ipv6; ret = strnlen(buf, count); out_unlock: From 4aeb452c237afa6d7e8d09185bca6e34454ca333 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Mon, 11 Aug 2025 11:13:28 -0700 Subject: [PATCH 00474/11391] netconsole: use netpoll_parse_ip_addr in local_ip_store Replace manual IP address parsing with a call to netpoll_parse_ip_addr in remote_ip_store(), simplifying the code and reducing the chance of errors. The error message got removed, since it is not a good practice to pr_err() if used pass a wrong value in configfs. Signed-off-by: Breno Leitao Reviewed-by: Simon Horman Signed-off-by: Jakub Kicinski --- drivers/net/netconsole.c | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index a9b30b5891d7..194570443493 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -782,6 +782,7 @@ static ssize_t remote_ip_store(struct config_item *item, const char *buf, { struct netconsole_target *nt = to_target(item); ssize_t ret = -EINVAL; + int ipv6; mutex_lock(&dynamic_netconsole_mutex); if (nt->enabled) { @@ -790,23 +791,10 @@ static ssize_t remote_ip_store(struct config_item *item, const char *buf, goto out_unlock; } - if (strnchr(buf, count, ':')) { - const char *end; - - if (in6_pton(buf, count, nt->np.remote_ip.in6.s6_addr, -1, &end) > 0) { - if (*end && *end != '\n') { - pr_err("invalid IPv6 address at: <%c>\n", *end); - goto out_unlock; - } - nt->np.ipv6 = true; - } else - goto out_unlock; - } else { - if (!nt->np.ipv6) - nt->np.remote_ip.ip = in_aton(buf); - else - goto out_unlock; - } + ipv6 = netpoll_parse_ip_addr(buf, &nt->np.remote_ip); + if (ipv6 == -1) + goto out_unlock; + nt->np.ipv6 = !!ipv6; ret = strnlen(buf, count); out_unlock: From 942224e6baca0d1bdd1801e935f3544f2df37baf Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Mon, 11 Aug 2025 21:53:05 +0000 Subject: [PATCH 00475/11391] selftest: af_unix: Silence -Wflex-array-member-not-at-end warning for scm_inq.c. scm_inq.c has no problem in functionality, but when compiled with -Wflex-array-member-not-at-end, it shows this warning: scm_inq.c:15:24: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end] 15 | struct cmsghdr cmsghdr; | ^~~~~~~ Let's silence it. Signed-off-by: Kuniyuki Iwashima Link: https://patch.msgid.link/20250811215432.3379570-3-kuniyu@google.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/af_unix/scm_inq.c | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/tools/testing/selftests/net/af_unix/scm_inq.c b/tools/testing/selftests/net/af_unix/scm_inq.c index 9d22561e7b8f..fc467714387e 100644 --- a/tools/testing/selftests/net/af_unix/scm_inq.c +++ b/tools/testing/selftests/net/af_unix/scm_inq.c @@ -11,11 +11,6 @@ #define NR_CHUNKS 100 #define MSG_LEN 256 -struct scm_inq { - struct cmsghdr cmsghdr; - int inq; -}; - FIXTURE(scm_inq) { int fd[2]; @@ -70,35 +65,38 @@ static void send_chunks(struct __test_metadata *_metadata, static void recv_chunks(struct __test_metadata *_metadata, FIXTURE_DATA(scm_inq) *self) { + char cmsg_buf[CMSG_SPACE(sizeof(int))]; struct msghdr msg = {}; struct iovec iov = {}; - struct scm_inq cmsg; + struct cmsghdr *cmsg; char buf[MSG_LEN]; int i, ret; int inq; msg.msg_iov = &iov; msg.msg_iovlen = 1; - msg.msg_control = &cmsg; - msg.msg_controllen = CMSG_SPACE(sizeof(cmsg.inq)); + msg.msg_control = cmsg_buf; + msg.msg_controllen = sizeof(cmsg_buf); iov.iov_base = buf; iov.iov_len = sizeof(buf); for (i = 0; i < NR_CHUNKS; i++) { memset(buf, 0, sizeof(buf)); - memset(&cmsg, 0, sizeof(cmsg)); + memset(cmsg_buf, 0, sizeof(cmsg_buf)); ret = recvmsg(self->fd[1], &msg, 0); ASSERT_EQ(MSG_LEN, ret); - ASSERT_NE(NULL, CMSG_FIRSTHDR(&msg)); - ASSERT_EQ(CMSG_LEN(sizeof(cmsg.inq)), cmsg.cmsghdr.cmsg_len); - ASSERT_EQ(SOL_SOCKET, cmsg.cmsghdr.cmsg_level); - ASSERT_EQ(SCM_INQ, cmsg.cmsghdr.cmsg_type); + + cmsg = CMSG_FIRSTHDR(&msg); + ASSERT_NE(NULL, cmsg); + ASSERT_EQ(CMSG_LEN(sizeof(int)), cmsg->cmsg_len); + ASSERT_EQ(SOL_SOCKET, cmsg->cmsg_level); + ASSERT_EQ(SCM_INQ, cmsg->cmsg_type); ret = ioctl(self->fd[1], SIOCINQ, &inq); ASSERT_EQ(0, ret); - ASSERT_EQ(cmsg.inq, inq); + ASSERT_EQ(*(int *)CMSG_DATA(cmsg), inq); } } From 9a58d8e68252af07138a2530a22f081ef0b070c1 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Mon, 11 Aug 2025 21:53:06 +0000 Subject: [PATCH 00476/11391] selftest: af_unix: Silence -Wflex-array-member-not-at-end warning for scm_rights.c. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit scm_rights.c has no problem in functionality, but when compiled with -Wflex-array-member-not-at-end, it shows this warning: scm_rights.c: In function ‘__send_fd’: scm_rights.c:275:32: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end] 275 | struct cmsghdr cmsghdr; | ^~~~~~~ Let's silence it. Signed-off-by: Kuniyuki Iwashima Link: https://patch.msgid.link/20250811215432.3379570-4-kuniyu@google.com Signed-off-by: Jakub Kicinski --- .../selftests/net/af_unix/scm_rights.c | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/tools/testing/selftests/net/af_unix/scm_rights.c b/tools/testing/selftests/net/af_unix/scm_rights.c index 8b015f16c03d..914f99d153ce 100644 --- a/tools/testing/selftests/net/af_unix/scm_rights.c +++ b/tools/testing/selftests/net/af_unix/scm_rights.c @@ -271,20 +271,11 @@ void __send_fd(struct __test_metadata *_metadata, { #define MSG "x" #define MSGLEN 1 - struct { - struct cmsghdr cmsghdr; - int fd[2]; - } cmsg = { - .cmsghdr = { - .cmsg_len = CMSG_LEN(sizeof(cmsg.fd)), - .cmsg_level = SOL_SOCKET, - .cmsg_type = SCM_RIGHTS, - }, - .fd = { - self->fd[inflight * 2], - self->fd[inflight * 2], - }, + int fds[2] = { + self->fd[inflight * 2], + self->fd[inflight * 2], }; + char cmsg_buf[CMSG_SPACE(sizeof(fds))]; struct iovec iov = { .iov_base = MSG, .iov_len = MSGLEN, @@ -294,11 +285,18 @@ void __send_fd(struct __test_metadata *_metadata, .msg_namelen = 0, .msg_iov = &iov, .msg_iovlen = 1, - .msg_control = &cmsg, - .msg_controllen = CMSG_SPACE(sizeof(cmsg.fd)), + .msg_control = cmsg_buf, + .msg_controllen = sizeof(cmsg_buf), }; + struct cmsghdr *cmsg; int ret; + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fds)); + memcpy(CMSG_DATA(cmsg), fds, sizeof(fds)); + ret = sendmsg(self->fd[receiver * 2 + 1], &msg, variant->flags); if (variant->disabled) { From fd9faac372cc5f95ca537be5e3daf044c87ffae1 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Mon, 11 Aug 2025 21:53:07 +0000 Subject: [PATCH 00477/11391] selftest: af_unix: Silence -Wall warning for scm_pid.c. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -Wall found 2 unused variables in scm_pid.c: scm_pidfd.c: In function ‘parse_cmsg’: scm_pidfd.c:140:13: warning: unused variable ‘data’ [-Wunused-variable] 140 | int data = 0; | ^~~~ scm_pidfd.c: In function ‘cmsg_check_dead’: scm_pidfd.c:246:15: warning: unused variable ‘client_pid’ [-Wunused-variable] 246 | pid_t client_pid; | ^~~~~~~~~~ Let's remove these variables. Signed-off-by: Kuniyuki Iwashima Link: https://patch.msgid.link/20250811215432.3379570-5-kuniyu@google.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/af_unix/scm_pidfd.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/testing/selftests/net/af_unix/scm_pidfd.c b/tools/testing/selftests/net/af_unix/scm_pidfd.c index 37e034874034..ef2921988e5f 100644 --- a/tools/testing/selftests/net/af_unix/scm_pidfd.c +++ b/tools/testing/selftests/net/af_unix/scm_pidfd.c @@ -137,7 +137,6 @@ struct cmsg_data { static int parse_cmsg(struct msghdr *msg, struct cmsg_data *res) { struct cmsghdr *cmsg; - int data = 0; if (msg->msg_flags & (MSG_TRUNC | MSG_CTRUNC)) { log_err("recvmsg: truncated"); @@ -243,7 +242,6 @@ static int cmsg_check_dead(int fd, int expected_pid) int data = 0; char control[CMSG_SPACE(sizeof(struct ucred)) + CMSG_SPACE(sizeof(int))] = { 0 }; - pid_t client_pid; struct pidfd_info info = { .mask = PIDFD_INFO_EXIT, }; From 1838731f1072ce859ae3350547de4792f365760c Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Mon, 11 Aug 2025 21:53:04 +0000 Subject: [PATCH 00478/11391] selftest: af_unix: Add -Wall and -Wflex-array-member-not-at-end to CFLAGS. -Wall and -Wflex-array-member-not-at-end caught some warnings that will be fixed in later patches. Signed-off-by: Kuniyuki Iwashima Link: https://patch.msgid.link/20250811215432.3379570-2-kuniyu@google.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/af_unix/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/af_unix/Makefile b/tools/testing/selftests/net/af_unix/Makefile index a4b61c6d0290..0a20c98bbcfd 100644 --- a/tools/testing/selftests/net/af_unix/Makefile +++ b/tools/testing/selftests/net/af_unix/Makefile @@ -1,4 +1,4 @@ -CFLAGS += $(KHDR_INCLUDES) +CFLAGS += $(KHDR_INCLUDES) -Wall -Wflex-array-member-not-at-end TEST_GEN_PROGS := diag_uid msg_oob scm_inq scm_pidfd scm_rights unix_connect include ../../lib.mk From 07bbbfe7addf5b032e04f3c38f0b183d067a3f0d Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 11 Aug 2025 19:50:43 +0100 Subject: [PATCH 00479/11391] net: stmmac: add suspend()/resume() platform ops Add suspend/resume platform operations, which, when populated, override the init/exit platform operations when we suspend and resume. These suspend()/resume() methods are called by core code, and thus are designed to support any struct device, not just platform devices. This allows them to be used by the PCI drivers we have. Signed-off-by: Russell King (Oracle) Reviewed-by: Maxime Chevallier Link: https://patch.msgid.link/E1ulXbX-008gqZ-Bb@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 9 +++++++++ .../net/ethernet/stmicro/stmmac/stmmac_platform.c | 12 ++++++++---- include/linux/stmmac.h | 2 ++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index f1abf4242cd2..2da4f7bb2899 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -7879,6 +7879,9 @@ int stmmac_suspend(struct device *dev) if (stmmac_fpe_supported(priv)) ethtool_mmsv_stop(&priv->fpe_cfg.mmsv); + if (priv->plat->suspend) + return priv->plat->suspend(dev, priv->plat->bsp_priv); + return 0; } EXPORT_SYMBOL_GPL(stmmac_suspend); @@ -7931,6 +7934,12 @@ int stmmac_resume(struct device *dev) struct stmmac_priv *priv = netdev_priv(ndev); int ret; + if (priv->plat->resume) { + ret = priv->plat->resume(dev, priv->plat->bsp_priv); + if (ret) + return ret; + } + if (!netif_running(ndev)) return 0; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 030fcf1b5993..21df052eeed0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -901,7 +901,9 @@ static int __maybe_unused stmmac_pltfr_suspend(struct device *dev) struct platform_device *pdev = to_platform_device(dev); ret = stmmac_suspend(dev); - stmmac_pltfr_exit(pdev, priv->plat); + + if (!priv->plat->suspend) + stmmac_pltfr_exit(pdev, priv->plat); return ret; } @@ -920,9 +922,11 @@ static int __maybe_unused stmmac_pltfr_resume(struct device *dev) struct platform_device *pdev = to_platform_device(dev); int ret; - ret = stmmac_pltfr_init(pdev, priv->plat); - if (ret) - return ret; + if (!priv->plat->resume) { + ret = stmmac_pltfr_init(pdev, priv->plat); + if (ret) + return ret; + } return stmmac_resume(dev); } diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h index 26ddf95d23f9..22c24dacbc65 100644 --- a/include/linux/stmmac.h +++ b/include/linux/stmmac.h @@ -248,6 +248,8 @@ struct plat_stmmacenet_data { void (*ptp_clk_freq_config)(struct stmmac_priv *priv); int (*init)(struct platform_device *pdev, void *priv); void (*exit)(struct platform_device *pdev, void *priv); + int (*suspend)(struct device *dev, void *priv); + int (*resume)(struct device *dev, void *priv); struct mac_device_info *(*setup)(void *priv); int (*clks_config)(void *priv, bool enabled); int (*crosststamp)(ktime_t *device, struct system_counterval_t *system, From 7e84b3fae58c5425c324277268cad431ad181599 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 11 Aug 2025 19:50:48 +0100 Subject: [PATCH 00480/11391] net: stmmac: provide a set of simple PM ops Several drivers will want to make use of simple PM operations, so provide these from the core driver. Signed-off-by: Russell King (Oracle) Reviewed-by: Maxime Chevallier Link: https://patch.msgid.link/E1ulXbc-008gqf-GJ@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/stmmac.h | 2 ++ drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 3 +++ 2 files changed, 5 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index cda09cf5dcca..bf95f03dd33f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -374,6 +374,8 @@ enum stmmac_state { STMMAC_SERVICE_SCHED, }; +extern const struct dev_pm_ops stmmac_simple_pm_ops; + int stmmac_mdio_unregister(struct net_device *ndev); int stmmac_mdio_register(struct net_device *ndev); int stmmac_mdio_reset(struct mii_bus *mii); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 2da4f7bb2899..4a82045ea6eb 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -8013,6 +8013,9 @@ int stmmac_resume(struct device *dev) } EXPORT_SYMBOL_GPL(stmmac_resume); +EXPORT_GPL_SIMPLE_DEV_PM_OPS(stmmac_simple_pm_ops, stmmac_suspend, + stmmac_resume); + #ifndef MODULE static int __init stmmac_cmdline_opt(char *str) { From b51f34bc85e3b8c24f091a8e216b28213758021d Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 11 Aug 2025 19:50:53 +0100 Subject: [PATCH 00481/11391] net: stmmac: platform: legacy hooks for suspend()/resume() methods Add legacy hooks for the suspend() and resume() methods to forward these calls to the init() and exit() methods when the platform code hasn't populated the two former methods. This allows us to get rid of stmmac_pltfr_suspend() and stmmac_pltfr_resume(). Signed-off-by: Russell King (Oracle) Reviewed-by: Maxime Chevallier Link: https://patch.msgid.link/E1ulXbh-008gql-LO@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- .../ethernet/stmicro/stmmac/stmmac_platform.c | 68 ++++++------------- 1 file changed, 22 insertions(+), 46 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 21df052eeed0..c849676d98e8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -811,6 +811,22 @@ static void stmmac_pltfr_exit(struct platform_device *pdev, plat->exit(pdev, plat->bsp_priv); } +static int stmmac_plat_suspend(struct device *dev, void *bsp_priv) +{ + struct stmmac_priv *priv = netdev_priv(dev_get_drvdata(dev)); + + stmmac_pltfr_exit(to_platform_device(dev), priv->plat); + + return 0; +} + +static int stmmac_plat_resume(struct device *dev, void *bsp_priv) +{ + struct stmmac_priv *priv = netdev_priv(dev_get_drvdata(dev)); + + return stmmac_pltfr_init(to_platform_device(dev), priv->plat); +} + /** * stmmac_pltfr_probe * @pdev: platform device pointer @@ -825,6 +841,11 @@ int stmmac_pltfr_probe(struct platform_device *pdev, { int ret; + if (!plat->suspend && plat->exit) + plat->suspend = stmmac_plat_suspend; + if (!plat->resume && plat->init) + plat->resume = stmmac_plat_resume; + ret = stmmac_pltfr_init(pdev, plat); if (ret) return ret; @@ -886,51 +907,6 @@ void stmmac_pltfr_remove(struct platform_device *pdev) } EXPORT_SYMBOL_GPL(stmmac_pltfr_remove); -/** - * stmmac_pltfr_suspend - * @dev: device pointer - * Description: this function is invoked when suspend the driver and it direcly - * call the main suspend function and then, if required, on some platform, it - * can call an exit helper. - */ -static int __maybe_unused stmmac_pltfr_suspend(struct device *dev) -{ - int ret; - struct net_device *ndev = dev_get_drvdata(dev); - struct stmmac_priv *priv = netdev_priv(ndev); - struct platform_device *pdev = to_platform_device(dev); - - ret = stmmac_suspend(dev); - - if (!priv->plat->suspend) - stmmac_pltfr_exit(pdev, priv->plat); - - return ret; -} - -/** - * stmmac_pltfr_resume - * @dev: device pointer - * Description: this function is invoked when resume the driver before calling - * the main resume function, on some platforms, it can call own init helper - * if required. - */ -static int __maybe_unused stmmac_pltfr_resume(struct device *dev) -{ - struct net_device *ndev = dev_get_drvdata(dev); - struct stmmac_priv *priv = netdev_priv(ndev); - struct platform_device *pdev = to_platform_device(dev); - int ret; - - if (!priv->plat->resume) { - ret = stmmac_pltfr_init(pdev, priv->plat); - if (ret) - return ret; - } - - return stmmac_resume(dev); -} - static int __maybe_unused stmmac_runtime_suspend(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); @@ -998,7 +974,7 @@ static int __maybe_unused stmmac_pltfr_noirq_resume(struct device *dev) } const struct dev_pm_ops stmmac_pltfr_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(stmmac_pltfr_suspend, stmmac_pltfr_resume) + SET_SYSTEM_SLEEP_PM_OPS(stmmac_suspend, stmmac_resume) SET_RUNTIME_PM_OPS(stmmac_runtime_suspend, stmmac_runtime_resume, NULL) SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(stmmac_pltfr_noirq_suspend, stmmac_pltfr_noirq_resume) }; From 062b428017332adf8cee09612db2ae0495b4eb4e Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 11 Aug 2025 19:50:58 +0100 Subject: [PATCH 00482/11391] net: stmmac: intel: convert to suspend()/resume() methods Convert intel to use the new suspend() and resume() methods rather than implementing these in custom wrappers around the main driver's suspend/resume methods. This allows this driver to use the stmmac simple PM ops structure. Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1ulXbm-008gqs-P9@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- .../net/ethernet/stmicro/stmmac/dwmac-intel.c | 74 +++++++++---------- 1 file changed, 35 insertions(+), 39 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c index ea33ae39be6b..3fac3945cbfa 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c @@ -1231,6 +1231,37 @@ static int stmmac_config_multi_msi(struct pci_dev *pdev, return 0; } +static int intel_eth_pci_suspend(struct device *dev, void *bsp_priv) +{ + struct pci_dev *pdev = to_pci_dev(dev); + int ret; + + ret = pci_save_state(pdev); + if (ret) + return ret; + + pci_wake_from_d3(pdev, true); + pci_set_power_state(pdev, PCI_D3hot); + return 0; +} + +static int intel_eth_pci_resume(struct device *dev, void *bsp_priv) +{ + struct pci_dev *pdev = to_pci_dev(dev); + int ret; + + pci_restore_state(pdev); + pci_set_power_state(pdev, PCI_D0); + + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + pci_set_master(pdev); + + return 0; +} + /** * intel_eth_pci_probe * @@ -1292,6 +1323,9 @@ static int intel_eth_pci_probe(struct pci_dev *pdev, pci_set_master(pdev); plat->bsp_priv = intel_priv; + plat->suspend = intel_eth_pci_suspend; + plat->resume = intel_eth_pci_resume; + intel_priv->mdio_adhoc_addr = INTEL_MGBE_ADHOC_ADDR; intel_priv->crossts_adj = 1; @@ -1355,44 +1389,6 @@ static void intel_eth_pci_remove(struct pci_dev *pdev) clk_unregister_fixed_rate(priv->plat->stmmac_clk); } -static int __maybe_unused intel_eth_pci_suspend(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - int ret; - - ret = stmmac_suspend(dev); - if (ret) - return ret; - - ret = pci_save_state(pdev); - if (ret) - return ret; - - pci_wake_from_d3(pdev, true); - pci_set_power_state(pdev, PCI_D3hot); - return 0; -} - -static int __maybe_unused intel_eth_pci_resume(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - int ret; - - pci_restore_state(pdev); - pci_set_power_state(pdev, PCI_D0); - - ret = pcim_enable_device(pdev); - if (ret) - return ret; - - pci_set_master(pdev); - - return stmmac_resume(dev); -} - -static SIMPLE_DEV_PM_OPS(intel_eth_pm_ops, intel_eth_pci_suspend, - intel_eth_pci_resume); - #define PCI_DEVICE_ID_INTEL_QUARK 0x0937 #define PCI_DEVICE_ID_INTEL_EHL_RGMII1G 0x4b30 #define PCI_DEVICE_ID_INTEL_EHL_SGMII1G 0x4b31 @@ -1442,7 +1438,7 @@ static struct pci_driver intel_eth_pci_driver = { .probe = intel_eth_pci_probe, .remove = intel_eth_pci_remove, .driver = { - .pm = &intel_eth_pm_ops, + .pm = &stmmac_simple_pm_ops, }, }; From 38772638d6d1989655f5a05b273dc62a026e0ef1 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 11 Aug 2025 19:51:04 +0100 Subject: [PATCH 00483/11391] net: stmmac: loongson: convert to suspend()/resume() methods Convert loongson to use the new suspend() and resume() methods rather than implementing these in custom wrappers around the main driver's suspend/resume methods. This allows this driver to use the stmmac simple PM ops structure. Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1ulXbs-008gqy-16@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- .../ethernet/stmicro/stmmac/dwmac-loongson.c | 73 +++++++++---------- 1 file changed, 34 insertions(+), 39 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c index e1591e6217d4..5769165ee5ba 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c @@ -521,6 +521,37 @@ static int loongson_dwmac_fix_reset(void *priv, void __iomem *ioaddr) 10000, 2000000); } +static int loongson_dwmac_suspend(struct device *dev, void *bsp_priv) +{ + struct pci_dev *pdev = to_pci_dev(dev); + int ret; + + ret = pci_save_state(pdev); + if (ret) + return ret; + + pci_disable_device(pdev); + pci_wake_from_d3(pdev, true); + return 0; +} + +static int loongson_dwmac_resume(struct device *dev, void *bsp_priv) +{ + struct pci_dev *pdev = to_pci_dev(dev); + int ret; + + pci_restore_state(pdev); + pci_set_power_state(pdev, PCI_D0); + + ret = pci_enable_device(pdev); + if (ret) + return ret; + + pci_set_master(pdev); + + return 0; +} + static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct plat_stmmacenet_data *plat; @@ -565,6 +596,8 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id plat->bsp_priv = ld; plat->setup = loongson_dwmac_setup; plat->fix_soc_reset = loongson_dwmac_fix_reset; + plat->suspend = loongson_dwmac_suspend; + plat->resume = loongson_dwmac_resume; ld->dev = &pdev->dev; ld->loongson_id = readl(res.addr + GMAC_VERSION) & 0xff; @@ -621,44 +654,6 @@ static void loongson_dwmac_remove(struct pci_dev *pdev) pci_disable_device(pdev); } -static int __maybe_unused loongson_dwmac_suspend(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - int ret; - - ret = stmmac_suspend(dev); - if (ret) - return ret; - - ret = pci_save_state(pdev); - if (ret) - return ret; - - pci_disable_device(pdev); - pci_wake_from_d3(pdev, true); - return 0; -} - -static int __maybe_unused loongson_dwmac_resume(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - int ret; - - pci_restore_state(pdev); - pci_set_power_state(pdev, PCI_D0); - - ret = pci_enable_device(pdev); - if (ret) - return ret; - - pci_set_master(pdev); - - return stmmac_resume(dev); -} - -static SIMPLE_DEV_PM_OPS(loongson_dwmac_pm_ops, loongson_dwmac_suspend, - loongson_dwmac_resume); - static const struct pci_device_id loongson_dwmac_id_table[] = { { PCI_DEVICE_DATA(LOONGSON, GMAC1, &loongson_gmac_pci_info) }, { PCI_DEVICE_DATA(LOONGSON, GMAC2, &loongson_gmac_pci_info) }, @@ -673,7 +668,7 @@ static struct pci_driver loongson_dwmac_driver = { .probe = loongson_dwmac_probe, .remove = loongson_dwmac_remove, .driver = { - .pm = &loongson_dwmac_pm_ops, + .pm = &stmmac_simple_pm_ops, }, }; From c91918a1e9767fc40488f69436f61af90221615b Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 11 Aug 2025 19:51:09 +0100 Subject: [PATCH 00484/11391] net: stmmac: pci: convert to suspend()/resume() methods Convert pci to use the new suspend() and resume() methods rather than implementing these in custom wrappers around the main driver's suspend/resume methods. Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1ulXbx-008gr4-5H@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- .../net/ethernet/stmicro/stmmac/stmmac_pci.c | 73 +++++++++---------- 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c index 9c1b54b701f7..e6a7d0ddac2a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c @@ -138,6 +138,37 @@ static const struct stmmac_pci_info snps_gmac5_pci_info = { .setup = snps_gmac5_default_data, }; +static int stmmac_pci_suspend(struct device *dev, void *bsp_priv) +{ + struct pci_dev *pdev = to_pci_dev(dev); + int ret; + + ret = pci_save_state(pdev); + if (ret) + return ret; + + pci_disable_device(pdev); + pci_wake_from_d3(pdev, true); + return 0; +} + +static int stmmac_pci_resume(struct device *dev, void *bsp_priv) +{ + struct pci_dev *pdev = to_pci_dev(dev); + int ret; + + pci_restore_state(pdev); + pci_set_power_state(pdev, PCI_D0); + + ret = pci_enable_device(pdev); + if (ret) + return ret; + + pci_set_master(pdev); + + return 0; +} + /** * stmmac_pci_probe * @@ -217,6 +248,9 @@ static int stmmac_pci_probe(struct pci_dev *pdev, plat->safety_feat_cfg->prtyen = 1; plat->safety_feat_cfg->tmouten = 1; + plat->suspend = stmmac_pci_suspend; + plat->resume = stmmac_pci_resume; + return stmmac_dvr_probe(&pdev->dev, plat, &res); } @@ -231,43 +265,6 @@ static void stmmac_pci_remove(struct pci_dev *pdev) stmmac_dvr_remove(&pdev->dev); } -static int __maybe_unused stmmac_pci_suspend(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - int ret; - - ret = stmmac_suspend(dev); - if (ret) - return ret; - - ret = pci_save_state(pdev); - if (ret) - return ret; - - pci_disable_device(pdev); - pci_wake_from_d3(pdev, true); - return 0; -} - -static int __maybe_unused stmmac_pci_resume(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - int ret; - - pci_restore_state(pdev); - pci_set_power_state(pdev, PCI_D0); - - ret = pci_enable_device(pdev); - if (ret) - return ret; - - pci_set_master(pdev); - - return stmmac_resume(dev); -} - -static SIMPLE_DEV_PM_OPS(stmmac_pm_ops, stmmac_pci_suspend, stmmac_pci_resume); - /* synthetic ID, no official vendor */ #define PCI_VENDOR_ID_STMMAC 0x0700 @@ -289,7 +286,7 @@ static struct pci_driver stmmac_pci_driver = { .probe = stmmac_pci_probe, .remove = stmmac_pci_remove, .driver = { - .pm = &stmmac_pm_ops, + .pm = &stmmac_simple_pm_ops, }, }; From d7a276a5768ffe4f3dbcb0a2d9d037f117b53784 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 11 Aug 2025 19:51:14 +0100 Subject: [PATCH 00485/11391] net: stmmac: rk: convert to suspend()/resume() methods Convert rk to use the new suspend() and resume() methods rather than implementing these in custom wrappers around the main driver's suspend/resume methods. This allows this driver to use the simmac simple PM ops structure. We can further simplify the driver as there is no need to track whether the device was suspended, we only need to check whether the device is wakeup capable in the resume method. This is because the resume method will only be called after the suspend method. Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1ulXc2-008grB-9k@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- .../net/ethernet/stmicro/stmmac/dwmac-rk.c | 58 ++++++++----------- 1 file changed, 25 insertions(+), 33 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c index 79b92130a03f..ac8288301994 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c @@ -71,7 +71,6 @@ struct rk_priv_data { phy_interface_t phy_iface; int id; struct regulator *regulator; - bool suspended; const struct rk_gmac_ops *ops; bool clk_enabled; @@ -1706,6 +1705,28 @@ static int rk_set_clk_tx_rate(void *bsp_priv_, struct clk *clk_tx_i, return -EINVAL; } +static int rk_gmac_suspend(struct device *dev, void *bsp_priv_) +{ + struct rk_priv_data *bsp_priv = bsp_priv_; + + /* Keep the PHY up if we use Wake-on-Lan. */ + if (!device_may_wakeup(dev)) + rk_gmac_powerdown(bsp_priv); + + return 0; +} + +static int rk_gmac_resume(struct device *dev, void *bsp_priv_) +{ + struct rk_priv_data *bsp_priv = bsp_priv_; + + /* The PHY was up for Wake-on-Lan. */ + if (!device_may_wakeup(dev)) + rk_gmac_powerup(bsp_priv); + + return 0; +} + static int rk_gmac_probe(struct platform_device *pdev) { struct plat_stmmacenet_data *plat_dat; @@ -1738,6 +1759,8 @@ static int rk_gmac_probe(struct platform_device *pdev) plat_dat->get_interfaces = rk_get_interfaces; plat_dat->set_clk_tx_rate = rk_set_clk_tx_rate; + plat_dat->suspend = rk_gmac_suspend; + plat_dat->resume = rk_gmac_resume; plat_dat->bsp_priv = rk_gmac_setup(pdev, plat_dat, data); if (IS_ERR(plat_dat->bsp_priv)) @@ -1772,37 +1795,6 @@ static void rk_gmac_remove(struct platform_device *pdev) rk_gmac_powerdown(bsp_priv); } -#ifdef CONFIG_PM_SLEEP -static int rk_gmac_suspend(struct device *dev) -{ - struct rk_priv_data *bsp_priv = get_stmmac_bsp_priv(dev); - int ret = stmmac_suspend(dev); - - /* Keep the PHY up if we use Wake-on-Lan. */ - if (!device_may_wakeup(dev)) { - rk_gmac_powerdown(bsp_priv); - bsp_priv->suspended = true; - } - - return ret; -} - -static int rk_gmac_resume(struct device *dev) -{ - struct rk_priv_data *bsp_priv = get_stmmac_bsp_priv(dev); - - /* The PHY was up for Wake-on-Lan. */ - if (bsp_priv->suspended) { - rk_gmac_powerup(bsp_priv); - bsp_priv->suspended = false; - } - - return stmmac_resume(dev); -} -#endif /* CONFIG_PM_SLEEP */ - -static SIMPLE_DEV_PM_OPS(rk_gmac_pm_ops, rk_gmac_suspend, rk_gmac_resume); - static const struct of_device_id rk_gmac_dwmac_match[] = { { .compatible = "rockchip,px30-gmac", .data = &px30_ops }, { .compatible = "rockchip,rk3128-gmac", .data = &rk3128_ops }, @@ -1828,7 +1820,7 @@ static struct platform_driver rk_gmac_dwmac_driver = { .remove = rk_gmac_remove, .driver = { .name = "rk_gmac-dwmac", - .pm = &rk_gmac_pm_ops, + .pm = &stmmac_simple_pm_ops, .of_match_table = rk_gmac_dwmac_match, }, }; From c7308b2f3d0d045005bc9d2110ac5d5085a4fe0c Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 11 Aug 2025 19:51:19 +0100 Subject: [PATCH 00486/11391] net: stmmac: stm32: convert to suspend()/resume() methods Convert stm32 to use the new suspend() and resume() methods rather than implementing these in custom wrappers around the main driver's suspend/resume methods. This allows this driver to use the stmmac simple PM ops structure. Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1ulXc7-008grH-Dh@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- .../net/ethernet/stmicro/stmmac/dwmac-stm32.c | 68 +++++++------------ 1 file changed, 23 insertions(+), 45 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c index 1eb16eec9c0d..77a04c4579c9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c @@ -498,6 +498,26 @@ static int stm32mp1_parse_data(struct stm32_dwmac *dwmac, return err; } +static int stm32_dwmac_suspend(struct device *dev, void *bsp_priv) +{ + struct stm32_dwmac *dwmac = bsp_priv; + + stm32_dwmac_clk_disable(dwmac); + + return dwmac->ops->suspend ? dwmac->ops->suspend(dwmac) : 0; +} + +static int stm32_dwmac_resume(struct device *dev, void *bsp_priv) +{ + struct stmmac_priv *priv = netdev_priv(dev_get_drvdata(dev)); + struct stm32_dwmac *dwmac = bsp_priv; + + if (dwmac->ops->resume) + dwmac->ops->resume(dwmac); + + return stm32_dwmac_init(priv->plat); +} + static int stm32_dwmac_probe(struct platform_device *pdev) { struct plat_stmmacenet_data *plat_dat; @@ -535,6 +555,8 @@ static int stm32_dwmac_probe(struct platform_device *pdev) plat_dat->flags |= STMMAC_FLAG_EN_TX_LPI_CLK_PHY_CAP; plat_dat->bsp_priv = dwmac; + plat_dat->suspend = stm32_dwmac_suspend; + plat_dat->resume = stm32_dwmac_resume; ret = stm32_dwmac_init(plat_dat); if (ret) @@ -600,50 +622,6 @@ static void stm32mp1_resume(struct stm32_dwmac *dwmac) clk_disable_unprepare(dwmac->clk_ethstp); } -#ifdef CONFIG_PM_SLEEP -static int stm32_dwmac_suspend(struct device *dev) -{ - struct net_device *ndev = dev_get_drvdata(dev); - struct stmmac_priv *priv = netdev_priv(ndev); - struct stm32_dwmac *dwmac = priv->plat->bsp_priv; - - int ret; - - ret = stmmac_suspend(dev); - if (ret) - return ret; - - stm32_dwmac_clk_disable(dwmac); - - if (dwmac->ops->suspend) - ret = dwmac->ops->suspend(dwmac); - - return ret; -} - -static int stm32_dwmac_resume(struct device *dev) -{ - struct net_device *ndev = dev_get_drvdata(dev); - struct stmmac_priv *priv = netdev_priv(ndev); - struct stm32_dwmac *dwmac = priv->plat->bsp_priv; - int ret; - - if (dwmac->ops->resume) - dwmac->ops->resume(dwmac); - - ret = stm32_dwmac_init(priv->plat); - if (ret) - return ret; - - ret = stmmac_resume(dev); - - return ret; -} -#endif /* CONFIG_PM_SLEEP */ - -static SIMPLE_DEV_PM_OPS(stm32_dwmac_pm_ops, - stm32_dwmac_suspend, stm32_dwmac_resume); - static struct stm32_ops stm32mcu_dwmac_data = { .set_mode = stm32mcu_set_mode }; @@ -691,7 +669,7 @@ static struct platform_driver stm32_dwmac_driver = { .remove = stm32_dwmac_remove, .driver = { .name = "stm32-dwmac", - .pm = &stm32_dwmac_pm_ops, + .pm = &stmmac_simple_pm_ops, .of_match_table = stm32_dwmac_match, }, }; From d6e1f2272960cdb5081e9318d6a04de478d80400 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 11 Aug 2025 19:51:24 +0100 Subject: [PATCH 00487/11391] net: stmmac: mediatek: convert to resume() method Convert mediatek to use the resume() platform method rather than the init() platform method as mediatek_dwmac_init() is only called from the resume paths. This will ensure that in a future commit, mediatek_dwmac_init() won't be called when probing the main part of the stmmac driver. Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1ulXcC-008grN-Hc@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c index 39421d6a34e4..f1b36f0a401d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c @@ -523,7 +523,7 @@ static int mediatek_dwmac_clk_init(struct mediatek_dwmac_plat_data *plat) return ret; } -static int mediatek_dwmac_init(struct platform_device *pdev, void *priv) +static int mediatek_dwmac_init(struct device *dev, void *priv) { struct mediatek_dwmac_plat_data *plat = priv; const struct mediatek_dwmac_variant *variant = plat->variant; @@ -532,7 +532,7 @@ static int mediatek_dwmac_init(struct platform_device *pdev, void *priv) if (variant->dwmac_set_phy_interface) { ret = variant->dwmac_set_phy_interface(plat); if (ret) { - dev_err(plat->dev, "failed to set phy interface, err = %d\n", ret); + dev_err(dev, "failed to set phy interface, err = %d\n", ret); return ret; } } @@ -540,7 +540,7 @@ static int mediatek_dwmac_init(struct platform_device *pdev, void *priv) if (variant->dwmac_set_delay) { ret = variant->dwmac_set_delay(plat); if (ret) { - dev_err(plat->dev, "failed to set delay value, err = %d\n", ret); + dev_err(dev, "failed to set delay value, err = %d\n", ret); return ret; } } @@ -589,7 +589,7 @@ static int mediatek_dwmac_common_data(struct platform_device *pdev, plat->maxmtu = ETH_DATA_LEN; plat->host_dma_width = priv_plat->variant->dma_bit_mask; plat->bsp_priv = priv_plat; - plat->init = mediatek_dwmac_init; + plat->resume = mediatek_dwmac_init; plat->clks_config = mediatek_dwmac_clks_config; plat->safety_feat_cfg = devm_kzalloc(&pdev->dev, @@ -654,7 +654,7 @@ static int mediatek_dwmac_probe(struct platform_device *pdev) return PTR_ERR(plat_dat); mediatek_dwmac_common_data(pdev, plat_dat, priv_plat); - mediatek_dwmac_init(pdev, priv_plat); + mediatek_dwmac_init(&pdev->dev, priv_plat); ret = mediatek_dwmac_clks_config(priv_plat, true); if (ret) From 27e5b560a86e479bef247a1327182d155ed0bad6 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 11 Aug 2025 16:13:30 -0700 Subject: [PATCH 00488/11391] selftests: drv-net: add configs for zerocopy Rx Looks like neither IO_URING nor UDMABUF are enabled even tho iou-zcrx.py and devmem.py (respectively) need those. IO_URING gets enabled by default but UDMABUF is missing. Reviewed-by: Joe Damato Reviewed-by: Mina Almasry Acked-by: Stanislav Fomichev Link: https://patch.msgid.link/20250811231334.561137-2-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/drivers/net/hw/config | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/testing/selftests/drivers/net/hw/config b/tools/testing/selftests/drivers/net/hw/config index 88ae719e6f8f..e8a06aa1471c 100644 --- a/tools/testing/selftests/drivers/net/hw/config +++ b/tools/testing/selftests/drivers/net/hw/config @@ -1,5 +1,7 @@ +CONFIG_IO_URING=y CONFIG_IPV6=y CONFIG_IPV6_GRE=y CONFIG_NET_IPGRE=y CONFIG_NET_IPGRE_DEMUX=y +CONFIG_UDMABUF=y CONFIG_VXLAN=y From a94e9cf79ceee04c3e2d042fdf417b8c235c6117 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 11 Aug 2025 16:13:31 -0700 Subject: [PATCH 00489/11391] selftests: drv-net: devmem: remove sudo from system() calls The general expectations for network HW selftests is that they will be run as root. sudo doesn't seem to work on NIPA VMs. While it's probably something solvable in the setup I think we should remove the sudos. devmem is the only networking test using sudo. Reviewed-by: Joe Damato Reviewed-by: Mina Almasry Acked-by: Stanislav Fomichev Link: https://patch.msgid.link/20250811231334.561137-3-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/drivers/net/hw/ncdevmem.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/testing/selftests/drivers/net/hw/ncdevmem.c b/tools/testing/selftests/drivers/net/hw/ncdevmem.c index 72f828021f83..be937542b4c0 100644 --- a/tools/testing/selftests/drivers/net/hw/ncdevmem.c +++ b/tools/testing/selftests/drivers/net/hw/ncdevmem.c @@ -287,10 +287,10 @@ static int reset_flow_steering(void) * the exit status. */ - run_command("sudo ethtool -K %s ntuple off >&2", ifname); - run_command("sudo ethtool -K %s ntuple on >&2", ifname); + run_command("ethtool -K %s ntuple off >&2", ifname); + run_command("ethtool -K %s ntuple on >&2", ifname); run_command( - "sudo ethtool -n %s | grep 'Filter:' | awk '{print $2}' | xargs -n1 ethtool -N %s delete >&2", + "ethtool -n %s | grep 'Filter:' | awk '{print $2}' | xargs -n1 ethtool -N %s delete >&2", ifname, ifname); return 0; } @@ -351,12 +351,12 @@ static int configure_headersplit(bool on) static int configure_rss(void) { - return run_command("sudo ethtool -X %s equal %d >&2", ifname, start_queue); + return run_command("ethtool -X %s equal %d >&2", ifname, start_queue); } static int configure_channels(unsigned int rx, unsigned int tx) { - return run_command("sudo ethtool -L %s rx %u tx %u", ifname, rx, tx); + return run_command("ethtool -L %s rx %u tx %u", ifname, rx, tx); } static int configure_flow_steering(struct sockaddr_in6 *server_sin) @@ -374,7 +374,7 @@ static int configure_flow_steering(struct sockaddr_in6 *server_sin) } /* Try configure 5-tuple */ - if (run_command("sudo ethtool -N %s flow-type %s %s %s dst-ip %s %s %s dst-port %s queue %d >&2", + if (run_command("ethtool -N %s flow-type %s %s %s dst-ip %s %s %s dst-port %s queue %d >&2", ifname, type, client_ip ? "src-ip" : "", @@ -384,7 +384,7 @@ static int configure_flow_steering(struct sockaddr_in6 *server_sin) client_ip ? port : "", port, start_queue)) /* If that fails, try configure 3-tuple */ - if (run_command("sudo ethtool -N %s flow-type %s dst-ip %s dst-port %s queue %d >&2", + if (run_command("ethtool -N %s flow-type %s dst-ip %s dst-port %s queue %d >&2", ifname, type, server_addr, From 424e96de30230aac2061f941961be645cf0070d5 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 11 Aug 2025 16:13:32 -0700 Subject: [PATCH 00490/11391] selftests: drv-net: devmem: add / correct the IPv6 support We need to use bracketed IPv6 addresses for socat. Reviewed-by: Joe Damato Reviewed-by: Mina Almasry Acked-by: Stanislav Fomichev Link: https://patch.msgid.link/20250811231334.561137-4-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/drivers/net/hw/devmem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/drivers/net/hw/devmem.py b/tools/testing/selftests/drivers/net/hw/devmem.py index baa2f24240ba..0a2533a3d6d6 100755 --- a/tools/testing/selftests/drivers/net/hw/devmem.py +++ b/tools/testing/selftests/drivers/net/hw/devmem.py @@ -24,7 +24,7 @@ def check_rx(cfg) -> None: require_devmem(cfg) port = rand_port() - socat = f"socat -u - TCP{cfg.addr_ipver}:{cfg.addr}:{port},bind={cfg.remote_addr}:{port}" + socat = f"socat -u - TCP{cfg.addr_ipver}:{cfg.baddr}:{port},bind={cfg.remote_baddr}:{port}" listen_cmd = f"{cfg.bin_local} -l -f {cfg.ifname} -s {cfg.addr} -p {port} -c {cfg.remote_addr} -v 7" with bkg(listen_cmd, exit_wait=True) as ncdevmem: From 6e9a12f85a7567bb9a41d5230468886bd6a27b20 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 11 Aug 2025 16:13:33 -0700 Subject: [PATCH 00491/11391] selftests: net: terminate bkg() commands on exception There is a number of: with bkg("socat ..LISTEN..", exit_wait=True) uses in the tests. If whatever is supposed to send the traffic fails we will get stuck in the bkg(). Try to kill the process in case of exception, to avoid the long wait. A specific example where this happens is the devmem Tx tests. Reviewed-by: Joe Damato Acked-by: Stanislav Fomichev Link: https://patch.msgid.link/20250811231334.561137-5-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/lib/py/utils.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/lib/py/utils.py b/tools/testing/selftests/net/lib/py/utils.py index f395c90fb0f1..4ac9249c85ab 100644 --- a/tools/testing/selftests/net/lib/py/utils.py +++ b/tools/testing/selftests/net/lib/py/utils.py @@ -117,6 +117,7 @@ class bkg(cmd): shell=shell, fail=fail, ns=ns, host=host, ksft_wait=ksft_wait) self.terminate = not exit_wait and not ksft_wait + self._exit_wait = exit_wait self.check_fail = fail if shell and self.terminate: @@ -127,7 +128,9 @@ class bkg(cmd): return self def __exit__(self, ex_type, ex_value, ex_tb): - return self.process(terminate=self.terminate, fail=self.check_fail) + # Force termination on exception + terminate = self.terminate or (self._exit_wait and ex_type) + return self.process(terminate=terminate, fail=self.check_fail) global_defer_queue = [] From c378c497f3fe8dc8f08b487fce49c3d96e4cada8 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 11 Aug 2025 16:13:34 -0700 Subject: [PATCH 00492/11391] selftests: drv-net: devmem: flip the direction of Tx tests The Device Under Test should always be the local system. While the Rx test gets this right the Tx test is sending from remote to local. So Tx of DMABUF memory happens on remote. These tests never run in NIPA since we don't have a compatible device so we haven't caught this. Reviewed-by: Joe Damato Reviewed-by: Mina Almasry Acked-by: Stanislav Fomichev Link: https://patch.msgid.link/20250811231334.561137-6-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/drivers/net/hw/devmem.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/drivers/net/hw/devmem.py b/tools/testing/selftests/drivers/net/hw/devmem.py index 0a2533a3d6d6..45c2d49d55b6 100755 --- a/tools/testing/selftests/drivers/net/hw/devmem.py +++ b/tools/testing/selftests/drivers/net/hw/devmem.py @@ -42,9 +42,9 @@ def check_tx(cfg) -> None: port = rand_port() listen_cmd = f"socat -U - TCP{cfg.addr_ipver}-LISTEN:{port}" - with bkg(listen_cmd) as socat: - wait_port_listen(port) - cmd(f"echo -e \"hello\\nworld\"| {cfg.bin_remote} -f {cfg.ifname} -s {cfg.addr} -p {port}", host=cfg.remote, shell=True) + with bkg(listen_cmd, host=cfg.remote, exit_wait=True) as socat: + wait_port_listen(port, host=cfg.remote) + cmd(f"echo -e \"hello\\nworld\"| {cfg.bin_local} -f {cfg.ifname} -s {cfg.remote_addr} -p {port}", shell=True) ksft_eq(socat.stdout.strip(), "hello\nworld") @@ -56,9 +56,9 @@ def check_tx_chunks(cfg) -> None: port = rand_port() listen_cmd = f"socat -U - TCP{cfg.addr_ipver}-LISTEN:{port}" - with bkg(listen_cmd, exit_wait=True) as socat: - wait_port_listen(port) - cmd(f"echo -e \"hello\\nworld\"| {cfg.bin_remote} -f {cfg.ifname} -s {cfg.addr} -p {port} -z 3", host=cfg.remote, shell=True) + with bkg(listen_cmd, host=cfg.remote, exit_wait=True) as socat: + wait_port_listen(port, host=cfg.remote) + cmd(f"echo -e \"hello\\nworld\"| {cfg.bin_local} -f {cfg.ifname} -s {cfg.remote_addr} -p {port} -z 3", shell=True) ksft_eq(socat.stdout.strip(), "hello\nworld") From cebd717d8f010a9897105434dbc6bdbd85693596 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 11 Aug 2025 17:31:36 +0200 Subject: [PATCH 00493/11391] dt-bindings: net: airoha: npu: Add memory regions used for wlan offload Document memory regions used by Airoha EN7581 NPU for wlan traffic offloading. The brand new added memory regions do not introduce any backward compatibility issues since they will be used just to offload traffic to/from the MT76 wireless NIC and the MT76 probing will not fail if these memory regions are not provide, it will just disable offloading via the NPU module. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Lorenzo Bianconi Link: https://patch.msgid.link/20250811-airoha-en7581-wlan-offlaod-v7-1-58823603bb4e@kernel.org Signed-off-by: Jakub Kicinski --- .../bindings/net/airoha,en7581-npu.yaml | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/net/airoha,en7581-npu.yaml b/Documentation/devicetree/bindings/net/airoha,en7581-npu.yaml index 76dd97c3fb40..c7644e6586d3 100644 --- a/Documentation/devicetree/bindings/net/airoha,en7581-npu.yaml +++ b/Documentation/devicetree/bindings/net/airoha,en7581-npu.yaml @@ -41,9 +41,21 @@ properties: - description: wlan irq line5 memory-region: - maxItems: 1 - description: - Memory used to store NPU firmware binary. + oneOf: + - items: + - description: NPU firmware binary region + - items: + - description: NPU firmware binary region + - description: NPU wlan offload RX buffers region + - description: NPU wlan offload TX buffers region + - description: NPU wlan offload TX packet identifiers region + + memory-region-names: + items: + - const: firmware + - const: pkt + - const: tx-pkt + - const: tx-bufid required: - compatible @@ -79,6 +91,8 @@ examples: , , ; - memory-region = <&npu_binary>; + memory-region = <&npu_firmware>, <&npu_pkt>, <&npu_txpkt>, + <&npu_txbufid>; + memory-region-names = "firmware", "pkt", "tx-pkt", "tx-bufid"; }; }; From 564923b02c1d2fe02ee789f9849ff79979b63b9f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 11 Aug 2025 17:31:37 +0200 Subject: [PATCH 00494/11391] net: airoha: npu: Add NPU wlan memory initialization commands Introduce wlan_init_reserved_memory callback used by MT76 driver during NPU wlan offloading setup. This is a preliminary patch to enable wlan flowtable offload for EN7581 SoC with MT76 driver. Reviewed-by: Simon Horman Signed-off-by: Lorenzo Bianconi Link: https://patch.msgid.link/20250811-airoha-en7581-wlan-offlaod-v7-2-58823603bb4e@kernel.org Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/airoha/airoha_npu.c | 82 ++++++++++++++++++++++++ drivers/net/ethernet/airoha/airoha_npu.h | 38 +++++++++++ 2 files changed, 120 insertions(+) diff --git a/drivers/net/ethernet/airoha/airoha_npu.c b/drivers/net/ethernet/airoha/airoha_npu.c index a802f95df99d..731e0119d988 100644 --- a/drivers/net/ethernet/airoha/airoha_npu.c +++ b/drivers/net/ethernet/airoha/airoha_npu.c @@ -124,6 +124,13 @@ struct ppe_mbox_data { }; }; +struct wlan_mbox_data { + u32 ifindex:4; + u32 func_type:4; + u32 func_id; + DECLARE_FLEX_ARRAY(u8, d); +}; + static int airoha_npu_send_msg(struct airoha_npu *npu, int func_id, void *p, int size) { @@ -390,6 +397,80 @@ static int airoha_npu_stats_setup(struct airoha_npu *npu, return err; } +static int airoha_npu_wlan_msg_send(struct airoha_npu *npu, int ifindex, + enum airoha_npu_wlan_set_cmd func_id, + void *data, int data_len, gfp_t gfp) +{ + struct wlan_mbox_data *wlan_data; + int err, len; + + len = sizeof(*wlan_data) + data_len; + wlan_data = kzalloc(len, gfp); + if (!wlan_data) + return -ENOMEM; + + wlan_data->ifindex = ifindex; + wlan_data->func_type = NPU_OP_SET; + wlan_data->func_id = func_id; + memcpy(wlan_data->d, data, data_len); + + err = airoha_npu_send_msg(npu, NPU_FUNC_WIFI, wlan_data, len); + kfree(wlan_data); + + return err; +} + +static int +airoha_npu_wlan_set_reserved_memory(struct airoha_npu *npu, + int ifindex, const char *name, + enum airoha_npu_wlan_set_cmd func_id) +{ + struct device *dev = npu->dev; + struct resource res; + int err; + u32 val; + + err = of_reserved_mem_region_to_resource_byname(dev->of_node, name, + &res); + if (err) + return err; + + val = res.start; + return airoha_npu_wlan_msg_send(npu, ifindex, func_id, &val, + sizeof(val), GFP_KERNEL); +} + +static int airoha_npu_wlan_init_memory(struct airoha_npu *npu) +{ + enum airoha_npu_wlan_set_cmd cmd = WLAN_FUNC_SET_WAIT_NPU_BAND0_ONCPU; + u32 val = 0; + int err; + + err = airoha_npu_wlan_msg_send(npu, 1, cmd, &val, sizeof(val), + GFP_KERNEL); + if (err) + return err; + + cmd = WLAN_FUNC_SET_WAIT_TX_BUF_CHECK_ADDR; + err = airoha_npu_wlan_set_reserved_memory(npu, 0, "tx-bufid", cmd); + if (err) + return err; + + cmd = WLAN_FUNC_SET_WAIT_PKT_BUF_ADDR; + err = airoha_npu_wlan_set_reserved_memory(npu, 0, "pkt", cmd); + if (err) + return err; + + cmd = WLAN_FUNC_SET_WAIT_TX_PKT_BUF_ADDR; + err = airoha_npu_wlan_set_reserved_memory(npu, 0, "tx-pkt", cmd); + if (err) + return err; + + cmd = WLAN_FUNC_SET_WAIT_IS_FORCE_TO_CPU; + return airoha_npu_wlan_msg_send(npu, 0, cmd, &val, sizeof(val), + GFP_KERNEL); +} + struct airoha_npu *airoha_npu_get(struct device *dev, dma_addr_t *stats_addr) { struct platform_device *pdev; @@ -493,6 +574,7 @@ static int airoha_npu_probe(struct platform_device *pdev) npu->ops.ppe_deinit = airoha_npu_ppe_deinit; npu->ops.ppe_flush_sram_entries = airoha_npu_ppe_flush_sram_entries; npu->ops.ppe_foe_commit_entry = airoha_npu_foe_commit_entry; + npu->ops.wlan_init_reserved_memory = airoha_npu_wlan_init_memory; npu->regmap = devm_regmap_init_mmio(dev, base, ®map_config); if (IS_ERR(npu->regmap)) diff --git a/drivers/net/ethernet/airoha/airoha_npu.h b/drivers/net/ethernet/airoha/airoha_npu.h index 98ec3be74ce4..0cb5356b00e9 100644 --- a/drivers/net/ethernet/airoha/airoha_npu.h +++ b/drivers/net/ethernet/airoha/airoha_npu.h @@ -6,6 +6,43 @@ #define NPU_NUM_CORES 8 +enum airoha_npu_wlan_set_cmd { + WLAN_FUNC_SET_WAIT_PCIE_ADDR, + WLAN_FUNC_SET_WAIT_DESC, + WLAN_FUNC_SET_WAIT_NPU_INIT_DONE, + WLAN_FUNC_SET_WAIT_TRAN_TO_CPU, + WLAN_FUNC_SET_WAIT_BA_WIN_SIZE, + WLAN_FUNC_SET_WAIT_DRIVER_MODEL, + WLAN_FUNC_SET_WAIT_DEL_STA, + WLAN_FUNC_SET_WAIT_DRAM_BA_NODE_ADDR, + WLAN_FUNC_SET_WAIT_PKT_BUF_ADDR, + WLAN_FUNC_SET_WAIT_IS_TEST_NOBA, + WLAN_FUNC_SET_WAIT_FLUSHONE_TIMEOUT, + WLAN_FUNC_SET_WAIT_FLUSHALL_TIMEOUT, + WLAN_FUNC_SET_WAIT_IS_FORCE_TO_CPU, + WLAN_FUNC_SET_WAIT_PCIE_STATE, + WLAN_FUNC_SET_WAIT_PCIE_PORT_TYPE, + WLAN_FUNC_SET_WAIT_ERROR_RETRY_TIMES, + WLAN_FUNC_SET_WAIT_BAR_INFO, + WLAN_FUNC_SET_WAIT_FAST_FLAG, + WLAN_FUNC_SET_WAIT_NPU_BAND0_ONCPU, + WLAN_FUNC_SET_WAIT_TX_RING_PCIE_ADDR, + WLAN_FUNC_SET_WAIT_TX_DESC_HW_BASE, + WLAN_FUNC_SET_WAIT_TX_BUF_SPACE_HW_BASE, + WLAN_FUNC_SET_WAIT_RX_RING_FOR_TXDONE_HW_BASE, + WLAN_FUNC_SET_WAIT_TX_PKT_BUF_ADDR, + WLAN_FUNC_SET_WAIT_INODE_TXRX_REG_ADDR, + WLAN_FUNC_SET_WAIT_INODE_DEBUG_FLAG, + WLAN_FUNC_SET_WAIT_INODE_HW_CFG_INFO, + WLAN_FUNC_SET_WAIT_INODE_STOP_ACTION, + WLAN_FUNC_SET_WAIT_INODE_PCIE_SWAP, + WLAN_FUNC_SET_WAIT_RATELIMIT_CTRL, + WLAN_FUNC_SET_WAIT_HWNAT_INIT, + WLAN_FUNC_SET_WAIT_ARHT_CHIP_INFO, + WLAN_FUNC_SET_WAIT_TX_BUF_CHECK_ADDR, + WLAN_FUNC_SET_WAIT_TOKEN_ID_SIZE, +}; + struct airoha_npu { struct device *dev; struct regmap *regmap; @@ -29,6 +66,7 @@ struct airoha_npu { dma_addr_t foe_addr, u32 entry_size, u32 hash, bool ppe2); + int (*wlan_init_reserved_memory)(struct airoha_npu *npu); } ops; }; From f97fc66185b2004ad5f393f78b3e645009ddd1d0 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 11 Aug 2025 17:31:38 +0200 Subject: [PATCH 00495/11391] net: airoha: npu: Add wlan_{send,get}_msg NPU callbacks Introduce wlan_send_msg() and wlan_get_msg() NPU wlan callbacks used by the wlan driver (MT76) to initialize NPU module registers in order to offload wireless-wired traffic. This is a preliminary patch to enable wlan flowtable offload for EN7581 SoC with MT76 driver. Signed-off-by: Lorenzo Bianconi Link: https://patch.msgid.link/20250811-airoha-en7581-wlan-offlaod-v7-3-58823603bb4e@kernel.org Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/airoha/airoha_npu.c | 52 ++++++++++++++++++++++++ drivers/net/ethernet/airoha/airoha_npu.h | 22 ++++++++++ 2 files changed, 74 insertions(+) diff --git a/drivers/net/ethernet/airoha/airoha_npu.c b/drivers/net/ethernet/airoha/airoha_npu.c index 731e0119d988..2a337f00386f 100644 --- a/drivers/net/ethernet/airoha/airoha_npu.c +++ b/drivers/net/ethernet/airoha/airoha_npu.c @@ -42,6 +42,22 @@ #define REG_CR_MBQ8_CTRL(_n) (NPU_MBOX_BASE_ADDR + 0x0b0 + ((_n) << 2)) #define REG_CR_NPU_MIB(_n) (NPU_MBOX_BASE_ADDR + 0x140 + ((_n) << 2)) +#define NPU_WLAN_BASE_ADDR 0x30d000 + +#define REG_IRQ_STATUS (NPU_WLAN_BASE_ADDR + 0x030) +#define REG_IRQ_RXDONE(_n) (NPU_WLAN_BASE_ADDR + ((_n) << 2) + 0x034) +#define NPU_IRQ_RX_MASK(_n) ((_n) == 1 ? BIT(17) : BIT(16)) + +#define REG_TX_BASE(_n) (NPU_WLAN_BASE_ADDR + ((_n) << 4) + 0x080) +#define REG_TX_DSCP_NUM(_n) (NPU_WLAN_BASE_ADDR + ((_n) << 4) + 0x084) +#define REG_TX_CPU_IDX(_n) (NPU_WLAN_BASE_ADDR + ((_n) << 4) + 0x088) +#define REG_TX_DMA_IDX(_n) (NPU_WLAN_BASE_ADDR + ((_n) << 4) + 0x08c) + +#define REG_RX_BASE(_n) (NPU_WLAN_BASE_ADDR + ((_n) << 4) + 0x180) +#define REG_RX_DSCP_NUM(_n) (NPU_WLAN_BASE_ADDR + ((_n) << 4) + 0x184) +#define REG_RX_CPU_IDX(_n) (NPU_WLAN_BASE_ADDR + ((_n) << 4) + 0x188) +#define REG_RX_DMA_IDX(_n) (NPU_WLAN_BASE_ADDR + ((_n) << 4) + 0x18c) + #define NPU_TIMER_BASE_ADDR 0x310100 #define REG_WDT_TIMER_CTRL(_n) (NPU_TIMER_BASE_ADDR + ((_n) * 0x100)) #define WDT_EN_MASK BIT(25) @@ -420,6 +436,30 @@ static int airoha_npu_wlan_msg_send(struct airoha_npu *npu, int ifindex, return err; } +static int airoha_npu_wlan_msg_get(struct airoha_npu *npu, int ifindex, + enum airoha_npu_wlan_get_cmd func_id, + void *data, int data_len, gfp_t gfp) +{ + struct wlan_mbox_data *wlan_data; + int err, len; + + len = sizeof(*wlan_data) + data_len; + wlan_data = kzalloc(len, gfp); + if (!wlan_data) + return -ENOMEM; + + wlan_data->ifindex = ifindex; + wlan_data->func_type = NPU_OP_GET; + wlan_data->func_id = func_id; + + err = airoha_npu_send_msg(npu, NPU_FUNC_WIFI, wlan_data, len); + if (!err) + memcpy(data, wlan_data->d, data_len); + kfree(wlan_data); + + return err; +} + static int airoha_npu_wlan_set_reserved_memory(struct airoha_npu *npu, int ifindex, const char *name, @@ -471,6 +511,15 @@ static int airoha_npu_wlan_init_memory(struct airoha_npu *npu) GFP_KERNEL); } +static u32 airoha_npu_wlan_queue_addr_get(struct airoha_npu *npu, int qid, + bool xmit) +{ + if (xmit) + return REG_TX_BASE(qid + 2); + + return REG_RX_BASE(qid); +} + struct airoha_npu *airoha_npu_get(struct device *dev, dma_addr_t *stats_addr) { struct platform_device *pdev; @@ -575,6 +624,9 @@ static int airoha_npu_probe(struct platform_device *pdev) npu->ops.ppe_flush_sram_entries = airoha_npu_ppe_flush_sram_entries; npu->ops.ppe_foe_commit_entry = airoha_npu_foe_commit_entry; npu->ops.wlan_init_reserved_memory = airoha_npu_wlan_init_memory; + npu->ops.wlan_send_msg = airoha_npu_wlan_msg_send; + npu->ops.wlan_get_msg = airoha_npu_wlan_msg_get; + npu->ops.wlan_get_queue_addr = airoha_npu_wlan_queue_addr_get; npu->regmap = devm_regmap_init_mmio(dev, base, ®map_config); if (IS_ERR(npu->regmap)) diff --git a/drivers/net/ethernet/airoha/airoha_npu.h b/drivers/net/ethernet/airoha/airoha_npu.h index 0cb5356b00e9..7b9ff370c879 100644 --- a/drivers/net/ethernet/airoha/airoha_npu.h +++ b/drivers/net/ethernet/airoha/airoha_npu.h @@ -43,6 +43,20 @@ enum airoha_npu_wlan_set_cmd { WLAN_FUNC_SET_WAIT_TOKEN_ID_SIZE, }; +enum airoha_npu_wlan_get_cmd { + WLAN_FUNC_GET_WAIT_NPU_INFO, + WLAN_FUNC_GET_WAIT_LAST_RATE, + WLAN_FUNC_GET_WAIT_COUNTER, + WLAN_FUNC_GET_WAIT_DBG_COUNTER, + WLAN_FUNC_GET_WAIT_RXDESC_BASE, + WLAN_FUNC_GET_WAIT_WCID_DBG_COUNTER, + WLAN_FUNC_GET_WAIT_DMA_ADDR, + WLAN_FUNC_GET_WAIT_RING_SIZE, + WLAN_FUNC_GET_WAIT_NPU_SUPPORT_MAP, + WLAN_FUNC_GET_WAIT_MDC_LOCK_ADDRESS, + WLAN_FUNC_GET_WAIT_NPU_VERSION, +}; + struct airoha_npu { struct device *dev; struct regmap *regmap; @@ -67,6 +81,14 @@ struct airoha_npu { u32 entry_size, u32 hash, bool ppe2); int (*wlan_init_reserved_memory)(struct airoha_npu *npu); + int (*wlan_send_msg)(struct airoha_npu *npu, int ifindex, + enum airoha_npu_wlan_set_cmd func_id, + void *data, int data_len, gfp_t gfp); + int (*wlan_get_msg)(struct airoha_npu *npu, int ifindex, + enum airoha_npu_wlan_get_cmd func_id, + void *data, int data_len, gfp_t gfp); + u32 (*wlan_get_queue_addr)(struct airoha_npu *npu, int qid, + bool xmit); } ops; }; From 03b7ca3ee5e1b700c462aed5b6cb88f616d6ba7f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 11 Aug 2025 17:31:39 +0200 Subject: [PATCH 00496/11391] net: airoha: npu: Add wlan irq management callbacks Introduce callbacks used by the MT76 driver to configure NPU SoC interrupts. This is a preliminary patch to enable wlan flowtable offload for EN7581 SoC with MT76 driver. Reviewed-by: Simon Horman Signed-off-by: Lorenzo Bianconi Link: https://patch.msgid.link/20250811-airoha-en7581-wlan-offlaod-v7-4-58823603bb4e@kernel.org Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/airoha/airoha_npu.c | 27 ++++++++++++++++++++++++ drivers/net/ethernet/airoha/airoha_npu.h | 4 ++++ 2 files changed, 31 insertions(+) diff --git a/drivers/net/ethernet/airoha/airoha_npu.c b/drivers/net/ethernet/airoha/airoha_npu.c index 2a337f00386f..5d1355126d16 100644 --- a/drivers/net/ethernet/airoha/airoha_npu.c +++ b/drivers/net/ethernet/airoha/airoha_npu.c @@ -520,6 +520,29 @@ static u32 airoha_npu_wlan_queue_addr_get(struct airoha_npu *npu, int qid, return REG_RX_BASE(qid); } +static void airoha_npu_wlan_irq_status_set(struct airoha_npu *npu, u32 val) +{ + regmap_write(npu->regmap, REG_IRQ_STATUS, val); +} + +static u32 airoha_npu_wlan_irq_status_get(struct airoha_npu *npu, int q) +{ + u32 val; + + regmap_read(npu->regmap, REG_IRQ_STATUS, &val); + return val; +} + +static void airoha_npu_wlan_irq_enable(struct airoha_npu *npu, int q) +{ + regmap_set_bits(npu->regmap, REG_IRQ_RXDONE(q), NPU_IRQ_RX_MASK(q)); +} + +static void airoha_npu_wlan_irq_disable(struct airoha_npu *npu, int q) +{ + regmap_clear_bits(npu->regmap, REG_IRQ_RXDONE(q), NPU_IRQ_RX_MASK(q)); +} + struct airoha_npu *airoha_npu_get(struct device *dev, dma_addr_t *stats_addr) { struct platform_device *pdev; @@ -627,6 +650,10 @@ static int airoha_npu_probe(struct platform_device *pdev) npu->ops.wlan_send_msg = airoha_npu_wlan_msg_send; npu->ops.wlan_get_msg = airoha_npu_wlan_msg_get; npu->ops.wlan_get_queue_addr = airoha_npu_wlan_queue_addr_get; + npu->ops.wlan_set_irq_status = airoha_npu_wlan_irq_status_set; + npu->ops.wlan_get_irq_status = airoha_npu_wlan_irq_status_get; + npu->ops.wlan_enable_irq = airoha_npu_wlan_irq_enable; + npu->ops.wlan_disable_irq = airoha_npu_wlan_irq_disable; npu->regmap = devm_regmap_init_mmio(dev, base, ®map_config); if (IS_ERR(npu->regmap)) diff --git a/drivers/net/ethernet/airoha/airoha_npu.h b/drivers/net/ethernet/airoha/airoha_npu.h index 7b9ff370c879..84c83753c2bd 100644 --- a/drivers/net/ethernet/airoha/airoha_npu.h +++ b/drivers/net/ethernet/airoha/airoha_npu.h @@ -89,6 +89,10 @@ struct airoha_npu { void *data, int data_len, gfp_t gfp); u32 (*wlan_get_queue_addr)(struct airoha_npu *npu, int qid, bool xmit); + void (*wlan_set_irq_status)(struct airoha_npu *npu, u32 val); + u32 (*wlan_get_irq_status)(struct airoha_npu *npu, int q); + void (*wlan_enable_irq)(struct airoha_npu *npu, int q); + void (*wlan_disable_irq)(struct airoha_npu *npu, int q); } ops; }; From a1740b16c83729d908c760eaa821f27b51e58a13 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 11 Aug 2025 17:31:40 +0200 Subject: [PATCH 00497/11391] net: airoha: npu: Read NPU wlan interrupt lines from the DTS Read all NPU wlan IRQ lines from the NPU device-tree node. NPU module fires wlan irq lines when the traffic to/from the WiFi NIC is not hw accelerated (these interrupts will be consumed by the MT76 driver in subsequent patches). This is a preliminary patch to enable wlan flowtable offload for EN7581 SoC. Signed-off-by: Lorenzo Bianconi Link: https://patch.msgid.link/20250811-airoha-en7581-wlan-offlaod-v7-5-58823603bb4e@kernel.org Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/airoha/airoha_npu.c | 9 +++++++++ drivers/net/ethernet/airoha/airoha_npu.h | 3 +++ 2 files changed, 12 insertions(+) diff --git a/drivers/net/ethernet/airoha/airoha_npu.c b/drivers/net/ethernet/airoha/airoha_npu.c index 5d1355126d16..e0448e1225b8 100644 --- a/drivers/net/ethernet/airoha/airoha_npu.c +++ b/drivers/net/ethernet/airoha/airoha_npu.c @@ -690,6 +690,15 @@ static int airoha_npu_probe(struct platform_device *pdev) INIT_WORK(&core->wdt_work, airoha_npu_wdt_work); } + /* wlan IRQ lines */ + for (i = 0; i < ARRAY_SIZE(npu->irqs); i++) { + irq = platform_get_irq(pdev, i + ARRAY_SIZE(npu->cores) + 1); + if (irq < 0) + return irq; + + npu->irqs[i] = irq; + } + err = dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); if (err) return err; diff --git a/drivers/net/ethernet/airoha/airoha_npu.h b/drivers/net/ethernet/airoha/airoha_npu.h index 84c83753c2bd..a448c74208a9 100644 --- a/drivers/net/ethernet/airoha/airoha_npu.h +++ b/drivers/net/ethernet/airoha/airoha_npu.h @@ -5,6 +5,7 @@ */ #define NPU_NUM_CORES 8 +#define NPU_NUM_IRQ 6 enum airoha_npu_wlan_set_cmd { WLAN_FUNC_SET_WAIT_PCIE_ADDR, @@ -68,6 +69,8 @@ struct airoha_npu { struct work_struct wdt_work; } cores[NPU_NUM_CORES]; + int irqs[NPU_NUM_IRQ]; + struct airoha_foe_stats __iomem *stats; struct { From 29c4a3ce508961a02d185ead2d52699b16d82c6d Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 11 Aug 2025 17:31:41 +0200 Subject: [PATCH 00498/11391] net: airoha: npu: Enable core 3 for WiFi offloading NPU core 3 is responsible for WiFi offloading so enable it during NPU probe. Reviewed-by: Simon Horman Signed-off-by: Lorenzo Bianconi Link: https://patch.msgid.link/20250811-airoha-en7581-wlan-offlaod-v7-6-58823603bb4e@kernel.org Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/airoha/airoha_npu.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/airoha/airoha_npu.c b/drivers/net/ethernet/airoha/airoha_npu.c index e0448e1225b8..66a8a992dbf2 100644 --- a/drivers/net/ethernet/airoha/airoha_npu.c +++ b/drivers/net/ethernet/airoha/airoha_npu.c @@ -720,8 +720,7 @@ static int airoha_npu_probe(struct platform_device *pdev) usleep_range(1000, 2000); /* enable NPU cores */ - /* do not start core3 since it is used for WiFi offloading */ - regmap_write(npu->regmap, REG_CR_BOOT_CONFIG, 0xf7); + regmap_write(npu->regmap, REG_CR_BOOT_CONFIG, 0xff); regmap_write(npu->regmap, REG_CR_BOOT_TRIGGER, 0x1); msleep(100); From b3ef7bdec66fb1813e865fd39d179a93cefd2015 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 11 Aug 2025 17:31:42 +0200 Subject: [PATCH 00499/11391] net: airoha: Add airoha_offload.h header Move NPU definitions to airoha_offload.h in include/linux/soc/airoha/ in order to allow the MT76 driver to access the callback definitions. Signed-off-by: Lorenzo Bianconi Link: https://patch.msgid.link/20250811-airoha-en7581-wlan-offlaod-v7-7-58823603bb4e@kernel.org Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/airoha/airoha_npu.c | 2 +- drivers/net/ethernet/airoha/airoha_npu.h | 103 --------- drivers/net/ethernet/airoha/airoha_ppe.c | 2 +- include/linux/soc/airoha/airoha_offload.h | 260 ++++++++++++++++++++++ 4 files changed, 262 insertions(+), 105 deletions(-) delete mode 100644 drivers/net/ethernet/airoha/airoha_npu.h create mode 100644 include/linux/soc/airoha/airoha_offload.h diff --git a/drivers/net/ethernet/airoha/airoha_npu.c b/drivers/net/ethernet/airoha/airoha_npu.c index 66a8a992dbf2..1a6b191ae0b0 100644 --- a/drivers/net/ethernet/airoha/airoha_npu.c +++ b/drivers/net/ethernet/airoha/airoha_npu.c @@ -11,9 +11,9 @@ #include #include #include +#include #include "airoha_eth.h" -#include "airoha_npu.h" #define NPU_EN7581_FIRMWARE_DATA "airoha/en7581_npu_data.bin" #define NPU_EN7581_FIRMWARE_RV32 "airoha/en7581_npu_rv32.bin" diff --git a/drivers/net/ethernet/airoha/airoha_npu.h b/drivers/net/ethernet/airoha/airoha_npu.h deleted file mode 100644 index a448c74208a9..000000000000 --- a/drivers/net/ethernet/airoha/airoha_npu.h +++ /dev/null @@ -1,103 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2025 AIROHA Inc - * Author: Lorenzo Bianconi - */ - -#define NPU_NUM_CORES 8 -#define NPU_NUM_IRQ 6 - -enum airoha_npu_wlan_set_cmd { - WLAN_FUNC_SET_WAIT_PCIE_ADDR, - WLAN_FUNC_SET_WAIT_DESC, - WLAN_FUNC_SET_WAIT_NPU_INIT_DONE, - WLAN_FUNC_SET_WAIT_TRAN_TO_CPU, - WLAN_FUNC_SET_WAIT_BA_WIN_SIZE, - WLAN_FUNC_SET_WAIT_DRIVER_MODEL, - WLAN_FUNC_SET_WAIT_DEL_STA, - WLAN_FUNC_SET_WAIT_DRAM_BA_NODE_ADDR, - WLAN_FUNC_SET_WAIT_PKT_BUF_ADDR, - WLAN_FUNC_SET_WAIT_IS_TEST_NOBA, - WLAN_FUNC_SET_WAIT_FLUSHONE_TIMEOUT, - WLAN_FUNC_SET_WAIT_FLUSHALL_TIMEOUT, - WLAN_FUNC_SET_WAIT_IS_FORCE_TO_CPU, - WLAN_FUNC_SET_WAIT_PCIE_STATE, - WLAN_FUNC_SET_WAIT_PCIE_PORT_TYPE, - WLAN_FUNC_SET_WAIT_ERROR_RETRY_TIMES, - WLAN_FUNC_SET_WAIT_BAR_INFO, - WLAN_FUNC_SET_WAIT_FAST_FLAG, - WLAN_FUNC_SET_WAIT_NPU_BAND0_ONCPU, - WLAN_FUNC_SET_WAIT_TX_RING_PCIE_ADDR, - WLAN_FUNC_SET_WAIT_TX_DESC_HW_BASE, - WLAN_FUNC_SET_WAIT_TX_BUF_SPACE_HW_BASE, - WLAN_FUNC_SET_WAIT_RX_RING_FOR_TXDONE_HW_BASE, - WLAN_FUNC_SET_WAIT_TX_PKT_BUF_ADDR, - WLAN_FUNC_SET_WAIT_INODE_TXRX_REG_ADDR, - WLAN_FUNC_SET_WAIT_INODE_DEBUG_FLAG, - WLAN_FUNC_SET_WAIT_INODE_HW_CFG_INFO, - WLAN_FUNC_SET_WAIT_INODE_STOP_ACTION, - WLAN_FUNC_SET_WAIT_INODE_PCIE_SWAP, - WLAN_FUNC_SET_WAIT_RATELIMIT_CTRL, - WLAN_FUNC_SET_WAIT_HWNAT_INIT, - WLAN_FUNC_SET_WAIT_ARHT_CHIP_INFO, - WLAN_FUNC_SET_WAIT_TX_BUF_CHECK_ADDR, - WLAN_FUNC_SET_WAIT_TOKEN_ID_SIZE, -}; - -enum airoha_npu_wlan_get_cmd { - WLAN_FUNC_GET_WAIT_NPU_INFO, - WLAN_FUNC_GET_WAIT_LAST_RATE, - WLAN_FUNC_GET_WAIT_COUNTER, - WLAN_FUNC_GET_WAIT_DBG_COUNTER, - WLAN_FUNC_GET_WAIT_RXDESC_BASE, - WLAN_FUNC_GET_WAIT_WCID_DBG_COUNTER, - WLAN_FUNC_GET_WAIT_DMA_ADDR, - WLAN_FUNC_GET_WAIT_RING_SIZE, - WLAN_FUNC_GET_WAIT_NPU_SUPPORT_MAP, - WLAN_FUNC_GET_WAIT_MDC_LOCK_ADDRESS, - WLAN_FUNC_GET_WAIT_NPU_VERSION, -}; - -struct airoha_npu { - struct device *dev; - struct regmap *regmap; - - struct airoha_npu_core { - struct airoha_npu *npu; - /* protect concurrent npu memory accesses */ - spinlock_t lock; - struct work_struct wdt_work; - } cores[NPU_NUM_CORES]; - - int irqs[NPU_NUM_IRQ]; - - struct airoha_foe_stats __iomem *stats; - - struct { - int (*ppe_init)(struct airoha_npu *npu); - int (*ppe_deinit)(struct airoha_npu *npu); - int (*ppe_flush_sram_entries)(struct airoha_npu *npu, - dma_addr_t foe_addr, - int sram_num_entries); - int (*ppe_foe_commit_entry)(struct airoha_npu *npu, - dma_addr_t foe_addr, - u32 entry_size, u32 hash, - bool ppe2); - int (*wlan_init_reserved_memory)(struct airoha_npu *npu); - int (*wlan_send_msg)(struct airoha_npu *npu, int ifindex, - enum airoha_npu_wlan_set_cmd func_id, - void *data, int data_len, gfp_t gfp); - int (*wlan_get_msg)(struct airoha_npu *npu, int ifindex, - enum airoha_npu_wlan_get_cmd func_id, - void *data, int data_len, gfp_t gfp); - u32 (*wlan_get_queue_addr)(struct airoha_npu *npu, int qid, - bool xmit); - void (*wlan_set_irq_status)(struct airoha_npu *npu, u32 val); - u32 (*wlan_get_irq_status)(struct airoha_npu *npu, int q); - void (*wlan_enable_irq)(struct airoha_npu *npu, int q); - void (*wlan_disable_irq)(struct airoha_npu *npu, int q); - } ops; -}; - -struct airoha_npu *airoha_npu_get(struct device *dev, dma_addr_t *stats_addr); -void airoha_npu_put(struct airoha_npu *npu); diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c index 47411d2cbd28..82163392332c 100644 --- a/drivers/net/ethernet/airoha/airoha_ppe.c +++ b/drivers/net/ethernet/airoha/airoha_ppe.c @@ -7,10 +7,10 @@ #include #include #include +#include #include #include -#include "airoha_npu.h" #include "airoha_regs.h" #include "airoha_eth.h" diff --git a/include/linux/soc/airoha/airoha_offload.h b/include/linux/soc/airoha/airoha_offload.h new file mode 100644 index 000000000000..117c63c2448d --- /dev/null +++ b/include/linux/soc/airoha/airoha_offload.h @@ -0,0 +1,260 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2025 AIROHA Inc + * Author: Lorenzo Bianconi + */ +#ifndef AIROHA_OFFLOAD_H +#define AIROHA_OFFLOAD_H + +#include +#include + +#define NPU_NUM_CORES 8 +#define NPU_NUM_IRQ 6 +#define NPU_RX0_DESC_NUM 512 +#define NPU_RX1_DESC_NUM 512 + +/* CTRL */ +#define NPU_RX_DMA_DESC_LAST_MASK BIT(29) +#define NPU_RX_DMA_DESC_LEN_MASK GENMASK(28, 15) +#define NPU_RX_DMA_DESC_CUR_LEN_MASK GENMASK(14, 1) +#define NPU_RX_DMA_DESC_DONE_MASK BIT(0) +/* INFO */ +#define NPU_RX_DMA_PKT_COUNT_MASK GENMASK(31, 28) +#define NPU_RX_DMA_PKT_ID_MASK GENMASK(28, 26) +#define NPU_RX_DMA_SRC_PORT_MASK GENMASK(25, 21) +#define NPU_RX_DMA_CRSN_MASK GENMASK(20, 16) +#define NPU_RX_DMA_FOE_ID_MASK GENMASK(15, 0) +/* DATA */ +#define NPU_RX_DMA_SID_MASK GENMASK(31, 16) +#define NPU_RX_DMA_FRAG_TYPE_MASK GENMASK(15, 14) +#define NPU_RX_DMA_PRIORITY_MASK GENMASK(13, 10) +#define NPU_RX_DMA_RADIO_ID_MASK GENMASK(9, 6) +#define NPU_RX_DMA_VAP_ID_MASK GENMASK(5, 2) +#define NPU_RX_DMA_FRAME_TYPE_MASK GENMASK(1, 0) + +struct airoha_npu_rx_dma_desc { + u32 ctrl; + u32 info; + u32 data; + u32 addr; + u64 rsv; +} __packed; + +/* CTRL */ +#define NPU_TX_DMA_DESC_SCHED_MASK BIT(31) +#define NPU_TX_DMA_DESC_LEN_MASK GENMASK(30, 18) +#define NPU_TX_DMA_DESC_VEND_LEN_MASK GENMASK(17, 1) +#define NPU_TX_DMA_DESC_DONE_MASK BIT(0) + +#define NPU_TXWI_LEN 192 + +struct airoha_npu_tx_dma_desc { + u32 ctrl; + u32 addr; + u64 rsv; + u8 txwi[NPU_TXWI_LEN]; +} __packed; + +enum airoha_npu_wlan_set_cmd { + WLAN_FUNC_SET_WAIT_PCIE_ADDR, + WLAN_FUNC_SET_WAIT_DESC, + WLAN_FUNC_SET_WAIT_NPU_INIT_DONE, + WLAN_FUNC_SET_WAIT_TRAN_TO_CPU, + WLAN_FUNC_SET_WAIT_BA_WIN_SIZE, + WLAN_FUNC_SET_WAIT_DRIVER_MODEL, + WLAN_FUNC_SET_WAIT_DEL_STA, + WLAN_FUNC_SET_WAIT_DRAM_BA_NODE_ADDR, + WLAN_FUNC_SET_WAIT_PKT_BUF_ADDR, + WLAN_FUNC_SET_WAIT_IS_TEST_NOBA, + WLAN_FUNC_SET_WAIT_FLUSHONE_TIMEOUT, + WLAN_FUNC_SET_WAIT_FLUSHALL_TIMEOUT, + WLAN_FUNC_SET_WAIT_IS_FORCE_TO_CPU, + WLAN_FUNC_SET_WAIT_PCIE_STATE, + WLAN_FUNC_SET_WAIT_PCIE_PORT_TYPE, + WLAN_FUNC_SET_WAIT_ERROR_RETRY_TIMES, + WLAN_FUNC_SET_WAIT_BAR_INFO, + WLAN_FUNC_SET_WAIT_FAST_FLAG, + WLAN_FUNC_SET_WAIT_NPU_BAND0_ONCPU, + WLAN_FUNC_SET_WAIT_TX_RING_PCIE_ADDR, + WLAN_FUNC_SET_WAIT_TX_DESC_HW_BASE, + WLAN_FUNC_SET_WAIT_TX_BUF_SPACE_HW_BASE, + WLAN_FUNC_SET_WAIT_RX_RING_FOR_TXDONE_HW_BASE, + WLAN_FUNC_SET_WAIT_TX_PKT_BUF_ADDR, + WLAN_FUNC_SET_WAIT_INODE_TXRX_REG_ADDR, + WLAN_FUNC_SET_WAIT_INODE_DEBUG_FLAG, + WLAN_FUNC_SET_WAIT_INODE_HW_CFG_INFO, + WLAN_FUNC_SET_WAIT_INODE_STOP_ACTION, + WLAN_FUNC_SET_WAIT_INODE_PCIE_SWAP, + WLAN_FUNC_SET_WAIT_RATELIMIT_CTRL, + WLAN_FUNC_SET_WAIT_HWNAT_INIT, + WLAN_FUNC_SET_WAIT_ARHT_CHIP_INFO, + WLAN_FUNC_SET_WAIT_TX_BUF_CHECK_ADDR, + WLAN_FUNC_SET_WAIT_TOKEN_ID_SIZE, +}; + +enum airoha_npu_wlan_get_cmd { + WLAN_FUNC_GET_WAIT_NPU_INFO, + WLAN_FUNC_GET_WAIT_LAST_RATE, + WLAN_FUNC_GET_WAIT_COUNTER, + WLAN_FUNC_GET_WAIT_DBG_COUNTER, + WLAN_FUNC_GET_WAIT_RXDESC_BASE, + WLAN_FUNC_GET_WAIT_WCID_DBG_COUNTER, + WLAN_FUNC_GET_WAIT_DMA_ADDR, + WLAN_FUNC_GET_WAIT_RING_SIZE, + WLAN_FUNC_GET_WAIT_NPU_SUPPORT_MAP, + WLAN_FUNC_GET_WAIT_MDC_LOCK_ADDRESS, + WLAN_FUNC_GET_WAIT_NPU_VERSION, +}; + +struct airoha_npu { +#if (IS_BUILTIN(CONFIG_NET_AIROHA_NPU) || IS_MODULE(CONFIG_NET_AIROHA_NPU)) + struct device *dev; + struct regmap *regmap; + + struct airoha_npu_core { + struct airoha_npu *npu; + /* protect concurrent npu memory accesses */ + spinlock_t lock; + struct work_struct wdt_work; + } cores[NPU_NUM_CORES]; + + int irqs[NPU_NUM_IRQ]; + + struct airoha_foe_stats __iomem *stats; + + struct { + int (*ppe_init)(struct airoha_npu *npu); + int (*ppe_deinit)(struct airoha_npu *npu); + int (*ppe_flush_sram_entries)(struct airoha_npu *npu, + dma_addr_t foe_addr, + int sram_num_entries); + int (*ppe_foe_commit_entry)(struct airoha_npu *npu, + dma_addr_t foe_addr, + u32 entry_size, u32 hash, + bool ppe2); + int (*wlan_init_reserved_memory)(struct airoha_npu *npu); + int (*wlan_send_msg)(struct airoha_npu *npu, int ifindex, + enum airoha_npu_wlan_set_cmd func_id, + void *data, int data_len, gfp_t gfp); + int (*wlan_get_msg)(struct airoha_npu *npu, int ifindex, + enum airoha_npu_wlan_get_cmd func_id, + void *data, int data_len, gfp_t gfp); + u32 (*wlan_get_queue_addr)(struct airoha_npu *npu, int qid, + bool xmit); + void (*wlan_set_irq_status)(struct airoha_npu *npu, u32 val); + u32 (*wlan_get_irq_status)(struct airoha_npu *npu, int q); + void (*wlan_enable_irq)(struct airoha_npu *npu, int q); + void (*wlan_disable_irq)(struct airoha_npu *npu, int q); + } ops; +#endif +}; + +#if (IS_BUILTIN(CONFIG_NET_AIROHA_NPU) || IS_MODULE(CONFIG_NET_AIROHA_NPU)) +struct airoha_npu *airoha_npu_get(struct device *dev, dma_addr_t *stats_addr); +void airoha_npu_put(struct airoha_npu *npu); + +static inline int airoha_npu_wlan_init_reserved_memory(struct airoha_npu *npu) +{ + return npu->ops.wlan_init_reserved_memory(npu); +} + +static inline int airoha_npu_wlan_send_msg(struct airoha_npu *npu, + int ifindex, + enum airoha_npu_wlan_set_cmd cmd, + void *data, int data_len, gfp_t gfp) +{ + return npu->ops.wlan_send_msg(npu, ifindex, cmd, data, data_len, gfp); +} + +static inline int airoha_npu_wlan_get_msg(struct airoha_npu *npu, int ifindex, + enum airoha_npu_wlan_get_cmd cmd, + void *data, int data_len, gfp_t gfp) +{ + return npu->ops.wlan_get_msg(npu, ifindex, cmd, data, data_len, gfp); +} + +static inline u32 airoha_npu_wlan_get_queue_addr(struct airoha_npu *npu, + int qid, bool xmit) +{ + return npu->ops.wlan_get_queue_addr(npu, qid, xmit); +} + +static inline void airoha_npu_wlan_set_irq_status(struct airoha_npu *npu, + u32 val) +{ + npu->ops.wlan_set_irq_status(npu, val); +} + +static inline u32 airoha_npu_wlan_get_irq_status(struct airoha_npu *npu, int q) +{ + return npu->ops.wlan_get_irq_status(npu, q); +} + +static inline void airoha_npu_wlan_enable_irq(struct airoha_npu *npu, int q) +{ + npu->ops.wlan_enable_irq(npu, q); +} + +static inline void airoha_npu_wlan_disable_irq(struct airoha_npu *npu, int q) +{ + npu->ops.wlan_disable_irq(npu, q); +} +#else +static inline struct airoha_npu *airoha_npu_get(struct device *dev, + dma_addr_t *foe_stats_addr) +{ + return NULL; +} + +static inline void airoha_npu_put(struct airoha_npu *npu) +{ +} + +static inline int airoha_npu_wlan_init_reserved_memory(struct airoha_npu *npu) +{ + return -EOPNOTSUPP; +} + +static inline int airoha_npu_wlan_send_msg(struct airoha_npu *npu, + int ifindex, + enum airoha_npu_wlan_set_cmd cmd, + void *data, int data_len, gfp_t gfp) +{ + return -EOPNOTSUPP; +} + +static inline int airoha_npu_wlan_get_msg(struct airoha_npu *npu, int ifindex, + enum airoha_npu_wlan_get_cmd cmd, + void *data, int data_len, gfp_t gfp) +{ + return -EOPNOTSUPP; +} + +static inline u32 airoha_npu_wlan_get_queue_addr(struct airoha_npu *npu, + int qid, bool xmit) +{ + return 0; +} + +static inline void airoha_npu_wlan_set_irq_status(struct airoha_npu *npu, + u32 val) +{ +} + +static inline u32 airoha_npu_wlan_get_irq_status(struct airoha_npu *npu, + int q) +{ + return 0; +} + +static inline void airoha_npu_wlan_enable_irq(struct airoha_npu *npu, int q) +{ +} + +static inline void airoha_npu_wlan_disable_irq(struct airoha_npu *npu, int q) +{ +} +#endif + +#endif /* AIROHA_OFFLOAD_H */ From 103b0cfc9ab6ae920289223f402ec5e868e3a872 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Wed, 25 Jun 2025 14:32:55 +0100 Subject: [PATCH 00500/11391] media: radio-wl1273: Remove The wl1273 FM radio is on Arnd's unused driver list: https://lore.kernel.org/lkml/a15bb180-401d-49ad-a212-0c81d613fbc8@app.fastmail.com/ remove the radio component itself. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/radio/Kconfig | 17 - drivers/media/radio/Makefile | 1 - drivers/media/radio/radio-wl1273.c | 2159 ---------------------------- 3 files changed, 2177 deletions(-) delete mode 100644 drivers/media/radio/radio-wl1273.c diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index 72776d08046a..bbbdd054ba64 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -141,23 +141,6 @@ config RADIO_TIMBERDALE found behind the Timberdale FPGA on the Russellville board. Enabling this driver will automatically select the DSP and tuner. -config RADIO_WL1273 - tristate "Texas Instruments WL1273 I2C FM Radio" - depends on I2C - select MFD_CORE - select MFD_WL1273_CORE - select FW_LOADER - help - Choose Y here if you have this FM radio chip. - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux 2 API. Information on - this API and pointers to "v4l2" programs may be found at - . - - To compile this driver as a module, choose M here: the - module will be called radio-wl1273. - config USB_DSBR tristate "D-Link/GemTek USB FM radio support" depends on USB diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile index 1ff46f3a6ed3..f54693ebdb30 100644 --- a/drivers/media/radio/Makefile +++ b/drivers/media/radio/Makefile @@ -30,7 +30,6 @@ obj-$(CONFIG_RADIO_TERRATEC) += radio-terratec.o obj-$(CONFIG_RADIO_TIMBERDALE) += radio-timb.o obj-$(CONFIG_RADIO_TRUST) += radio-trust.o obj-$(CONFIG_RADIO_TYPHOON) += radio-typhoon.o -obj-$(CONFIG_RADIO_WL1273) += radio-wl1273.o obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o obj-$(CONFIG_USB_DSBR) += dsbr100.o diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c deleted file mode 100644 index f55217ccf2b8..000000000000 --- a/drivers/media/radio/radio-wl1273.c +++ /dev/null @@ -1,2159 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Driver for the Texas Instruments WL1273 FM radio. - * - * Copyright (C) 2011 Nokia Corporation - * Author: Matti J. Aaltonen - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRIVER_DESC "Wl1273 FM Radio" - -#define WL1273_POWER_SET_OFF 0 -#define WL1273_POWER_SET_FM BIT(0) -#define WL1273_POWER_SET_RDS BIT(1) -#define WL1273_POWER_SET_RETENTION BIT(4) - -#define WL1273_PUPD_SET_OFF 0x00 -#define WL1273_PUPD_SET_ON 0x01 -#define WL1273_PUPD_SET_RETENTION 0x10 - -#define WL1273_FREQ(x) (x * 10000 / 625) -#define WL1273_INV_FREQ(x) (x * 625 / 10000) - -/* - * static int radio_nr - The number of the radio device - * - * The default is 0. - */ -static int radio_nr; -module_param(radio_nr, int, 0); -MODULE_PARM_DESC(radio_nr, "The number of the radio device. Default = 0"); - -struct wl1273_device { - char *bus_type; - - u8 forbidden; - unsigned int preemphasis; - unsigned int spacing; - unsigned int tx_power; - unsigned int rx_frequency; - unsigned int tx_frequency; - unsigned int rangelow; - unsigned int rangehigh; - unsigned int band; - bool stereo; - - /* RDS */ - unsigned int rds_on; - - wait_queue_head_t read_queue; - struct mutex lock; /* for serializing fm radio operations */ - struct completion busy; - - unsigned char *buffer; - unsigned int buf_size; - unsigned int rd_index; - unsigned int wr_index; - - /* Selected interrupts */ - u16 irq_flags; - u16 irq_received; - - struct v4l2_ctrl_handler ctrl_handler; - struct v4l2_device v4l2dev; - struct video_device videodev; - struct device *dev; - struct wl1273_core *core; - struct file *owner; - char *write_buf; - unsigned int rds_users; -}; - -#define WL1273_IRQ_MASK (WL1273_FR_EVENT | \ - WL1273_POW_ENB_EVENT) - -/* - * static unsigned int rds_buf - the number of RDS buffer blocks used. - * - * The default number is 100. - */ -static unsigned int rds_buf = 100; -module_param(rds_buf, uint, 0); -MODULE_PARM_DESC(rds_buf, "Number of RDS buffer entries. Default = 100"); - -static int wl1273_fm_write_fw(struct wl1273_core *core, - __u8 *fw, int len) -{ - struct i2c_client *client = core->client; - struct i2c_msg msg; - int i, r = 0; - - msg.addr = client->addr; - msg.flags = 0; - - for (i = 0; i <= len; i++) { - msg.len = fw[0]; - msg.buf = fw + 1; - - fw += msg.len + 1; - dev_dbg(&client->dev, "%s:len[%d]: %d\n", __func__, i, msg.len); - - r = i2c_transfer(client->adapter, &msg, 1); - if (r < 0 && i < len + 1) - break; - } - - dev_dbg(&client->dev, "%s: i: %d\n", __func__, i); - dev_dbg(&client->dev, "%s: len + 1: %d\n", __func__, len + 1); - - /* Last transfer always fails. */ - if (i == len || r == 1) - r = 0; - - return r; -} - -#define WL1273_FIFO_HAS_DATA(status) (1 << 5 & status) -#define WL1273_RDS_CORRECTABLE_ERROR (1 << 3) -#define WL1273_RDS_UNCORRECTABLE_ERROR (1 << 4) - -static int wl1273_fm_rds(struct wl1273_device *radio) -{ - struct wl1273_core *core = radio->core; - struct i2c_client *client = core->client; - u16 val; - u8 b0 = WL1273_RDS_DATA_GET, status; - struct v4l2_rds_data rds = { 0, 0, 0 }; - struct i2c_msg msg[] = { - { - .addr = client->addr, - .flags = 0, - .buf = &b0, - .len = 1, - }, - { - .addr = client->addr, - .flags = I2C_M_RD, - .buf = (u8 *) &rds, - .len = sizeof(rds), - } - }; - int r; - - if (core->mode != WL1273_MODE_RX) - return 0; - - r = core->read(core, WL1273_RDS_SYNC_GET, &val); - if (r) - return r; - - if ((val & 0x01) == 0) { - /* RDS decoder not synchronized */ - return -EAGAIN; - } - - /* copy all four RDS blocks to internal buffer */ - do { - r = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); - if (r != ARRAY_SIZE(msg)) { - dev_err(radio->dev, WL1273_FM_DRIVER_NAME - ": %s: read_rds error r == %i)\n", - __func__, r); - } - - status = rds.block; - - if (!WL1273_FIFO_HAS_DATA(status)) - break; - - /* copy bits 0-2 (the block ID) to bits 3-5 */ - rds.block = V4L2_RDS_BLOCK_MSK & status; - rds.block |= rds.block << 3; - - /* copy the error bits to standard positions */ - if (WL1273_RDS_UNCORRECTABLE_ERROR & status) { - rds.block |= V4L2_RDS_BLOCK_ERROR; - rds.block &= ~V4L2_RDS_BLOCK_CORRECTED; - } else if (WL1273_RDS_CORRECTABLE_ERROR & status) { - rds.block &= ~V4L2_RDS_BLOCK_ERROR; - rds.block |= V4L2_RDS_BLOCK_CORRECTED; - } - - /* copy RDS block to internal buffer */ - memcpy(&radio->buffer[radio->wr_index], &rds, RDS_BLOCK_SIZE); - radio->wr_index += 3; - - /* wrap write pointer */ - if (radio->wr_index >= radio->buf_size) - radio->wr_index = 0; - - /* check for overflow & start over */ - if (radio->wr_index == radio->rd_index) { - dev_dbg(radio->dev, "RDS OVERFLOW"); - - radio->rd_index = 0; - radio->wr_index = 0; - break; - } - } while (WL1273_FIFO_HAS_DATA(status)); - - /* wake up read queue */ - if (radio->wr_index != radio->rd_index) - wake_up_interruptible(&radio->read_queue); - - return 0; -} - -static irqreturn_t wl1273_fm_irq_thread_handler(int irq, void *dev_id) -{ - struct wl1273_device *radio = dev_id; - struct wl1273_core *core = radio->core; - u16 flags; - int r; - - r = core->read(core, WL1273_FLAG_GET, &flags); - if (r) - goto out; - - if (flags & WL1273_BL_EVENT) { - radio->irq_received = flags; - dev_dbg(radio->dev, "IRQ: BL\n"); - } - - if (flags & WL1273_RDS_EVENT) { - msleep(200); - - wl1273_fm_rds(radio); - } - - if (flags & WL1273_BBLK_EVENT) - dev_dbg(radio->dev, "IRQ: BBLK\n"); - - if (flags & WL1273_LSYNC_EVENT) - dev_dbg(radio->dev, "IRQ: LSYNC\n"); - - if (flags & WL1273_LEV_EVENT) { - u16 level; - - r = core->read(core, WL1273_RSSI_LVL_GET, &level); - if (r) - goto out; - - if (level > 14) - dev_dbg(radio->dev, "IRQ: LEV: 0x%x04\n", level); - } - - if (flags & WL1273_IFFR_EVENT) - dev_dbg(radio->dev, "IRQ: IFFR\n"); - - if (flags & WL1273_PI_EVENT) - dev_dbg(radio->dev, "IRQ: PI\n"); - - if (flags & WL1273_PD_EVENT) - dev_dbg(radio->dev, "IRQ: PD\n"); - - if (flags & WL1273_STIC_EVENT) - dev_dbg(radio->dev, "IRQ: STIC\n"); - - if (flags & WL1273_MAL_EVENT) - dev_dbg(radio->dev, "IRQ: MAL\n"); - - if (flags & WL1273_POW_ENB_EVENT) { - complete(&radio->busy); - dev_dbg(radio->dev, "NOT BUSY\n"); - dev_dbg(radio->dev, "IRQ: POW_ENB\n"); - } - - if (flags & WL1273_SCAN_OVER_EVENT) - dev_dbg(radio->dev, "IRQ: SCAN_OVER\n"); - - if (flags & WL1273_ERROR_EVENT) - dev_dbg(radio->dev, "IRQ: ERROR\n"); - - if (flags & WL1273_FR_EVENT) { - u16 freq; - - dev_dbg(radio->dev, "IRQ: FR:\n"); - - if (core->mode == WL1273_MODE_RX) { - r = core->write(core, WL1273_TUNER_MODE_SET, - TUNER_MODE_STOP_SEARCH); - if (r) { - dev_err(radio->dev, - "%s: TUNER_MODE_SET fails: %d\n", - __func__, r); - goto out; - } - - r = core->read(core, WL1273_FREQ_SET, &freq); - if (r) - goto out; - - if (radio->band == WL1273_BAND_JAPAN) - radio->rx_frequency = WL1273_BAND_JAPAN_LOW + - freq * 50; - else - radio->rx_frequency = WL1273_BAND_OTHER_LOW + - freq * 50; - /* - * The driver works better with this msleep, - * the documentation doesn't mention it. - */ - usleep_range(10000, 15000); - - dev_dbg(radio->dev, "%dkHz\n", radio->rx_frequency); - - } else { - r = core->read(core, WL1273_CHANL_SET, &freq); - if (r) - goto out; - - dev_dbg(radio->dev, "%dkHz\n", freq); - } - dev_dbg(radio->dev, "%s: NOT BUSY\n", __func__); - } - -out: - core->write(core, WL1273_INT_MASK_SET, radio->irq_flags); - complete(&radio->busy); - - return IRQ_HANDLED; -} - -static int wl1273_fm_set_tx_freq(struct wl1273_device *radio, unsigned int freq) -{ - struct wl1273_core *core = radio->core; - int r = 0; - unsigned long t; - - if (freq < WL1273_BAND_TX_LOW) { - dev_err(radio->dev, - "Frequency out of range: %d < %d\n", freq, - WL1273_BAND_TX_LOW); - return -ERANGE; - } - - if (freq > WL1273_BAND_TX_HIGH) { - dev_err(radio->dev, - "Frequency out of range: %d > %d\n", freq, - WL1273_BAND_TX_HIGH); - return -ERANGE; - } - - /* - * The driver works better with this sleep, - * the documentation doesn't mention it. - */ - usleep_range(5000, 10000); - - dev_dbg(radio->dev, "%s: freq: %d kHz\n", __func__, freq); - - /* Set the current tx channel */ - r = core->write(core, WL1273_CHANL_SET, freq / 10); - if (r) - return r; - - reinit_completion(&radio->busy); - - /* wait for the FR IRQ */ - t = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(2000)); - if (!t) - return -ETIMEDOUT; - - dev_dbg(radio->dev, "WL1273_CHANL_SET: %lu\n", t); - - /* Enable the output power */ - r = core->write(core, WL1273_POWER_ENB_SET, 1); - if (r) - return r; - - reinit_completion(&radio->busy); - - /* wait for the POWER_ENB IRQ */ - t = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(1000)); - if (!t) - return -ETIMEDOUT; - - radio->tx_frequency = freq; - dev_dbg(radio->dev, "WL1273_POWER_ENB_SET: %lu\n", t); - - return 0; -} - -static int wl1273_fm_set_rx_freq(struct wl1273_device *radio, unsigned int freq) -{ - struct wl1273_core *core = radio->core; - int r, f; - unsigned long t; - - if (freq < radio->rangelow) { - dev_err(radio->dev, - "Frequency out of range: %d < %d\n", freq, - radio->rangelow); - r = -ERANGE; - goto err; - } - - if (freq > radio->rangehigh) { - dev_err(radio->dev, - "Frequency out of range: %d > %d\n", freq, - radio->rangehigh); - r = -ERANGE; - goto err; - } - - dev_dbg(radio->dev, "%s: %dkHz\n", __func__, freq); - - core->write(core, WL1273_INT_MASK_SET, radio->irq_flags); - - if (radio->band == WL1273_BAND_JAPAN) - f = (freq - WL1273_BAND_JAPAN_LOW) / 50; - else - f = (freq - WL1273_BAND_OTHER_LOW) / 50; - - r = core->write(core, WL1273_FREQ_SET, f); - if (r) { - dev_err(radio->dev, "FREQ_SET fails\n"); - goto err; - } - - r = core->write(core, WL1273_TUNER_MODE_SET, TUNER_MODE_PRESET); - if (r) { - dev_err(radio->dev, "TUNER_MODE_SET fails\n"); - goto err; - } - - reinit_completion(&radio->busy); - - t = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(2000)); - if (!t) { - dev_err(radio->dev, "%s: TIMEOUT\n", __func__); - return -ETIMEDOUT; - } - - radio->rd_index = 0; - radio->wr_index = 0; - radio->rx_frequency = freq; - return 0; -err: - return r; -} - -static int wl1273_fm_get_freq(struct wl1273_device *radio) -{ - struct wl1273_core *core = radio->core; - unsigned int freq; - u16 f; - int r; - - if (core->mode == WL1273_MODE_RX) { - r = core->read(core, WL1273_FREQ_SET, &f); - if (r) - return r; - - dev_dbg(radio->dev, "Freq get: 0x%04x\n", f); - if (radio->band == WL1273_BAND_JAPAN) - freq = WL1273_BAND_JAPAN_LOW + 50 * f; - else - freq = WL1273_BAND_OTHER_LOW + 50 * f; - } else { - r = core->read(core, WL1273_CHANL_SET, &f); - if (r) - return r; - - freq = f * 10; - } - - return freq; -} - -/** - * wl1273_fm_upload_firmware_patch() - Upload the firmware. - * @radio: A pointer to the device struct. - * - * The firmware file consists of arrays of bytes where the first byte - * gives the array length. The first byte in the file gives the - * number of these arrays. - */ -static int wl1273_fm_upload_firmware_patch(struct wl1273_device *radio) -{ - struct wl1273_core *core = radio->core; - unsigned int packet_num; - const struct firmware *fw_p; - const char *fw_name = "radio-wl1273-fw.bin"; - struct device *dev = radio->dev; - __u8 *ptr; - int r; - - dev_dbg(dev, "%s:\n", __func__); - - /* - * Uploading the firmware patch is not always necessary, - * so we only print an info message. - */ - if (request_firmware(&fw_p, fw_name, dev)) { - dev_info(dev, "%s - %s not found\n", __func__, fw_name); - - return 0; - } - - ptr = (__u8 *) fw_p->data; - packet_num = ptr[0]; - dev_dbg(dev, "%s: packets: %d\n", __func__, packet_num); - - r = wl1273_fm_write_fw(core, ptr + 1, packet_num); - if (r) { - dev_err(dev, "FW upload error: %d\n", r); - goto out; - } - - /* ignore possible error here */ - core->write(core, WL1273_RESET, 0); - - dev_dbg(dev, "%s - download OK, r: %d\n", __func__, r); -out: - release_firmware(fw_p); - return r; -} - -static int wl1273_fm_stop(struct wl1273_device *radio) -{ - struct wl1273_core *core = radio->core; - - if (core->mode == WL1273_MODE_RX) { - int r = core->write(core, WL1273_POWER_SET, - WL1273_POWER_SET_OFF); - if (r) - dev_err(radio->dev, "%s: POWER_SET fails: %d\n", - __func__, r); - } else if (core->mode == WL1273_MODE_TX) { - int r = core->write(core, WL1273_PUPD_SET, - WL1273_PUPD_SET_OFF); - if (r) - dev_err(radio->dev, - "%s: PUPD_SET fails: %d\n", __func__, r); - } - - if (core->pdata->disable) { - core->pdata->disable(); - dev_dbg(radio->dev, "Back to reset\n"); - } - - return 0; -} - -static int wl1273_fm_start(struct wl1273_device *radio, int new_mode) -{ - struct wl1273_core *core = radio->core; - struct wl1273_fm_platform_data *pdata = core->pdata; - struct device *dev = radio->dev; - int r = -EINVAL; - - if (pdata->enable && core->mode == WL1273_MODE_OFF) { - dev_dbg(radio->dev, "Out of reset\n"); - - pdata->enable(); - msleep(250); - } - - if (new_mode == WL1273_MODE_RX) { - u16 val = WL1273_POWER_SET_FM; - - if (radio->rds_on) - val |= WL1273_POWER_SET_RDS; - - /* If this fails try again */ - r = core->write(core, WL1273_POWER_SET, val); - if (r) { - msleep(100); - - r = core->write(core, WL1273_POWER_SET, val); - if (r) { - dev_err(dev, "%s: POWER_SET fails\n", __func__); - goto fail; - } - } - - /* rds buffer configuration */ - radio->wr_index = 0; - radio->rd_index = 0; - - } else if (new_mode == WL1273_MODE_TX) { - /* If this fails try again once */ - r = core->write(core, WL1273_PUPD_SET, WL1273_PUPD_SET_ON); - if (r) { - msleep(100); - r = core->write(core, WL1273_PUPD_SET, - WL1273_PUPD_SET_ON); - if (r) { - dev_err(dev, "%s: PUPD_SET fails\n", __func__); - goto fail; - } - } - - if (radio->rds_on) { - r = core->write(core, WL1273_RDS_DATA_ENB, 1); - if (r) { - dev_err(dev, "%s: RDS_DATA_ENB ON fails\n", - __func__); - goto fail; - } - } else { - r = core->write(core, WL1273_RDS_DATA_ENB, 0); - if (r) { - dev_err(dev, "%s: RDS_DATA_ENB OFF fails\n", - __func__); - goto fail; - } - } - } else { - dev_warn(dev, "%s: Illegal mode.\n", __func__); - } - - if (core->mode == WL1273_MODE_OFF) { - r = wl1273_fm_upload_firmware_patch(radio); - if (r) - dev_warn(dev, "Firmware upload failed.\n"); - - /* - * Sometimes the chip is in a wrong power state at this point. - * So we set the power once again. - */ - if (new_mode == WL1273_MODE_RX) { - u16 val = WL1273_POWER_SET_FM; - - if (radio->rds_on) - val |= WL1273_POWER_SET_RDS; - - r = core->write(core, WL1273_POWER_SET, val); - if (r) { - dev_err(dev, "%s: POWER_SET fails\n", __func__); - goto fail; - } - } else if (new_mode == WL1273_MODE_TX) { - r = core->write(core, WL1273_PUPD_SET, - WL1273_PUPD_SET_ON); - if (r) { - dev_err(dev, "%s: PUPD_SET fails\n", __func__); - goto fail; - } - } - } - - return 0; -fail: - if (pdata->disable) - pdata->disable(); - - dev_dbg(dev, "%s: return: %d\n", __func__, r); - return r; -} - -static int wl1273_fm_suspend(struct wl1273_device *radio) -{ - struct wl1273_core *core = radio->core; - int r; - - /* Cannot go from OFF to SUSPENDED */ - if (core->mode == WL1273_MODE_RX) - r = core->write(core, WL1273_POWER_SET, - WL1273_POWER_SET_RETENTION); - else if (core->mode == WL1273_MODE_TX) - r = core->write(core, WL1273_PUPD_SET, - WL1273_PUPD_SET_RETENTION); - else - r = -EINVAL; - - if (r) { - dev_err(radio->dev, "%s: POWER_SET fails: %d\n", __func__, r); - goto out; - } - -out: - return r; -} - -static int wl1273_fm_set_mode(struct wl1273_device *radio, int mode) -{ - struct wl1273_core *core = radio->core; - struct device *dev = radio->dev; - int old_mode; - int r; - - dev_dbg(dev, "%s\n", __func__); - dev_dbg(dev, "Forbidden modes: 0x%02x\n", radio->forbidden); - - old_mode = core->mode; - if (mode & radio->forbidden) { - r = -EPERM; - goto out; - } - - switch (mode) { - case WL1273_MODE_RX: - case WL1273_MODE_TX: - r = wl1273_fm_start(radio, mode); - if (r) { - dev_err(dev, "%s: Cannot start.\n", __func__); - wl1273_fm_stop(radio); - goto out; - } - - core->mode = mode; - r = core->write(core, WL1273_INT_MASK_SET, radio->irq_flags); - if (r) { - dev_err(dev, "INT_MASK_SET fails.\n"); - goto out; - } - - /* remember previous settings */ - if (mode == WL1273_MODE_RX) { - r = wl1273_fm_set_rx_freq(radio, radio->rx_frequency); - if (r) { - dev_err(dev, "set freq fails: %d.\n", r); - goto out; - } - - r = core->set_volume(core, core->volume); - if (r) { - dev_err(dev, "set volume fails: %d.\n", r); - goto out; - } - - dev_dbg(dev, "%s: Set vol: %d.\n", __func__, - core->volume); - } else { - r = wl1273_fm_set_tx_freq(radio, radio->tx_frequency); - if (r) { - dev_err(dev, "set freq fails: %d.\n", r); - goto out; - } - } - - dev_dbg(radio->dev, "%s: Set audio mode.\n", __func__); - - r = core->set_audio(core, core->audio_mode); - if (r) - dev_err(dev, "Cannot set audio mode.\n"); - break; - - case WL1273_MODE_OFF: - r = wl1273_fm_stop(radio); - if (r) - dev_err(dev, "%s: Off fails: %d\n", __func__, r); - else - core->mode = WL1273_MODE_OFF; - - break; - - case WL1273_MODE_SUSPENDED: - r = wl1273_fm_suspend(radio); - if (r) - dev_err(dev, "%s: Suspend fails: %d\n", __func__, r); - else - core->mode = WL1273_MODE_SUSPENDED; - - break; - - default: - dev_err(dev, "%s: Unknown mode: %d\n", __func__, mode); - r = -EINVAL; - break; - } -out: - if (r) - core->mode = old_mode; - - return r; -} - -static int wl1273_fm_set_seek(struct wl1273_device *radio, - unsigned int wrap_around, - unsigned int seek_upward, - int level) -{ - struct wl1273_core *core = radio->core; - int r = 0; - unsigned int dir = (seek_upward == 0) ? 0 : 1; - unsigned int f; - - f = radio->rx_frequency; - dev_dbg(radio->dev, "rx_frequency: %d\n", f); - - if (dir && f + radio->spacing <= radio->rangehigh) - r = wl1273_fm_set_rx_freq(radio, f + radio->spacing); - else if (dir && wrap_around) - r = wl1273_fm_set_rx_freq(radio, radio->rangelow); - else if (f - radio->spacing >= radio->rangelow) - r = wl1273_fm_set_rx_freq(radio, f - radio->spacing); - else if (wrap_around) - r = wl1273_fm_set_rx_freq(radio, radio->rangehigh); - - if (r) - goto out; - - if (level < SCHAR_MIN || level > SCHAR_MAX) - return -EINVAL; - - reinit_completion(&radio->busy); - dev_dbg(radio->dev, "%s: BUSY\n", __func__); - - r = core->write(core, WL1273_INT_MASK_SET, radio->irq_flags); - if (r) - goto out; - - dev_dbg(radio->dev, "%s\n", __func__); - - r = core->write(core, WL1273_SEARCH_LVL_SET, level); - if (r) - goto out; - - r = core->write(core, WL1273_SEARCH_DIR_SET, dir); - if (r) - goto out; - - r = core->write(core, WL1273_TUNER_MODE_SET, TUNER_MODE_AUTO_SEEK); - if (r) - goto out; - - /* wait for the FR IRQ */ - wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(1000)); - if (!(radio->irq_received & WL1273_BL_EVENT)) { - r = -ETIMEDOUT; - goto out; - } - - radio->irq_received &= ~WL1273_BL_EVENT; - - if (!wrap_around) - goto out; - - /* Wrap around */ - dev_dbg(radio->dev, "Wrap around in HW seek.\n"); - - if (seek_upward) - f = radio->rangelow; - else - f = radio->rangehigh; - - r = wl1273_fm_set_rx_freq(radio, f); - if (r) - goto out; - - reinit_completion(&radio->busy); - dev_dbg(radio->dev, "%s: BUSY\n", __func__); - - r = core->write(core, WL1273_TUNER_MODE_SET, TUNER_MODE_AUTO_SEEK); - if (r) - goto out; - - /* wait for the FR IRQ */ - if (!wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(1000))) - r = -ETIMEDOUT; -out: - dev_dbg(radio->dev, "%s: Err: %d\n", __func__, r); - return r; -} - -/** - * wl1273_fm_get_tx_ctune() - Get the TX tuning capacitor value. - * @radio: A pointer to the device struct. - */ -static unsigned int wl1273_fm_get_tx_ctune(struct wl1273_device *radio) -{ - struct wl1273_core *core = radio->core; - struct device *dev = radio->dev; - u16 val; - int r; - - if (core->mode == WL1273_MODE_OFF || - core->mode == WL1273_MODE_SUSPENDED) - return -EPERM; - - r = core->read(core, WL1273_READ_FMANT_TUNE_VALUE, &val); - if (r) { - dev_err(dev, "%s: read error: %d\n", __func__, r); - goto out; - } - -out: - return val; -} - -/** - * wl1273_fm_set_preemphasis() - Set the TX pre-emphasis value. - * @radio: A pointer to the device struct. - * @preemphasis: The new pre-amphasis value. - * - * Possible pre-emphasis values are: V4L2_PREEMPHASIS_DISABLED, - * V4L2_PREEMPHASIS_50_uS and V4L2_PREEMPHASIS_75_uS. - */ -static int wl1273_fm_set_preemphasis(struct wl1273_device *radio, - unsigned int preemphasis) -{ - struct wl1273_core *core = radio->core; - int r; - u16 em; - - if (core->mode == WL1273_MODE_OFF || - core->mode == WL1273_MODE_SUSPENDED) - return -EPERM; - - mutex_lock(&core->lock); - - switch (preemphasis) { - case V4L2_PREEMPHASIS_DISABLED: - em = 1; - break; - case V4L2_PREEMPHASIS_50_uS: - em = 0; - break; - case V4L2_PREEMPHASIS_75_uS: - em = 2; - break; - default: - r = -EINVAL; - goto out; - } - - r = core->write(core, WL1273_PREMPH_SET, em); - if (r) - goto out; - - radio->preemphasis = preemphasis; - -out: - mutex_unlock(&core->lock); - return r; -} - -static int wl1273_fm_rds_on(struct wl1273_device *radio) -{ - struct wl1273_core *core = radio->core; - int r; - - dev_dbg(radio->dev, "%s\n", __func__); - if (radio->rds_on) - return 0; - - r = core->write(core, WL1273_POWER_SET, - WL1273_POWER_SET_FM | WL1273_POWER_SET_RDS); - if (r) - goto out; - - r = wl1273_fm_set_rx_freq(radio, radio->rx_frequency); - if (r) - dev_err(radio->dev, "set freq fails: %d.\n", r); -out: - return r; -} - -static int wl1273_fm_rds_off(struct wl1273_device *radio) -{ - struct wl1273_core *core = radio->core; - int r; - - if (!radio->rds_on) - return 0; - - radio->irq_flags &= ~WL1273_RDS_EVENT; - - r = core->write(core, WL1273_INT_MASK_SET, radio->irq_flags); - if (r) - goto out; - - /* Service pending read */ - wake_up_interruptible(&radio->read_queue); - - dev_dbg(radio->dev, "%s\n", __func__); - - r = core->write(core, WL1273_POWER_SET, WL1273_POWER_SET_FM); - if (r) - goto out; - - r = wl1273_fm_set_rx_freq(radio, radio->rx_frequency); - if (r) - dev_err(radio->dev, "set freq fails: %d.\n", r); -out: - dev_dbg(radio->dev, "%s: exiting...\n", __func__); - - return r; -} - -static int wl1273_fm_set_rds(struct wl1273_device *radio, unsigned int new_mode) -{ - int r = 0; - struct wl1273_core *core = radio->core; - - if (core->mode == WL1273_MODE_OFF || - core->mode == WL1273_MODE_SUSPENDED) - return -EPERM; - - if (new_mode == WL1273_RDS_RESET) { - r = core->write(core, WL1273_RDS_CNTRL_SET, 1); - return r; - } - - if (core->mode == WL1273_MODE_TX && new_mode == WL1273_RDS_OFF) { - r = core->write(core, WL1273_RDS_DATA_ENB, 0); - } else if (core->mode == WL1273_MODE_TX && new_mode == WL1273_RDS_ON) { - r = core->write(core, WL1273_RDS_DATA_ENB, 1); - } else if (core->mode == WL1273_MODE_RX && new_mode == WL1273_RDS_OFF) { - r = wl1273_fm_rds_off(radio); - } else if (core->mode == WL1273_MODE_RX && new_mode == WL1273_RDS_ON) { - r = wl1273_fm_rds_on(radio); - } else { - dev_err(radio->dev, "%s: Unknown mode: %d\n", - __func__, new_mode); - r = -EINVAL; - } - - if (!r) - radio->rds_on = new_mode == WL1273_RDS_ON; - - return r; -} - -static ssize_t wl1273_fm_fops_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - u16 val; - int r; - - dev_dbg(radio->dev, "%s\n", __func__); - - if (core->mode != WL1273_MODE_TX) - return count; - - if (radio->rds_users == 0) { - dev_warn(radio->dev, "%s: RDS not on.\n", __func__); - return 0; - } - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - /* - * Multiple processes can open the device, but only - * one gets to write to it. - */ - if (radio->owner && radio->owner != file) { - r = -EBUSY; - goto out; - } - radio->owner = file; - - /* Manual Mode */ - if (count > 255) - val = 255; - else - val = count; - - core->write(core, WL1273_RDS_CONFIG_DATA_SET, val); - - if (copy_from_user(radio->write_buf + 1, buf, val)) { - r = -EFAULT; - goto out; - } - - dev_dbg(radio->dev, "Count: %d\n", val); - dev_dbg(radio->dev, "From user: \"%s\"\n", radio->write_buf); - - radio->write_buf[0] = WL1273_RDS_DATA_SET; - core->write_data(core, radio->write_buf, val + 1); - - r = val; -out: - mutex_unlock(&core->lock); - - return r; -} - -static __poll_t wl1273_fm_fops_poll(struct file *file, - struct poll_table_struct *pts) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - - if (radio->owner && radio->owner != file) - return EPOLLERR; - - radio->owner = file; - - if (core->mode == WL1273_MODE_RX) { - poll_wait(file, &radio->read_queue, pts); - - if (radio->rd_index != radio->wr_index) - return EPOLLIN | EPOLLRDNORM; - - } else if (core->mode == WL1273_MODE_TX) { - return EPOLLOUT | EPOLLWRNORM; - } - - return 0; -} - -static int wl1273_fm_fops_open(struct file *file) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - int r = 0; - - dev_dbg(radio->dev, "%s\n", __func__); - - if (core->mode == WL1273_MODE_RX && radio->rds_on && - !radio->rds_users) { - dev_dbg(radio->dev, "%s: Mode: %d\n", __func__, core->mode); - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - radio->irq_flags |= WL1273_RDS_EVENT; - - r = core->write(core, WL1273_INT_MASK_SET, - radio->irq_flags); - if (r) { - mutex_unlock(&core->lock); - goto out; - } - - radio->rds_users++; - - mutex_unlock(&core->lock); - } -out: - return r; -} - -static int wl1273_fm_fops_release(struct file *file) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - int r = 0; - - dev_dbg(radio->dev, "%s\n", __func__); - - if (radio->rds_users > 0) { - radio->rds_users--; - if (radio->rds_users == 0) { - mutex_lock(&core->lock); - - radio->irq_flags &= ~WL1273_RDS_EVENT; - - if (core->mode == WL1273_MODE_RX) { - r = core->write(core, - WL1273_INT_MASK_SET, - radio->irq_flags); - if (r) { - mutex_unlock(&core->lock); - goto out; - } - } - mutex_unlock(&core->lock); - } - } - - if (file == radio->owner) - radio->owner = NULL; -out: - return r; -} - -static ssize_t wl1273_fm_fops_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - int r = 0; - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - unsigned int block_count = 0; - u16 val; - - dev_dbg(radio->dev, "%s\n", __func__); - - if (core->mode != WL1273_MODE_RX) - return 0; - - if (radio->rds_users == 0) { - dev_warn(radio->dev, "%s: RDS not on.\n", __func__); - return 0; - } - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - /* - * Multiple processes can open the device, but only - * one at a time gets read access. - */ - if (radio->owner && radio->owner != file) { - r = -EBUSY; - goto out; - } - radio->owner = file; - - r = core->read(core, WL1273_RDS_SYNC_GET, &val); - if (r) { - dev_err(radio->dev, "%s: Get RDS_SYNC fails.\n", __func__); - goto out; - } else if (val == 0) { - dev_info(radio->dev, "RDS_SYNC: Not synchronized\n"); - r = -ENODATA; - goto out; - } - - /* block if no new data available */ - while (radio->wr_index == radio->rd_index) { - if (file->f_flags & O_NONBLOCK) { - r = -EWOULDBLOCK; - goto out; - } - - dev_dbg(radio->dev, "%s: Wait for RDS data.\n", __func__); - if (wait_event_interruptible(radio->read_queue, - radio->wr_index != - radio->rd_index) < 0) { - r = -EINTR; - goto out; - } - } - - /* calculate block count from byte count */ - count /= RDS_BLOCK_SIZE; - - /* copy RDS blocks from the internal buffer and to user buffer */ - while (block_count < count) { - if (radio->rd_index == radio->wr_index) - break; - - /* always transfer complete RDS blocks */ - if (copy_to_user(buf, &radio->buffer[radio->rd_index], - RDS_BLOCK_SIZE)) - break; - - /* increment and wrap the read pointer */ - radio->rd_index += RDS_BLOCK_SIZE; - if (radio->rd_index >= radio->buf_size) - radio->rd_index = 0; - - /* increment counters */ - block_count++; - buf += RDS_BLOCK_SIZE; - r += RDS_BLOCK_SIZE; - } - -out: - dev_dbg(radio->dev, "%s: exit\n", __func__); - mutex_unlock(&core->lock); - - return r; -} - -static const struct v4l2_file_operations wl1273_fops = { - .owner = THIS_MODULE, - .read = wl1273_fm_fops_read, - .write = wl1273_fm_fops_write, - .poll = wl1273_fm_fops_poll, - .unlocked_ioctl = video_ioctl2, - .open = wl1273_fm_fops_open, - .release = wl1273_fm_fops_release, -}; - -static int wl1273_fm_vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *capability) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - - dev_dbg(radio->dev, "%s\n", __func__); - - strscpy(capability->driver, WL1273_FM_DRIVER_NAME, - sizeof(capability->driver)); - strscpy(capability->card, "TI Wl1273 FM Radio", - sizeof(capability->card)); - strscpy(capability->bus_info, radio->bus_type, - sizeof(capability->bus_info)); - return 0; -} - -static int wl1273_fm_vidioc_g_input(struct file *file, void *priv, - unsigned int *i) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - - dev_dbg(radio->dev, "%s\n", __func__); - - *i = 0; - - return 0; -} - -static int wl1273_fm_vidioc_s_input(struct file *file, void *priv, - unsigned int i) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - - dev_dbg(radio->dev, "%s\n", __func__); - - if (i != 0) - return -EINVAL; - - return 0; -} - -/** - * wl1273_fm_set_tx_power() - Set the transmission power value. - * @radio: A pointer to the device struct. - * @power: The new power value. - */ -static int wl1273_fm_set_tx_power(struct wl1273_device *radio, u16 power) -{ - struct wl1273_core *core = radio->core; - int r; - - if (core->mode == WL1273_MODE_OFF || - core->mode == WL1273_MODE_SUSPENDED) - return -EPERM; - - mutex_lock(&core->lock); - - /* Convert the dBuV value to chip presentation */ - r = core->write(core, WL1273_POWER_LEV_SET, 122 - power); - if (r) - goto out; - - radio->tx_power = power; - -out: - mutex_unlock(&core->lock); - return r; -} - -#define WL1273_SPACING_50kHz 1 -#define WL1273_SPACING_100kHz 2 -#define WL1273_SPACING_200kHz 4 - -static int wl1273_fm_tx_set_spacing(struct wl1273_device *radio, - unsigned int spacing) -{ - struct wl1273_core *core = radio->core; - int r; - - if (spacing == 0) { - r = core->write(core, WL1273_SCAN_SPACING_SET, - WL1273_SPACING_100kHz); - radio->spacing = 100; - } else if (spacing - 50000 < 25000) { - r = core->write(core, WL1273_SCAN_SPACING_SET, - WL1273_SPACING_50kHz); - radio->spacing = 50; - } else if (spacing - 100000 < 50000) { - r = core->write(core, WL1273_SCAN_SPACING_SET, - WL1273_SPACING_100kHz); - radio->spacing = 100; - } else { - r = core->write(core, WL1273_SCAN_SPACING_SET, - WL1273_SPACING_200kHz); - radio->spacing = 200; - } - - return r; -} - -static int wl1273_fm_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct wl1273_device *radio = ctrl->priv; - struct wl1273_core *core = radio->core; - - dev_dbg(radio->dev, "%s\n", __func__); - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - switch (ctrl->id) { - case V4L2_CID_TUNE_ANTENNA_CAPACITOR: - ctrl->val = wl1273_fm_get_tx_ctune(radio); - break; - - default: - dev_warn(radio->dev, "%s: Unknown IOCTL: %d\n", - __func__, ctrl->id); - break; - } - - mutex_unlock(&core->lock); - - return 0; -} - -#define WL1273_MUTE_SOFT_ENABLE (1 << 0) -#define WL1273_MUTE_AC (1 << 1) -#define WL1273_MUTE_HARD_LEFT (1 << 2) -#define WL1273_MUTE_HARD_RIGHT (1 << 3) -#define WL1273_MUTE_SOFT_FORCE (1 << 4) - -static inline struct wl1273_device *to_radio(struct v4l2_ctrl *ctrl) -{ - return container_of(ctrl->handler, struct wl1273_device, ctrl_handler); -} - -static int wl1273_fm_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct wl1273_device *radio = to_radio(ctrl); - struct wl1273_core *core = radio->core; - int r = 0; - - dev_dbg(radio->dev, "%s\n", __func__); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - if (core->mode == WL1273_MODE_RX && ctrl->val) - r = core->write(core, - WL1273_MUTE_STATUS_SET, - WL1273_MUTE_HARD_LEFT | - WL1273_MUTE_HARD_RIGHT); - else if (core->mode == WL1273_MODE_RX) - r = core->write(core, - WL1273_MUTE_STATUS_SET, 0x0); - else if (core->mode == WL1273_MODE_TX && ctrl->val) - r = core->write(core, WL1273_MUTE, 1); - else if (core->mode == WL1273_MODE_TX) - r = core->write(core, WL1273_MUTE, 0); - - mutex_unlock(&core->lock); - break; - - case V4L2_CID_AUDIO_VOLUME: - if (ctrl->val == 0) - r = wl1273_fm_set_mode(radio, WL1273_MODE_OFF); - else - r = core->set_volume(core, core->volume); - break; - - case V4L2_CID_TUNE_PREEMPHASIS: - r = wl1273_fm_set_preemphasis(radio, ctrl->val); - break; - - case V4L2_CID_TUNE_POWER_LEVEL: - r = wl1273_fm_set_tx_power(radio, ctrl->val); - break; - - default: - dev_warn(radio->dev, "%s: Unknown IOCTL: %d\n", - __func__, ctrl->id); - break; - } - - dev_dbg(radio->dev, "%s\n", __func__); - return r; -} - -static int wl1273_fm_vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *audio) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - - dev_dbg(radio->dev, "%s\n", __func__); - - if (audio->index > 1) - return -EINVAL; - - strscpy(audio->name, "Radio", sizeof(audio->name)); - audio->capability = V4L2_AUDCAP_STEREO; - - return 0; -} - -static int wl1273_fm_vidioc_s_audio(struct file *file, void *priv, - const struct v4l2_audio *audio) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - - dev_dbg(radio->dev, "%s\n", __func__); - - if (audio->index != 0) - return -EINVAL; - - return 0; -} - -#define WL1273_RDS_NOT_SYNCHRONIZED 0 -#define WL1273_RDS_SYNCHRONIZED 1 - -static int wl1273_fm_vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *tuner) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - u16 val; - int r; - - dev_dbg(radio->dev, "%s\n", __func__); - - if (tuner->index > 0) - return -EINVAL; - - strscpy(tuner->name, WL1273_FM_DRIVER_NAME, sizeof(tuner->name)); - tuner->type = V4L2_TUNER_RADIO; - - tuner->rangelow = WL1273_FREQ(WL1273_BAND_JAPAN_LOW); - tuner->rangehigh = WL1273_FREQ(WL1273_BAND_OTHER_HIGH); - - tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_RDS | - V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS_BLOCK_IO | - V4L2_TUNER_CAP_HWSEEK_BOUNDED | V4L2_TUNER_CAP_HWSEEK_WRAP; - - if (radio->stereo) - tuner->audmode = V4L2_TUNER_MODE_STEREO; - else - tuner->audmode = V4L2_TUNER_MODE_MONO; - - if (core->mode != WL1273_MODE_RX) - return 0; - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - r = core->read(core, WL1273_STEREO_GET, &val); - if (r) - goto out; - - if (val == 1) - tuner->rxsubchans = V4L2_TUNER_SUB_STEREO; - else - tuner->rxsubchans = V4L2_TUNER_SUB_MONO; - - r = core->read(core, WL1273_RSSI_LVL_GET, &val); - if (r) - goto out; - - tuner->signal = (s16) val; - dev_dbg(radio->dev, "Signal: %d\n", tuner->signal); - - tuner->afc = 0; - - r = core->read(core, WL1273_RDS_SYNC_GET, &val); - if (r) - goto out; - - if (val == WL1273_RDS_SYNCHRONIZED) - tuner->rxsubchans |= V4L2_TUNER_SUB_RDS; -out: - mutex_unlock(&core->lock); - - return r; -} - -static int wl1273_fm_vidioc_s_tuner(struct file *file, void *priv, - const struct v4l2_tuner *tuner) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - int r = 0; - - dev_dbg(radio->dev, "%s\n", __func__); - dev_dbg(radio->dev, "tuner->index: %d\n", tuner->index); - dev_dbg(radio->dev, "tuner->name: %s\n", tuner->name); - dev_dbg(radio->dev, "tuner->capability: 0x%04x\n", tuner->capability); - dev_dbg(radio->dev, "tuner->rxsubchans: 0x%04x\n", tuner->rxsubchans); - dev_dbg(radio->dev, "tuner->rangelow: %d\n", tuner->rangelow); - dev_dbg(radio->dev, "tuner->rangehigh: %d\n", tuner->rangehigh); - - if (tuner->index > 0) - return -EINVAL; - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - r = wl1273_fm_set_mode(radio, WL1273_MODE_RX); - if (r) - goto out; - - if (tuner->rxsubchans & V4L2_TUNER_SUB_RDS) - r = wl1273_fm_set_rds(radio, WL1273_RDS_ON); - else - r = wl1273_fm_set_rds(radio, WL1273_RDS_OFF); - - if (r) - dev_warn(radio->dev, "%s: RDS fails: %d\n", __func__, r); - - if (tuner->audmode == V4L2_TUNER_MODE_MONO) { - r = core->write(core, WL1273_MOST_MODE_SET, WL1273_RX_MONO); - if (r < 0) { - dev_warn(radio->dev, "%s: MOST_MODE fails: %d\n", - __func__, r); - goto out; - } - radio->stereo = false; - } else if (tuner->audmode == V4L2_TUNER_MODE_STEREO) { - r = core->write(core, WL1273_MOST_MODE_SET, WL1273_RX_STEREO); - if (r < 0) { - dev_warn(radio->dev, "%s: MOST_MODE fails: %d\n", - __func__, r); - goto out; - } - radio->stereo = true; - } else { - dev_err(radio->dev, "%s: tuner->audmode: %d\n", - __func__, tuner->audmode); - r = -EINVAL; - goto out; - } - -out: - mutex_unlock(&core->lock); - - return r; -} - -static int wl1273_fm_vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *freq) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - - dev_dbg(radio->dev, "%s\n", __func__); - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - freq->type = V4L2_TUNER_RADIO; - freq->frequency = WL1273_FREQ(wl1273_fm_get_freq(radio)); - - mutex_unlock(&core->lock); - - return 0; -} - -static int wl1273_fm_vidioc_s_frequency(struct file *file, void *priv, - const struct v4l2_frequency *freq) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - int r; - - dev_dbg(radio->dev, "%s: %d\n", __func__, freq->frequency); - - if (freq->type != V4L2_TUNER_RADIO) { - dev_dbg(radio->dev, - "freq->type != V4L2_TUNER_RADIO: %d\n", freq->type); - return -EINVAL; - } - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - if (core->mode == WL1273_MODE_RX) { - dev_dbg(radio->dev, "freq: %d\n", freq->frequency); - - r = wl1273_fm_set_rx_freq(radio, - WL1273_INV_FREQ(freq->frequency)); - if (r) - dev_warn(radio->dev, WL1273_FM_DRIVER_NAME - ": set frequency failed with %d\n", r); - } else { - r = wl1273_fm_set_tx_freq(radio, - WL1273_INV_FREQ(freq->frequency)); - if (r) - dev_warn(radio->dev, WL1273_FM_DRIVER_NAME - ": set frequency failed with %d\n", r); - } - - mutex_unlock(&core->lock); - - dev_dbg(radio->dev, "wl1273_vidioc_s_frequency: DONE\n"); - return r; -} - -#define WL1273_DEFAULT_SEEK_LEVEL 7 - -static int wl1273_fm_vidioc_s_hw_freq_seek(struct file *file, void *priv, - const struct v4l2_hw_freq_seek *seek) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - int r; - - dev_dbg(radio->dev, "%s\n", __func__); - - if (seek->tuner != 0 || seek->type != V4L2_TUNER_RADIO) - return -EINVAL; - - if (file->f_flags & O_NONBLOCK) - return -EWOULDBLOCK; - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - r = wl1273_fm_set_mode(radio, WL1273_MODE_RX); - if (r) - goto out; - - r = wl1273_fm_tx_set_spacing(radio, seek->spacing); - if (r) - dev_warn(radio->dev, "HW seek failed: %d\n", r); - - r = wl1273_fm_set_seek(radio, seek->wrap_around, seek->seek_upward, - WL1273_DEFAULT_SEEK_LEVEL); - if (r) - dev_warn(radio->dev, "HW seek failed: %d\n", r); - -out: - mutex_unlock(&core->lock); - return r; -} - -static int wl1273_fm_vidioc_s_modulator(struct file *file, void *priv, - const struct v4l2_modulator *modulator) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - int r = 0; - - dev_dbg(radio->dev, "%s\n", __func__); - - if (modulator->index > 0) - return -EINVAL; - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - r = wl1273_fm_set_mode(radio, WL1273_MODE_TX); - if (r) - goto out; - - if (modulator->txsubchans & V4L2_TUNER_SUB_RDS) - r = wl1273_fm_set_rds(radio, WL1273_RDS_ON); - else - r = wl1273_fm_set_rds(radio, WL1273_RDS_OFF); - - if (modulator->txsubchans & V4L2_TUNER_SUB_MONO) - r = core->write(core, WL1273_MONO_SET, WL1273_TX_MONO); - else - r = core->write(core, WL1273_MONO_SET, - WL1273_RX_STEREO); - if (r < 0) - dev_warn(radio->dev, WL1273_FM_DRIVER_NAME - "MONO_SET fails: %d\n", r); -out: - mutex_unlock(&core->lock); - - return r; -} - -static int wl1273_fm_vidioc_g_modulator(struct file *file, void *priv, - struct v4l2_modulator *modulator) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - u16 val; - int r; - - dev_dbg(radio->dev, "%s\n", __func__); - - strscpy(modulator->name, WL1273_FM_DRIVER_NAME, - sizeof(modulator->name)); - - modulator->rangelow = WL1273_FREQ(WL1273_BAND_JAPAN_LOW); - modulator->rangehigh = WL1273_FREQ(WL1273_BAND_OTHER_HIGH); - - modulator->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_RDS | - V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS_BLOCK_IO; - - if (core->mode != WL1273_MODE_TX) - return 0; - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - r = core->read(core, WL1273_MONO_SET, &val); - if (r) - goto out; - - if (val == WL1273_TX_STEREO) - modulator->txsubchans = V4L2_TUNER_SUB_STEREO; - else - modulator->txsubchans = V4L2_TUNER_SUB_MONO; - - if (radio->rds_on) - modulator->txsubchans |= V4L2_TUNER_SUB_RDS; -out: - mutex_unlock(&core->lock); - - return 0; -} - -static int wl1273_fm_vidioc_log_status(struct file *file, void *priv) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - struct device *dev = radio->dev; - u16 val; - int r; - - dev_info(dev, DRIVER_DESC); - - if (core->mode == WL1273_MODE_OFF) { - dev_info(dev, "Mode: Off\n"); - return 0; - } - - if (core->mode == WL1273_MODE_SUSPENDED) { - dev_info(dev, "Mode: Suspended\n"); - return 0; - } - - r = core->read(core, WL1273_ASIC_ID_GET, &val); - if (r) - dev_err(dev, "%s: Get ASIC_ID fails.\n", __func__); - else - dev_info(dev, "ASIC_ID: 0x%04x\n", val); - - r = core->read(core, WL1273_ASIC_VER_GET, &val); - if (r) - dev_err(dev, "%s: Get ASIC_VER fails.\n", __func__); - else - dev_info(dev, "ASIC Version: 0x%04x\n", val); - - r = core->read(core, WL1273_FIRM_VER_GET, &val); - if (r) - dev_err(dev, "%s: Get FIRM_VER fails.\n", __func__); - else - dev_info(dev, "FW version: %d(0x%04x)\n", val, val); - - r = core->read(core, WL1273_BAND_SET, &val); - if (r) - dev_err(dev, "%s: Get BAND fails.\n", __func__); - else - dev_info(dev, "BAND: %d\n", val); - - if (core->mode == WL1273_MODE_TX) { - r = core->read(core, WL1273_PUPD_SET, &val); - if (r) - dev_err(dev, "%s: Get PUPD fails.\n", __func__); - else - dev_info(dev, "PUPD: 0x%04x\n", val); - - r = core->read(core, WL1273_CHANL_SET, &val); - if (r) - dev_err(dev, "%s: Get CHANL fails.\n", __func__); - else - dev_info(dev, "Tx frequency: %dkHz\n", val*10); - } else if (core->mode == WL1273_MODE_RX) { - int bf = radio->rangelow; - - r = core->read(core, WL1273_FREQ_SET, &val); - if (r) - dev_err(dev, "%s: Get FREQ fails.\n", __func__); - else - dev_info(dev, "RX Frequency: %dkHz\n", bf + val*50); - - r = core->read(core, WL1273_MOST_MODE_SET, &val); - if (r) - dev_err(dev, "%s: Get MOST_MODE fails.\n", - __func__); - else if (val == 0) - dev_info(dev, "MOST_MODE: Stereo according to blend\n"); - else if (val == 1) - dev_info(dev, "MOST_MODE: Force mono output\n"); - else - dev_info(dev, "MOST_MODE: Unexpected value: %d\n", val); - - r = core->read(core, WL1273_MOST_BLEND_SET, &val); - if (r) - dev_err(dev, "%s: Get MOST_BLEND fails.\n", __func__); - else if (val == 0) - dev_info(dev, - "MOST_BLEND: Switched blend & hysteresis.\n"); - else if (val == 1) - dev_info(dev, "MOST_BLEND: Soft blend.\n"); - else - dev_info(dev, "MOST_BLEND: Unexpected val: %d\n", val); - - r = core->read(core, WL1273_STEREO_GET, &val); - if (r) - dev_err(dev, "%s: Get STEREO fails.\n", __func__); - else if (val == 0) - dev_info(dev, "STEREO: Not detected\n"); - else if (val == 1) - dev_info(dev, "STEREO: Detected\n"); - else - dev_info(dev, "STEREO: Unexpected value: %d\n", val); - - r = core->read(core, WL1273_RSSI_LVL_GET, &val); - if (r) - dev_err(dev, "%s: Get RSSI_LVL fails.\n", __func__); - else - dev_info(dev, "RX signal strength: %d\n", (s16) val); - - r = core->read(core, WL1273_POWER_SET, &val); - if (r) - dev_err(dev, "%s: Get POWER fails.\n", __func__); - else - dev_info(dev, "POWER: 0x%04x\n", val); - - r = core->read(core, WL1273_INT_MASK_SET, &val); - if (r) - dev_err(dev, "%s: Get INT_MASK fails.\n", __func__); - else - dev_info(dev, "INT_MASK: 0x%04x\n", val); - - r = core->read(core, WL1273_RDS_SYNC_GET, &val); - if (r) - dev_err(dev, "%s: Get RDS_SYNC fails.\n", - __func__); - else if (val == 0) - dev_info(dev, "RDS_SYNC: Not synchronized\n"); - - else if (val == 1) - dev_info(dev, "RDS_SYNC: Synchronized\n"); - else - dev_info(dev, "RDS_SYNC: Unexpected value: %d\n", val); - - r = core->read(core, WL1273_I2S_MODE_CONFIG_SET, &val); - if (r) - dev_err(dev, "%s: Get I2S_MODE_CONFIG fails.\n", - __func__); - else - dev_info(dev, "I2S_MODE_CONFIG: 0x%04x\n", val); - - r = core->read(core, WL1273_VOLUME_SET, &val); - if (r) - dev_err(dev, "%s: Get VOLUME fails.\n", __func__); - else - dev_info(dev, "VOLUME: 0x%04x\n", val); - } - - return 0; -} - -static void wl1273_vdev_release(struct video_device *dev) -{ -} - -static const struct v4l2_ctrl_ops wl1273_ctrl_ops = { - .s_ctrl = wl1273_fm_s_ctrl, - .g_volatile_ctrl = wl1273_fm_g_volatile_ctrl, -}; - -static const struct v4l2_ioctl_ops wl1273_ioctl_ops = { - .vidioc_querycap = wl1273_fm_vidioc_querycap, - .vidioc_g_input = wl1273_fm_vidioc_g_input, - .vidioc_s_input = wl1273_fm_vidioc_s_input, - .vidioc_g_audio = wl1273_fm_vidioc_g_audio, - .vidioc_s_audio = wl1273_fm_vidioc_s_audio, - .vidioc_g_tuner = wl1273_fm_vidioc_g_tuner, - .vidioc_s_tuner = wl1273_fm_vidioc_s_tuner, - .vidioc_g_frequency = wl1273_fm_vidioc_g_frequency, - .vidioc_s_frequency = wl1273_fm_vidioc_s_frequency, - .vidioc_s_hw_freq_seek = wl1273_fm_vidioc_s_hw_freq_seek, - .vidioc_g_modulator = wl1273_fm_vidioc_g_modulator, - .vidioc_s_modulator = wl1273_fm_vidioc_s_modulator, - .vidioc_log_status = wl1273_fm_vidioc_log_status, -}; - -static const struct video_device wl1273_viddev_template = { - .fops = &wl1273_fops, - .ioctl_ops = &wl1273_ioctl_ops, - .name = WL1273_FM_DRIVER_NAME, - .release = wl1273_vdev_release, - .vfl_dir = VFL_DIR_TX, - .device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER | - V4L2_CAP_RADIO | V4L2_CAP_AUDIO | - V4L2_CAP_RDS_CAPTURE | V4L2_CAP_MODULATOR | - V4L2_CAP_RDS_OUTPUT, -}; - -static void wl1273_fm_radio_remove(struct platform_device *pdev) -{ - struct wl1273_device *radio = platform_get_drvdata(pdev); - struct wl1273_core *core = radio->core; - - dev_info(&pdev->dev, "%s.\n", __func__); - - free_irq(core->client->irq, radio); - core->pdata->free_resources(); - - v4l2_ctrl_handler_free(&radio->ctrl_handler); - video_unregister_device(&radio->videodev); - v4l2_device_unregister(&radio->v4l2dev); -} - -static int wl1273_fm_radio_probe(struct platform_device *pdev) -{ - struct wl1273_core **core = pdev->dev.platform_data; - struct wl1273_device *radio; - struct v4l2_ctrl *ctrl; - int r = 0; - - pr_debug("%s\n", __func__); - - if (!core) { - dev_err(&pdev->dev, "No platform data.\n"); - r = -EINVAL; - goto pdata_err; - } - - radio = devm_kzalloc(&pdev->dev, sizeof(*radio), GFP_KERNEL); - if (!radio) { - r = -ENOMEM; - goto pdata_err; - } - - /* RDS buffer allocation */ - radio->buf_size = rds_buf * RDS_BLOCK_SIZE; - radio->buffer = devm_kzalloc(&pdev->dev, radio->buf_size, GFP_KERNEL); - if (!radio->buffer) { - pr_err("Cannot allocate memory for RDS buffer.\n"); - r = -ENOMEM; - goto pdata_err; - } - - radio->core = *core; - radio->irq_flags = WL1273_IRQ_MASK; - radio->dev = &radio->core->client->dev; - radio->rds_on = false; - radio->core->mode = WL1273_MODE_OFF; - radio->tx_power = 118; - radio->core->audio_mode = WL1273_AUDIO_ANALOG; - radio->band = WL1273_BAND_OTHER; - radio->core->i2s_mode = WL1273_I2S_DEF_MODE; - radio->core->channel_number = 2; - radio->core->volume = WL1273_DEFAULT_VOLUME; - radio->rx_frequency = WL1273_BAND_OTHER_LOW; - radio->tx_frequency = WL1273_BAND_OTHER_HIGH; - radio->rangelow = WL1273_BAND_OTHER_LOW; - radio->rangehigh = WL1273_BAND_OTHER_HIGH; - radio->stereo = true; - radio->bus_type = "I2C"; - - if (radio->core->pdata->request_resources) { - r = radio->core->pdata->request_resources(radio->core->client); - if (r) { - dev_err(radio->dev, WL1273_FM_DRIVER_NAME - ": Cannot get platform data\n"); - goto pdata_err; - } - - dev_dbg(radio->dev, "irq: %d\n", radio->core->client->irq); - - r = request_threaded_irq(radio->core->client->irq, NULL, - wl1273_fm_irq_thread_handler, - IRQF_ONESHOT | IRQF_TRIGGER_FALLING, - "wl1273-fm", radio); - if (r < 0) { - dev_err(radio->dev, WL1273_FM_DRIVER_NAME - ": Unable to register IRQ handler: %d\n", r); - goto err_request_irq; - } - } else { - dev_err(radio->dev, WL1273_FM_DRIVER_NAME ": Core WL1273 IRQ not configured"); - r = -EINVAL; - goto pdata_err; - } - - init_completion(&radio->busy); - init_waitqueue_head(&radio->read_queue); - - radio->write_buf = devm_kzalloc(&pdev->dev, 256, GFP_KERNEL); - if (!radio->write_buf) { - r = -ENOMEM; - goto write_buf_err; - } - - radio->dev = &pdev->dev; - radio->v4l2dev.ctrl_handler = &radio->ctrl_handler; - radio->rds_users = 0; - - r = v4l2_device_register(&pdev->dev, &radio->v4l2dev); - if (r) { - dev_err(&pdev->dev, "Cannot register v4l2_device.\n"); - goto write_buf_err; - } - - /* V4L2 configuration */ - radio->videodev = wl1273_viddev_template; - - radio->videodev.v4l2_dev = &radio->v4l2dev; - - v4l2_ctrl_handler_init(&radio->ctrl_handler, 6); - - /* add in ascending ID order */ - v4l2_ctrl_new_std(&radio->ctrl_handler, &wl1273_ctrl_ops, - V4L2_CID_AUDIO_VOLUME, 0, WL1273_MAX_VOLUME, 1, - WL1273_DEFAULT_VOLUME); - - v4l2_ctrl_new_std(&radio->ctrl_handler, &wl1273_ctrl_ops, - V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); - - v4l2_ctrl_new_std_menu(&radio->ctrl_handler, &wl1273_ctrl_ops, - V4L2_CID_TUNE_PREEMPHASIS, - V4L2_PREEMPHASIS_75_uS, 0x03, - V4L2_PREEMPHASIS_50_uS); - - v4l2_ctrl_new_std(&radio->ctrl_handler, &wl1273_ctrl_ops, - V4L2_CID_TUNE_POWER_LEVEL, 91, 122, 1, 118); - - ctrl = v4l2_ctrl_new_std(&radio->ctrl_handler, &wl1273_ctrl_ops, - V4L2_CID_TUNE_ANTENNA_CAPACITOR, - 0, 255, 1, 255); - if (ctrl) - ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; - - if (radio->ctrl_handler.error) { - r = radio->ctrl_handler.error; - dev_err(&pdev->dev, "Ctrl handler error: %d\n", r); - goto handler_init_err; - } - - video_set_drvdata(&radio->videodev, radio); - platform_set_drvdata(pdev, radio); - - /* register video device */ - r = video_register_device(&radio->videodev, VFL_TYPE_RADIO, radio_nr); - if (r) { - dev_err(&pdev->dev, WL1273_FM_DRIVER_NAME - ": Could not register video device\n"); - goto handler_init_err; - } - - return 0; - -handler_init_err: - v4l2_ctrl_handler_free(&radio->ctrl_handler); - v4l2_device_unregister(&radio->v4l2dev); -write_buf_err: - free_irq(radio->core->client->irq, radio); -err_request_irq: - radio->core->pdata->free_resources(); -pdata_err: - return r; -} - -static struct platform_driver wl1273_fm_radio_driver = { - .probe = wl1273_fm_radio_probe, - .remove = wl1273_fm_radio_remove, - .driver = { - .name = "wl1273_fm_radio", - }, -}; - -module_platform_driver(wl1273_fm_radio_driver); - -MODULE_AUTHOR("Matti Aaltonen "); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:wl1273_fm_radio"); From 2ce99accf39b1e4fd979a70093711edeb7c979b4 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:29:43 +0300 Subject: [PATCH 00501/11391] media: pci: saa7164: Store v4l2_fh pointer in file->private_data Most V4L2 drivers store the v4l2_fh pointer in file->private_data. The saa7164 instead stores the pointer to the driver-specific structure that embeds the v4l2_fh. Switch to storing the v4l2_fh pointer itself to standardize behaviour across drivers. This also prepares for future refactoring that depends on v4l2_fh being stored in private_data. This also fixes a bug in the vidioc_g_std() in saa7164-vbi.c that casts the private_data void pointer to a saa7164_encoder_fh instead of a saa7164_vbi_fh. The bug has no practical consequence as the two structures are identical. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/pci/saa7164/saa7164-encoder.c | 27 ++++++++++----------- drivers/media/pci/saa7164/saa7164-vbi.c | 22 ++++++++--------- drivers/media/pci/saa7164/saa7164.h | 10 ++++++++ 3 files changed, 34 insertions(+), 25 deletions(-) diff --git a/drivers/media/pci/saa7164/saa7164-encoder.c b/drivers/media/pci/saa7164/saa7164-encoder.c index bf73e9e83f52..296f50b6b8d3 100644 --- a/drivers/media/pci/saa7164/saa7164-encoder.c +++ b/drivers/media/pci/saa7164/saa7164-encoder.c @@ -219,7 +219,7 @@ int saa7164_s_std(struct saa7164_port *port, v4l2_std_id id) static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) { - struct saa7164_encoder_fh *fh = file->private_data; + struct saa7164_encoder_fh *fh = to_saa7164_encoder_fh(file); return saa7164_s_std(fh->port, id); } @@ -232,7 +232,7 @@ int saa7164_g_std(struct saa7164_port *port, v4l2_std_id *id) static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) { - struct saa7164_encoder_fh *fh = file->private_data; + struct saa7164_encoder_fh *fh = to_saa7164_encoder_fh(file); return saa7164_g_std(fh->port, id); } @@ -277,7 +277,7 @@ int saa7164_g_input(struct saa7164_port *port, unsigned int *i) static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) { - struct saa7164_encoder_fh *fh = file->private_data; + struct saa7164_encoder_fh *fh = to_saa7164_encoder_fh(file); return saa7164_g_input(fh->port, i); } @@ -301,14 +301,14 @@ int saa7164_s_input(struct saa7164_port *port, unsigned int i) static int vidioc_s_input(struct file *file, void *priv, unsigned int i) { - struct saa7164_encoder_fh *fh = file->private_data; + struct saa7164_encoder_fh *fh = to_saa7164_encoder_fh(file); return saa7164_s_input(fh->port, i); } int saa7164_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { - struct saa7164_encoder_fh *fh = file->private_data; + struct saa7164_encoder_fh *fh = to_saa7164_encoder_fh(file); struct saa7164_port *port = fh->port; struct saa7164_dev *dev = port->dev; @@ -347,7 +347,7 @@ int saa7164_g_frequency(struct saa7164_port *port, struct v4l2_frequency *f) static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct saa7164_encoder_fh *fh = file->private_data; + struct saa7164_encoder_fh *fh = to_saa7164_encoder_fh(file); return saa7164_g_frequency(fh->port, f); } @@ -400,7 +400,7 @@ int saa7164_s_frequency(struct saa7164_port *port, static int vidioc_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *f) { - struct saa7164_encoder_fh *fh = file->private_data; + struct saa7164_encoder_fh *fh = to_saa7164_encoder_fh(file); return saa7164_s_frequency(fh->port, f); } @@ -483,7 +483,7 @@ static int saa7164_s_ctrl(struct v4l2_ctrl *ctrl) static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct saa7164_encoder_fh *fh = file->private_data; + struct saa7164_encoder_fh *fh = to_saa7164_encoder_fh(file); struct saa7164_port *port = fh->port; struct saa7164_dev *dev = port->dev; @@ -510,7 +510,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, static int vidioc_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct saa7164_encoder_fh *fh = file->private_data; + struct saa7164_encoder_fh *fh = to_saa7164_encoder_fh(file); struct saa7164_port *port = fh->port; f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; @@ -726,14 +726,14 @@ static int fops_open(struct file *file) fh->port = port; v4l2_fh_init(&fh->fh, video_devdata(file)); v4l2_fh_add(&fh->fh); - file->private_data = fh; + file->private_data = &fh->fh; return 0; } static int fops_release(struct file *file) { - struct saa7164_encoder_fh *fh = file->private_data; + struct saa7164_encoder_fh *fh = to_saa7164_encoder_fh(file); struct saa7164_port *port = fh->port; struct saa7164_dev *dev = port->dev; @@ -787,7 +787,7 @@ saa7164_user_buffer *saa7164_enc_next_buf(struct saa7164_port *port) static ssize_t fops_read(struct file *file, char __user *buffer, size_t count, loff_t *pos) { - struct saa7164_encoder_fh *fh = file->private_data; + struct saa7164_encoder_fh *fh = to_saa7164_encoder_fh(file); struct saa7164_port *port = fh->port; struct saa7164_user_buffer *ubuf = NULL; struct saa7164_dev *dev = port->dev; @@ -893,8 +893,7 @@ static ssize_t fops_read(struct file *file, char __user *buffer, static __poll_t fops_poll(struct file *file, poll_table *wait) { __poll_t req_events = poll_requested_events(wait); - struct saa7164_encoder_fh *fh = - (struct saa7164_encoder_fh *)file->private_data; + struct saa7164_encoder_fh *fh = to_saa7164_encoder_fh(file); struct saa7164_port *port = fh->port; __poll_t mask = v4l2_ctrl_poll(file, wait); diff --git a/drivers/media/pci/saa7164/saa7164-vbi.c b/drivers/media/pci/saa7164/saa7164-vbi.c index ac958a5fca78..a7e398f30472 100644 --- a/drivers/media/pci/saa7164/saa7164-vbi.c +++ b/drivers/media/pci/saa7164/saa7164-vbi.c @@ -144,28 +144,28 @@ static int saa7164_vbi_initialize(struct saa7164_port *port) /* -- V4L2 --------------------------------------------------------- */ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) { - struct saa7164_vbi_fh *fh = file->private_data; + struct saa7164_vbi_fh *fh = to_saa7164_vbi_fh(file); return saa7164_s_std(fh->port->enc_port, id); } static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) { - struct saa7164_encoder_fh *fh = file->private_data; + struct saa7164_vbi_fh *fh = to_saa7164_vbi_fh(file); return saa7164_g_std(fh->port->enc_port, id); } static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) { - struct saa7164_vbi_fh *fh = file->private_data; + struct saa7164_vbi_fh *fh = to_saa7164_vbi_fh(file); return saa7164_g_input(fh->port->enc_port, i); } static int vidioc_s_input(struct file *file, void *priv, unsigned int i) { - struct saa7164_vbi_fh *fh = file->private_data; + struct saa7164_vbi_fh *fh = to_saa7164_vbi_fh(file); return saa7164_s_input(fh->port->enc_port, i); } @@ -173,7 +173,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct saa7164_vbi_fh *fh = file->private_data; + struct saa7164_vbi_fh *fh = to_saa7164_vbi_fh(file); return saa7164_g_frequency(fh->port->enc_port, f); } @@ -181,7 +181,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, static int vidioc_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *f) { - struct saa7164_vbi_fh *fh = file->private_data; + struct saa7164_vbi_fh *fh = to_saa7164_vbi_fh(file); int ret = saa7164_s_frequency(fh->port->enc_port, f); if (ret == 0) @@ -192,7 +192,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct saa7164_vbi_fh *fh = file->private_data; + struct saa7164_vbi_fh *fh = to_saa7164_vbi_fh(file); struct saa7164_port *port = fh->port; struct saa7164_dev *dev = port->dev; @@ -429,14 +429,14 @@ static int fops_open(struct file *file) fh->port = port; v4l2_fh_init(&fh->fh, video_devdata(file)); v4l2_fh_add(&fh->fh); - file->private_data = fh; + file->private_data = &fh->fh; return 0; } static int fops_release(struct file *file) { - struct saa7164_vbi_fh *fh = file->private_data; + struct saa7164_vbi_fh *fh = to_saa7164_vbi_fh(file); struct saa7164_port *port = fh->port; struct saa7164_dev *dev = port->dev; @@ -489,7 +489,7 @@ saa7164_user_buffer *saa7164_vbi_next_buf(struct saa7164_port *port) static ssize_t fops_read(struct file *file, char __user *buffer, size_t count, loff_t *pos) { - struct saa7164_vbi_fh *fh = file->private_data; + struct saa7164_vbi_fh *fh = to_saa7164_vbi_fh(file); struct saa7164_port *port = fh->port; struct saa7164_user_buffer *ubuf = NULL; struct saa7164_dev *dev = port->dev; @@ -596,7 +596,7 @@ static ssize_t fops_read(struct file *file, char __user *buffer, static __poll_t fops_poll(struct file *file, poll_table *wait) { - struct saa7164_vbi_fh *fh = (struct saa7164_vbi_fh *)file->private_data; + struct saa7164_vbi_fh *fh = to_saa7164_vbi_fh(file); struct saa7164_port *port = fh->port; __poll_t mask = 0; diff --git a/drivers/media/pci/saa7164/saa7164.h b/drivers/media/pci/saa7164/saa7164.h index e1bac1fe19d3..7b511f7f1cfc 100644 --- a/drivers/media/pci/saa7164/saa7164.h +++ b/drivers/media/pci/saa7164/saa7164.h @@ -180,12 +180,22 @@ struct saa7164_encoder_fh { atomic_t v4l_reading; }; +static inline struct saa7164_encoder_fh *to_saa7164_encoder_fh(struct file *filp) +{ + return container_of(filp->private_data, struct saa7164_encoder_fh, fh); +} + struct saa7164_vbi_fh { struct v4l2_fh fh; struct saa7164_port *port; atomic_t v4l_reading; }; +static inline struct saa7164_vbi_fh *to_saa7164_vbi_fh(struct file *filp) +{ + return container_of(filp->private_data, struct saa7164_vbi_fh, fh); +} + struct saa7164_histogram_bucket { u32 val; u32 count; From 5d8d523d3652970be0c13c08dedfab47feed4033 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:29:44 +0300 Subject: [PATCH 00502/11391] media: imagination: Store v4l2_fh pointer in file->private_data Most V4L2 drivers store the v4l2_fh pointer in file->private_data. The e5010-jpeg-enc driver instead stores the pointer to the driver-specific structure that embeds the v4l2_fh. Switch to storing the v4l2_fh pointer itself to standardize behaviour across drivers. This also prepares for future refactoring that depends on v4l2_fh being stored in private_data. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- .../platform/imagination/e5010-jpeg-enc.c | 18 +++++++++--------- .../platform/imagination/e5010-jpeg-enc.h | 5 +++++ 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/imagination/e5010-jpeg-enc.c b/drivers/media/platform/imagination/e5010-jpeg-enc.c index ae868d9f73e1..295461325862 100644 --- a/drivers/media/platform/imagination/e5010-jpeg-enc.c +++ b/drivers/media/platform/imagination/e5010-jpeg-enc.c @@ -253,7 +253,7 @@ static int e5010_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f) { int i, index = 0; struct e5010_fmt *fmt = NULL; - struct e5010_context *ctx = file->private_data; + struct e5010_context *ctx = to_e5010_context(file); if (!V4L2_TYPE_IS_MULTIPLANAR(f->type)) { v4l2_err(&ctx->e5010->v4l2_dev, "ENUMFMT with Invalid type: %d\n", f->type); @@ -279,7 +279,7 @@ static int e5010_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f) static int e5010_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct e5010_context *ctx = file->private_data; + struct e5010_context *ctx = to_e5010_context(file); struct e5010_q_data *queue; int i; struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; @@ -380,14 +380,14 @@ static int e5010_jpeg_try_fmt(struct v4l2_format *f, struct e5010_context *ctx) static int e5010_try_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct e5010_context *ctx = file->private_data; + struct e5010_context *ctx = to_e5010_context(file); return e5010_jpeg_try_fmt(f, ctx); } static int e5010_s_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct e5010_context *ctx = file->private_data; + struct e5010_context *ctx = to_e5010_context(file); struct vb2_queue *vq; int ret = 0, i = 0; struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; @@ -462,7 +462,7 @@ static int e5010_enum_framesizes(struct file *file, void *priv, struct v4l2_frms static int e5010_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct e5010_context *ctx = file->private_data; + struct e5010_context *ctx = to_e5010_context(file); struct e5010_q_data *queue; if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) @@ -490,7 +490,7 @@ static int e5010_g_selection(struct file *file, void *fh, struct v4l2_selection static int e5010_s_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct e5010_context *ctx = file->private_data; + struct e5010_context *ctx = to_e5010_context(file); struct e5010_q_data *queue; struct vb2_queue *vq; struct v4l2_rect base_rect; @@ -742,7 +742,7 @@ static int e5010_open(struct file *file) } v4l2_fh_init(&ctx->fh, vdev); - file->private_data = ctx; + file->private_data = &ctx->fh; v4l2_fh_add(&ctx->fh); ctx->e5010 = e5010; @@ -781,7 +781,7 @@ static int e5010_open(struct file *file) static int e5010_release(struct file *file) { struct e5010_dev *e5010 = video_drvdata(file); - struct e5010_context *ctx = file->private_data; + struct e5010_context *ctx = to_e5010_context(file); dprintk(e5010, 1, "Releasing instance: 0x%p, m2m_ctx: 0x%p\n", ctx, ctx->fh.m2m_ctx); mutex_lock(&e5010->mutex); @@ -1262,7 +1262,7 @@ static void e5010_buf_queue(struct vb2_buffer *vb) static int e5010_encoder_cmd(struct file *file, void *priv, struct v4l2_encoder_cmd *cmd) { - struct e5010_context *ctx = file->private_data; + struct e5010_context *ctx = to_e5010_context(file); int ret; struct vb2_queue *cap_vq; diff --git a/drivers/media/platform/imagination/e5010-jpeg-enc.h b/drivers/media/platform/imagination/e5010-jpeg-enc.h index 71f49ead6898..eefaf60489d3 100644 --- a/drivers/media/platform/imagination/e5010-jpeg-enc.h +++ b/drivers/media/platform/imagination/e5010-jpeg-enc.h @@ -120,6 +120,11 @@ struct e5010_context { u8 chroma_qp[QP_TABLE_SIZE]; }; +static inline struct e5010_context *to_e5010_context(struct file *filp) +{ + return container_of(filp->private_data, struct e5010_context, fh); +} + /* * Buffer structure * Contains info for all buffers From 597944ffa034223e5a7da380eb7b302c5ba64b79 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:29:45 +0300 Subject: [PATCH 00503/11391] media: ti: vpe: Store v4l2_fh pointer in file->private_data Most V4L2 drivers store the v4l2_fh pointer in file->private_data. The ti-vpe driver instead stores the pointer to the driver-specific structure that embeds the v4l2_fh. Switch to storing the v4l2_fh pointer itself to standardize behaviour across drivers. This also prepares for future refactoring that depends on v4l2_fh being stored in private_data. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/platform/ti/vpe/vpe.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/ti/vpe/vpe.c b/drivers/media/platform/ti/vpe/vpe.c index 636d76ecebcd..b76b5d18c963 100644 --- a/drivers/media/platform/ti/vpe/vpe.c +++ b/drivers/media/platform/ti/vpe/vpe.c @@ -422,6 +422,10 @@ struct vpe_ctx { unsigned int src_mv_buf_selector; }; +static inline struct vpe_ctx *to_vpe_ctx(struct file *filp) +{ + return container_of(filp->private_data, struct vpe_ctx, fh); +} /* * M2M devices get 2 queues. @@ -1562,7 +1566,7 @@ static int vpe_enum_fmt(struct file *file, void *priv, static int vpe_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; - struct vpe_ctx *ctx = file->private_data; + struct vpe_ctx *ctx = to_vpe_ctx(file); struct vb2_queue *vq; struct vpe_q_data *q_data; @@ -1719,7 +1723,7 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f, static int vpe_try_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct vpe_ctx *ctx = file->private_data; + struct vpe_ctx *ctx = to_vpe_ctx(file); struct vpe_fmt *fmt = find_format(f); if (V4L2_TYPE_IS_OUTPUT(f->type)) @@ -1783,7 +1787,7 @@ static int __vpe_s_fmt(struct vpe_ctx *ctx, struct v4l2_format *f) static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f) { int ret; - struct vpe_ctx *ctx = file->private_data; + struct vpe_ctx *ctx = to_vpe_ctx(file); ret = vpe_try_fmt(file, priv, f); if (ret) @@ -1871,7 +1875,7 @@ static int __vpe_try_selection(struct vpe_ctx *ctx, struct v4l2_selection *s) static int vpe_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct vpe_ctx *ctx = file->private_data; + struct vpe_ctx *ctx = to_vpe_ctx(file); struct vpe_q_data *q_data; struct v4l2_pix_format_mplane *pix; bool use_c_rect = false; @@ -1935,7 +1939,7 @@ static int vpe_g_selection(struct file *file, void *fh, static int vpe_s_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct vpe_ctx *ctx = file->private_data; + struct vpe_ctx *ctx = to_vpe_ctx(file); struct vpe_q_data *q_data; struct v4l2_selection sel = *s; int ret; @@ -2306,7 +2310,7 @@ static int vpe_open(struct file *file) init_adb_hdrs(ctx); v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = ctx; + file->private_data = &ctx->fh; hdl = &ctx->hdl; v4l2_ctrl_handler_init(hdl, 1); @@ -2400,7 +2404,7 @@ static int vpe_open(struct file *file) static int vpe_release(struct file *file) { struct vpe_dev *dev = video_drvdata(file); - struct vpe_ctx *ctx = file->private_data; + struct vpe_ctx *ctx = to_vpe_ctx(file); vpe_dbg(dev, "releasing instance %p\n", ctx); From b22ac2e4a96bcf63ecfa0b786f75d0173c8808de Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:29:46 +0300 Subject: [PATCH 00504/11391] media: usb: hdpvr: Store v4l2_fh pointer in file->private_data Most V4L2 drivers store the v4l2_fh pointer in file->private_data. The hdpvr driver instead stores the pointer to the driver-specific structure that embeds the v4l2_fh. Switch to storing the v4l2_fh pointer itself to standardize behaviour across drivers. This also prepares for future refactoring that depends on v4l2_fh being stored in private_data. No extensive driver refactoring is required, as file->private_data is only used to check if a file handle is the owner of the device by comparing pointer values. The private_data pointer is actually compared to a struct v4l2_fh pointer, which happens to be the first field of the hdpvr_fh structure. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/usb/hdpvr/hdpvr-video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index fd7d2a9d0449..4c431bd9b503 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -381,7 +381,7 @@ static int hdpvr_open(struct file *file) fh->legacy_mode = true; v4l2_fh_init(&fh->fh, video_devdata(file)); v4l2_fh_add(&fh->fh); - file->private_data = fh; + file->private_data = &fh->fh; return 0; } From 4a538a1c5f728641b8e3c89f73f92c2bbf7a553e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:29:47 +0300 Subject: [PATCH 00505/11391] media: usb: pvrusb2: Store v4l2_fh pointer in file->private_data Most V4L2 drivers store the v4l2_fh pointer in file->private_data. The pvrusb2 driver instead stores the pointer to the driver-specific structure that embeds the v4l2_fh. Switch to storing the v4l2_fh pointer itself to standardize behaviour across drivers. This also prepares for future refactoring that depends on v4l2_fh being stored in private_data. While at it, drop unneeded structure forward declarations. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/usb/pvrusb2/pvrusb2-v4l2.c | 65 +++++++++++++----------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index ad38e1240541..7dc7c90ebf62 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -21,8 +21,6 @@ #include #include -struct pvr2_v4l2_dev; -struct pvr2_v4l2_fh; struct pvr2_v4l2; struct pvr2_v4l2_dev { @@ -48,6 +46,11 @@ struct pvr2_v4l2_fh { unsigned int input_cnt; }; +static inline struct pvr2_v4l2_fh *to_pvr2_v4l2_fh(struct file *filp) +{ + return container_of(filp->private_data, struct pvr2_v4l2_fh, fh); +} + struct pvr2_v4l2 { struct pvr2_channel channel; @@ -108,7 +111,7 @@ static struct v4l2_format pvr_format [] = { */ static int pvr2_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; strscpy(cap->driver, "pvrusb2", sizeof(cap->driver)); @@ -123,7 +126,7 @@ static int pvr2_querycap(struct file *file, void *priv, struct v4l2_capability * static int pvr2_g_std(struct file *file, void *priv, v4l2_std_id *std) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int val = 0; int ret; @@ -136,7 +139,7 @@ static int pvr2_g_std(struct file *file, void *priv, v4l2_std_id *std) static int pvr2_s_std(struct file *file, void *priv, v4l2_std_id std) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int ret; @@ -148,7 +151,7 @@ static int pvr2_s_std(struct file *file, void *priv, v4l2_std_id std) static int pvr2_querystd(struct file *file, void *priv, v4l2_std_id *std) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int val = 0; int ret; @@ -161,7 +164,7 @@ static int pvr2_querystd(struct file *file, void *priv, v4l2_std_id *std) static int pvr2_enum_input(struct file *file, void *priv, struct v4l2_input *vi) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct pvr2_ctrl *cptr; struct v4l2_input tmp; @@ -209,7 +212,7 @@ static int pvr2_enum_input(struct file *file, void *priv, struct v4l2_input *vi) static int pvr2_g_input(struct file *file, void *priv, unsigned int *i) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; unsigned int idx; struct pvr2_ctrl *cptr; @@ -231,7 +234,7 @@ static int pvr2_g_input(struct file *file, void *priv, unsigned int *i) static int pvr2_s_input(struct file *file, void *priv, unsigned int inp) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int ret; @@ -286,7 +289,7 @@ static int pvr2_s_audio(struct file *file, void *priv, const struct v4l2_audio * static int pvr2_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; if (vt->index != 0) @@ -298,7 +301,7 @@ static int pvr2_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) static int pvr2_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *vt) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int ret; @@ -314,7 +317,7 @@ static int pvr2_s_tuner(struct file *file, void *priv, const struct v4l2_tuner * static int pvr2_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *vf) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; unsigned long fv; struct v4l2_tuner vt; @@ -349,7 +352,7 @@ static int pvr2_s_frequency(struct file *file, void *priv, const struct v4l2_fre static int pvr2_g_frequency(struct file *file, void *priv, struct v4l2_frequency *vf) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int val = 0; int cur_input; @@ -391,7 +394,7 @@ static int pvr2_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtd static int pvr2_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int val; @@ -411,7 +414,7 @@ static int pvr2_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format static int pvr2_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int lmin, lmax, ldef; struct pvr2_ctrl *hcp, *vcp; @@ -449,7 +452,7 @@ static int pvr2_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_forma static int pvr2_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct pvr2_ctrl *hcp, *vcp; int ret = pvr2_try_fmt_vid_cap(file, fh, vf); @@ -466,7 +469,7 @@ static int pvr2_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format static int pvr2_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct pvr2_v4l2_dev *pdi = fh->pdi; int ret; @@ -485,7 +488,7 @@ static int pvr2_streamon(struct file *file, void *priv, enum v4l2_buf_type i) static int pvr2_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; if (!fh->pdi->stream) { @@ -500,7 +503,7 @@ static int pvr2_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) static int pvr2_query_ext_ctrl(struct file *file, void *priv, struct v4l2_query_ext_ctrl *vc) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct pvr2_ctrl *cptr; int val; @@ -561,7 +564,7 @@ static int pvr2_query_ext_ctrl(struct file *file, void *priv, static int pvr2_querymenu(struct file *file, void *priv, struct v4l2_querymenu *vm) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; unsigned int cnt = 0; int ret; @@ -577,7 +580,7 @@ static int pvr2_querymenu(struct file *file, void *priv, struct v4l2_querymenu * static int pvr2_g_ext_ctrls(struct file *file, void *priv, struct v4l2_ext_controls *ctls) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct v4l2_ext_control *ctrl; struct pvr2_ctrl *cptr; @@ -612,7 +615,7 @@ static int pvr2_g_ext_ctrls(struct file *file, void *priv, static int pvr2_s_ext_ctrls(struct file *file, void *priv, struct v4l2_ext_controls *ctls) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct v4l2_ext_control *ctrl; unsigned int idx; @@ -637,7 +640,7 @@ static int pvr2_s_ext_ctrls(struct file *file, void *priv, static int pvr2_try_ext_ctrls(struct file *file, void *priv, struct v4l2_ext_controls *ctls) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct v4l2_ext_control *ctrl; struct pvr2_ctrl *pctl; @@ -659,7 +662,7 @@ static int pvr2_try_ext_ctrls(struct file *file, void *priv, static int pvr2_g_pixelaspect(struct file *file, void *priv, int type, struct v4l2_fract *f) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct v4l2_cropcap cap = { .type = type }; int ret; @@ -675,7 +678,7 @@ static int pvr2_g_pixelaspect(struct file *file, void *priv, static int pvr2_g_selection(struct file *file, void *priv, struct v4l2_selection *sel) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct v4l2_cropcap cap; int val = 0; @@ -726,7 +729,7 @@ static int pvr2_g_selection(struct file *file, void *priv, static int pvr2_s_selection(struct file *file, void *priv, struct v4l2_selection *sel) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int ret; @@ -758,7 +761,7 @@ static int pvr2_s_selection(struct file *file, void *priv, static int pvr2_log_status(struct file *file, void *priv) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; pvr2_hdw_trigger_module_log(hdw); @@ -882,7 +885,7 @@ static void pvr2_v4l2_internal_check(struct pvr2_channel *chp) static int pvr2_v4l2_release(struct file *file) { - struct pvr2_v4l2_fh *fhp = file->private_data; + struct pvr2_v4l2_fh *fhp = to_pvr2_v4l2_fh(file); struct pvr2_v4l2 *vp = fhp->pdi->v4lp; struct pvr2_hdw *hdw = fhp->channel.mc_head->hdw; @@ -1000,7 +1003,7 @@ static int pvr2_v4l2_open(struct file *file) } fhp->file = file; - file->private_data = fhp; + file->private_data = &fhp->fh; fhp->fw_mode_flag = pvr2_hdw_cpufw_get_enabled(hdw); v4l2_fh_add(&fhp->fh); @@ -1055,7 +1058,7 @@ static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh) static ssize_t pvr2_v4l2_read(struct file *file, char __user *buff, size_t count, loff_t *ppos) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); int ret; if (fh->fw_mode_flag) { @@ -1117,7 +1120,7 @@ static ssize_t pvr2_v4l2_read(struct file *file, static __poll_t pvr2_v4l2_poll(struct file *file, poll_table *wait) { __poll_t mask = 0; - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); int ret; if (fh->fw_mode_flag) { From 7b6cf051dff7b35299ce52b0b00d6e21e656fb4f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:29:48 +0300 Subject: [PATCH 00506/11391] media: usb: uvcvideo: Store v4l2_fh pointer in file->private_data Most V4L2 drivers store the v4l2_fh pointer in file->private_data. The uvcvideo driver instead stores the pointer to the driver-specific structure that embeds the v4l2_fh. Switch to storing the v4l2_fh pointer itself to standardize behaviour across drivers. This also prepares for future refactoring that depends on v4l2_fh being stored in private_data. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/usb/uvc/uvc_v4l2.c | 10 +++++----- drivers/media/usb/uvc/uvcvideo.h | 5 +++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 160f9cf6e6db..6dd329a972fd 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -603,14 +603,14 @@ static int uvc_v4l2_open(struct file *file) v4l2_fh_add(&handle->vfh); handle->chain = stream->chain; handle->stream = stream; - file->private_data = handle; + file->private_data = &handle->vfh; return 0; } static int uvc_v4l2_release(struct file *file) { - struct uvc_fh *handle = file->private_data; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; uvc_dbg(stream->dev, CALLS, "%s\n", __func__); @@ -626,7 +626,7 @@ static int uvc_v4l2_release(struct file *file) static int uvc_ioctl_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { - struct uvc_fh *handle = file->private_data; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; struct uvc_streaming *stream = handle->stream; @@ -1170,7 +1170,7 @@ static int uvc_v4l2_put_xu_query(const struct uvc_xu_control_query *kp, static long uvc_v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) { - struct uvc_fh *handle = file->private_data; + struct uvc_fh *handle = to_uvc_fh(file); union { struct uvc_xu_control_mapping xmap; struct uvc_xu_control_query xqry; @@ -1221,7 +1221,7 @@ static long uvc_v4l2_compat_ioctl32(struct file *file, static long uvc_v4l2_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct uvc_fh *handle = file->private_data; + struct uvc_fh *handle = to_uvc_fh(file); unsigned int converted_cmd = v4l2_translate_cmd(cmd); int ret; diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 757254fc4fe9..8b5625203048 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -637,6 +637,11 @@ struct uvc_fh { unsigned int pending_async_ctrls; }; +static inline struct uvc_fh *to_uvc_fh(struct file *filp) +{ + return container_of(filp->private_data, struct uvc_fh, vfh); +} + /* ------------------------------------------------------------------------ * Debugging, printing and logging */ From 0fd7155307bebb7daf946abae0ee8e50d20819ed Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:29:49 +0300 Subject: [PATCH 00507/11391] media: staging: most: Store v4l2_fh pointer in file->private_data Most V4L2 drivers store the v4l2_fh pointer in file->private_data. The most driver instead stores the pointer to the driver-specific structure that embeds the v4l2_fh. Switch to storing the v4l2_fh pointer itself to standardize behaviour across drivers. This also prepares for future refactoring that depends on v4l2_fh being stored in private_data. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/staging/most/video/video.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/staging/most/video/video.c b/drivers/staging/most/video/video.c index 2b3cdb1ce140..bce7ffeac8fe 100644 --- a/drivers/staging/most/video/video.c +++ b/drivers/staging/most/video/video.c @@ -52,6 +52,11 @@ struct comp_fh { u32 offs; }; +static inline struct comp_fh *to_comp_fh(struct file *filp) +{ + return container_of(filp->private_data, struct comp_fh, fh); +} + static LIST_HEAD(video_devices); static DEFINE_SPINLOCK(list_lock); @@ -91,7 +96,7 @@ static int comp_vdev_open(struct file *filp) fh->mdev = mdev; v4l2_fh_init(&fh->fh, vdev); - filp->private_data = fh; + filp->private_data = &fh->fh; v4l2_fh_add(&fh->fh); @@ -115,7 +120,7 @@ static int comp_vdev_open(struct file *filp) static int comp_vdev_close(struct file *filp) { - struct comp_fh *fh = filp->private_data; + struct comp_fh *fh = to_comp_fh(filp); struct most_video_dev *mdev = fh->mdev; struct mbo *mbo, *tmp; @@ -151,7 +156,7 @@ static int comp_vdev_close(struct file *filp) static ssize_t comp_vdev_read(struct file *filp, char __user *buf, size_t count, loff_t *pos) { - struct comp_fh *fh = filp->private_data; + struct comp_fh *fh = to_comp_fh(filp); struct most_video_dev *mdev = fh->mdev; int ret = 0; @@ -200,7 +205,7 @@ static ssize_t comp_vdev_read(struct file *filp, char __user *buf, static __poll_t comp_vdev_poll(struct file *filp, poll_table *wait) { - struct comp_fh *fh = filp->private_data; + struct comp_fh *fh = to_comp_fh(filp); struct most_video_dev *mdev = fh->mdev; __poll_t mask = 0; From 618882c92681de18e9bd99d2a88bb21c897283f3 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:29:50 +0300 Subject: [PATCH 00508/11391] media: Wrap file->private_data access with a helper function Accessing file->private_data manually to retrieve the v4l2_fh pointer is error-prone, as the field is a void * and will happily convert implicitly to any pointer type. To avoid direct access to file->private_data, introduce a new inline function that retrieves the v4l2_fh pointer, and use it to replace common access patterns through the kernel. Changes to drivers have been generated with the following coccinelle semantic patch: @@ struct file *filp; identifier fh; @@ - struct v4l2_fh *fh = filp->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(filp); Manual changes have been applied to Documentation/ to update the usage patterns, and to include/media/v4l2-fh.h to add the new function. While at it, fix a typo in the title of v4l2-fh.rst: the file describes the "file handles" API, not "file handlers". No functional change is intended, this only paves the way to remove direct accesses to file->private_data and make V4L2 drivers safer. Other accesses to the field will be addressed separately. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- Documentation/driver-api/media/v4l2-fh.rst | 16 +++++---- .../zh_CN/video4linux/v4l2-framework.txt | 2 +- .../media/common/videobuf2/videobuf2-v4l2.c | 2 +- drivers/media/pci/cx18/cx18-fileops.c | 2 +- drivers/media/pci/ivtv/ivtv-fileops.c | 2 +- .../media/platform/allegro-dvt/allegro-core.c | 2 +- .../platform/mediatek/jpeg/mtk_jpeg_core.c | 2 +- .../media/platform/nvidia/tegra-vde/v4l2.c | 2 +- .../media/platform/nxp/imx-jpeg/mxc-jpeg.c | 4 +-- .../media/platform/renesas/vsp1/vsp1_histo.c | 6 ++-- .../media/platform/renesas/vsp1/vsp1_video.c | 12 +++---- drivers/media/platform/ti/omap3isp/ispvideo.c | 2 +- drivers/media/platform/xilinx/xilinx-dma.c | 10 +++--- drivers/media/usb/uvc/uvc_metadata.c | 10 +++--- drivers/media/v4l2-core/v4l2-ctrls-api.c | 4 +-- drivers/media/v4l2-core/v4l2-fh.c | 2 +- drivers/media/v4l2-core/v4l2-mem2mem.c | 34 +++++++++---------- drivers/media/v4l2-core/v4l2-subdev.c | 8 ++--- include/media/v4l2-fh.h | 14 ++++++++ 19 files changed, 77 insertions(+), 59 deletions(-) diff --git a/Documentation/driver-api/media/v4l2-fh.rst b/Documentation/driver-api/media/v4l2-fh.rst index 3eeaa8da0c9e..2c87b74578d9 100644 --- a/Documentation/driver-api/media/v4l2-fh.rst +++ b/Documentation/driver-api/media/v4l2-fh.rst @@ -1,7 +1,7 @@ .. SPDX-License-Identifier: GPL-2.0 -V4L2 File handlers ------------------- +V4L2 File handles +----------------- struct v4l2_fh provides a way to easily keep file handle specific data that is used by the V4L2 framework. @@ -18,7 +18,9 @@ This bit is set whenever :c:func:`v4l2_fh_init` is called. struct v4l2_fh is allocated as a part of the driver's own file handle structure and ``file->private_data`` is set to it in the driver's ``open()`` -function by the driver. +function by the driver. The :c:type:`v4l2_fh` file handle can be retrieved +from the :c:type:`file` using :c:func:`file_to_v4l2_fh`. Drivers must not +access ``file->private_data`` directly. In many cases the struct v4l2_fh will be embedded in a larger structure. In that case you should call: @@ -63,7 +65,7 @@ Example: int my_release(struct file *file) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); struct my_fh *my_fh = container_of(fh, struct my_fh, fh); ... @@ -78,11 +80,9 @@ Below is a short description of the :c:type:`v4l2_fh` functions used: :c:func:`v4l2_fh_init ` (:c:type:`fh `, :c:type:`vdev `) - - Initialise the file handle. This **MUST** be performed in the driver's :c:type:`v4l2_file_operations`->open() handler. - :c:func:`v4l2_fh_add ` (:c:type:`fh `) @@ -101,6 +101,10 @@ Below is a short description of the :c:type:`v4l2_fh` functions used: - Uninitialise the file handle. After uninitialisation the :c:type:`v4l2_fh` memory can be freed. +:c:func:`file_to_v4l2_fh ` +(struct file \*filp) + +- Retrieve the :c:type:`v4l2_fh` instance associated with a :c:type:`file`. If struct v4l2_fh is not embedded, then you can use these helper functions: diff --git a/Documentation/translations/zh_CN/video4linux/v4l2-framework.txt b/Documentation/translations/zh_CN/video4linux/v4l2-framework.txt index 9cc97ec75d7a..a9eb62fa1531 100644 --- a/Documentation/translations/zh_CN/video4linux/v4l2-framework.txt +++ b/Documentation/translations/zh_CN/video4linux/v4l2-framework.txt @@ -819,7 +819,7 @@ int my_open(struct file *file) int my_release(struct file *file) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); struct my_fh *my_fh = container_of(fh, struct my_fh, fh); ... diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index 1cd26faee503..f29307e59be5 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -979,7 +979,7 @@ __poll_t vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait) res = vb2_core_poll(q, file, wait); if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); poll_wait(file, &fh->wait, wait); if (v4l2_event_pending(fh)) diff --git a/drivers/media/pci/cx18/cx18-fileops.c b/drivers/media/pci/cx18/cx18-fileops.c index cefa91b37f89..af25628b11ba 100644 --- a/drivers/media/pci/cx18/cx18-fileops.c +++ b/drivers/media/pci/cx18/cx18-fileops.c @@ -678,7 +678,7 @@ void cx18_stop_capture(struct cx18_stream *s, int gop_end) int cx18_v4l2_close(struct file *filp) { - struct v4l2_fh *fh = filp->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(filp); struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; struct cx18_stream *s = &cx->streams[id->type]; diff --git a/drivers/media/pci/ivtv/ivtv-fileops.c b/drivers/media/pci/ivtv/ivtv-fileops.c index cfa28d035586..230d498108b5 100644 --- a/drivers/media/pci/ivtv/ivtv-fileops.c +++ b/drivers/media/pci/ivtv/ivtv-fileops.c @@ -877,7 +877,7 @@ static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts) int ivtv_v4l2_close(struct file *filp) { - struct v4l2_fh *fh = filp->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(filp); struct ivtv_open_id *id = fh2id(fh); struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/allegro-core.c index eb03df0d8652..1f134e08923a 100644 --- a/drivers/media/platform/allegro-dvt/allegro-core.c +++ b/drivers/media/platform/allegro-dvt/allegro-core.c @@ -3483,7 +3483,7 @@ static int allegro_enum_framesizes(struct file *file, void *fh, static int allegro_ioctl_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); struct allegro_channel *channel = fh_to_channel(fh); int err; diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c index 7eb12449b63a..329e5787c2c2 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c @@ -588,7 +588,7 @@ static int mtk_jpeg_enc_s_selection(struct file *file, void *priv, static int mtk_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); struct vb2_queue *vq; struct vb2_buffer *vb; diff --git a/drivers/media/platform/nvidia/tegra-vde/v4l2.c b/drivers/media/platform/nvidia/tegra-vde/v4l2.c index e3726cab0c82..531a85e3fe49 100644 --- a/drivers/media/platform/nvidia/tegra-vde/v4l2.c +++ b/drivers/media/platform/nvidia/tegra-vde/v4l2.c @@ -853,7 +853,7 @@ static int tegra_open(struct file *file) static int tegra_release(struct file *file) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); struct tegra_ctx *ctx = fh_to_tegra_ctx(fh); struct tegra_vde *vde = ctx->vde; diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c index 8681dd193033..1b2148578cb6 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c @@ -1604,7 +1604,7 @@ static void mxc_jpeg_device_run(void *priv) static int mxc_jpeg_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh); unsigned long flags; int ret; @@ -1637,7 +1637,7 @@ static int mxc_jpeg_decoder_cmd(struct file *file, void *priv, static int mxc_jpeg_encoder_cmd(struct file *file, void *priv, struct v4l2_encoder_cmd *cmd) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh); unsigned long flags; int ret; diff --git a/drivers/media/platform/renesas/vsp1/vsp1_histo.c b/drivers/media/platform/renesas/vsp1/vsp1_histo.c index c762202877ba..390ea50f1595 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_histo.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_histo.c @@ -392,7 +392,7 @@ static const struct v4l2_subdev_ops histo_ops = { static int histo_v4l2_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct vsp1_histogram *histo = vdev_to_histo(vfh->vdev); cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING @@ -409,7 +409,7 @@ static int histo_v4l2_querycap(struct file *file, void *fh, static int histo_v4l2_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct vsp1_histogram *histo = vdev_to_histo(vfh->vdev); if (f->index > 0 || f->type != histo->queue.type) @@ -423,7 +423,7 @@ static int histo_v4l2_enum_format(struct file *file, void *fh, static int histo_v4l2_get_format(struct file *file, void *fh, struct v4l2_format *format) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct vsp1_histogram *histo = vdev_to_histo(vfh->vdev); struct v4l2_meta_format *meta = &format->fmt.meta; diff --git a/drivers/media/platform/renesas/vsp1/vsp1_video.c b/drivers/media/platform/renesas/vsp1/vsp1_video.c index bc66fbdde3cc..656fb5e6cb30 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_video.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_video.c @@ -896,7 +896,7 @@ static const struct vb2_ops vsp1_video_queue_qops = { static int vsp1_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct vsp1_video *video = to_vsp1_video(vfh->vdev); cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING @@ -912,7 +912,7 @@ vsp1_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap) static int vsp1_video_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct vsp1_video *video = to_vsp1_video(vfh->vdev); const struct vsp1_format_info *info; @@ -933,7 +933,7 @@ static int vsp1_video_enum_format(struct file *file, void *fh, static int vsp1_video_get_format(struct file *file, void *fh, struct v4l2_format *format) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct vsp1_video *video = to_vsp1_video(vfh->vdev); if (format->type != video->queue.type) @@ -949,7 +949,7 @@ vsp1_video_get_format(struct file *file, void *fh, struct v4l2_format *format) static int vsp1_video_try_format(struct file *file, void *fh, struct v4l2_format *format) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct vsp1_video *video = to_vsp1_video(vfh->vdev); if (format->type != video->queue.type) @@ -961,7 +961,7 @@ vsp1_video_try_format(struct file *file, void *fh, struct v4l2_format *format) static int vsp1_video_set_format(struct file *file, void *fh, struct v4l2_format *format) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct vsp1_video *video = to_vsp1_video(vfh->vdev); const struct vsp1_format_info *info; int ret; @@ -991,7 +991,7 @@ vsp1_video_set_format(struct file *file, void *fh, struct v4l2_format *format) static int vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct vsp1_video *video = to_vsp1_video(vfh->vdev); struct media_device *mdev = &video->vsp1->media_dev; struct vsp1_pipeline *pipe; diff --git a/drivers/media/platform/ti/omap3isp/ispvideo.c b/drivers/media/platform/ti/omap3isp/ispvideo.c index 78e30298c7ad..a777135c6a6c 100644 --- a/drivers/media/platform/ti/omap3isp/ispvideo.c +++ b/drivers/media/platform/ti/omap3isp/ispvideo.c @@ -1348,7 +1348,7 @@ static int isp_video_open(struct file *file) static int isp_video_release(struct file *file) { struct isp_video *video = video_drvdata(file); - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct isp_video_fh *handle = to_isp_video_fh(vfh); /* Disable streaming and free the buffers queue resources. */ diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c index 18bfa6001909..fcfe0883aba5 100644 --- a/drivers/media/platform/xilinx/xilinx-dma.c +++ b/drivers/media/platform/xilinx/xilinx-dma.c @@ -469,7 +469,7 @@ static const struct vb2_ops xvip_dma_queue_qops = { static int xvip_dma_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct xvip_dma *dma = to_xvip_dma(vfh->vdev); cap->capabilities = dma->xdev->v4l2_caps | V4L2_CAP_STREAMING | @@ -491,7 +491,7 @@ xvip_dma_querycap(struct file *file, void *fh, struct v4l2_capability *cap) static int xvip_dma_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct xvip_dma *dma = to_xvip_dma(vfh->vdev); if (f->index > 0) @@ -505,7 +505,7 @@ xvip_dma_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f) static int xvip_dma_get_format(struct file *file, void *fh, struct v4l2_format *format) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct xvip_dma *dma = to_xvip_dma(vfh->vdev); format->fmt.pix = dma->format; @@ -565,7 +565,7 @@ __xvip_dma_try_format(struct xvip_dma *dma, struct v4l2_pix_format *pix, static int xvip_dma_try_format(struct file *file, void *fh, struct v4l2_format *format) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct xvip_dma *dma = to_xvip_dma(vfh->vdev); __xvip_dma_try_format(dma, &format->fmt.pix, NULL); @@ -575,7 +575,7 @@ xvip_dma_try_format(struct file *file, void *fh, struct v4l2_format *format) static int xvip_dma_set_format(struct file *file, void *fh, struct v4l2_format *format) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct xvip_dma *dma = to_xvip_dma(vfh->vdev); const struct xvip_video_format *info; diff --git a/drivers/media/usb/uvc/uvc_metadata.c b/drivers/media/usb/uvc/uvc_metadata.c index 229e08ff323e..4cbf6ce314fd 100644 --- a/drivers/media/usb/uvc/uvc_metadata.c +++ b/drivers/media/usb/uvc/uvc_metadata.c @@ -26,7 +26,7 @@ static int uvc_meta_v4l2_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); struct uvc_video_chain *chain = stream->chain; @@ -42,7 +42,7 @@ static int uvc_meta_v4l2_querycap(struct file *file, void *fh, static int uvc_meta_v4l2_get_format(struct file *file, void *fh, struct v4l2_format *format) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); struct v4l2_meta_format *fmt = &format->fmt.meta; @@ -60,7 +60,7 @@ static int uvc_meta_v4l2_get_format(struct file *file, void *fh, static int uvc_meta_v4l2_try_format(struct file *file, void *fh, struct v4l2_format *format) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); struct uvc_device *dev = stream->dev; struct v4l2_meta_format *fmt = &format->fmt.meta; @@ -86,7 +86,7 @@ static int uvc_meta_v4l2_try_format(struct file *file, void *fh, static int uvc_meta_v4l2_set_format(struct file *file, void *fh, struct v4l2_format *format) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); struct v4l2_meta_format *fmt = &format->fmt.meta; int ret; @@ -115,7 +115,7 @@ static int uvc_meta_v4l2_set_format(struct file *file, void *fh, static int uvc_meta_v4l2_enum_formats(struct file *file, void *fh, struct v4l2_fmtdesc *fdesc) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); struct uvc_device *dev = stream->dev; u32 i = fdesc->index; diff --git a/drivers/media/v4l2-core/v4l2-ctrls-api.c b/drivers/media/v4l2-core/v4l2-ctrls-api.c index d49a68b36c28..d46b2c8f3d23 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-api.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-api.c @@ -1253,7 +1253,7 @@ EXPORT_SYMBOL(v4l2_querymenu); int v4l2_ctrl_log_status(struct file *file, void *fh) { struct video_device *vfd = video_devdata(file); - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) && vfd->v4l2_dev) v4l2_ctrl_handler_log_status(vfh->ctrl_handler, @@ -1348,7 +1348,7 @@ EXPORT_SYMBOL(v4l2_ctrl_subdev_subscribe_event); */ __poll_t v4l2_ctrl_poll(struct file *file, struct poll_table_struct *wait) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); poll_wait(file, &fh->wait, wait); if (v4l2_event_pending(fh)) diff --git a/drivers/media/v4l2-core/v4l2-fh.c b/drivers/media/v4l2-core/v4l2-fh.c index 90eec79ee995..7a5f7aa5e253 100644 --- a/drivers/media/v4l2-core/v4l2-fh.c +++ b/drivers/media/v4l2-core/v4l2-fh.c @@ -90,7 +90,7 @@ EXPORT_SYMBOL_GPL(v4l2_fh_exit); int v4l2_fh_release(struct file *filp) { - struct v4l2_fh *fh = filp->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(filp); if (fh) { v4l2_fh_del(fh); diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index eb22d6172462..e67e67f76f72 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -971,7 +971,7 @@ __poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, rc = v4l2_m2m_poll_for_data(file, m2m_ctx, wait); if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); poll_wait(file, &fh->wait, wait); if (v4l2_event_pending(fh)) @@ -1004,7 +1004,7 @@ unsigned long v4l2_m2m_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); unsigned long offset = pgoff << PAGE_SHIFT; struct vb2_queue *vq; @@ -1371,7 +1371,7 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_request_queue); int v4l2_m2m_ioctl_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *rb) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); return v4l2_m2m_reqbufs(file, fh->m2m_ctx, rb); } @@ -1380,7 +1380,7 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_reqbufs); int v4l2_m2m_ioctl_create_bufs(struct file *file, void *priv, struct v4l2_create_buffers *create) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); return v4l2_m2m_create_bufs(file, fh->m2m_ctx, create); } @@ -1389,7 +1389,7 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_create_bufs); int v4l2_m2m_ioctl_remove_bufs(struct file *file, void *priv, struct v4l2_remove_buffers *remove) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); struct vb2_queue *q = v4l2_m2m_get_vq(fh->m2m_ctx, remove->type); if (!q) @@ -1404,7 +1404,7 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_remove_bufs); int v4l2_m2m_ioctl_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); return v4l2_m2m_querybuf(file, fh->m2m_ctx, buf); } @@ -1413,7 +1413,7 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_querybuf); int v4l2_m2m_ioctl_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); return v4l2_m2m_qbuf(file, fh->m2m_ctx, buf); } @@ -1422,7 +1422,7 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_qbuf); int v4l2_m2m_ioctl_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); return v4l2_m2m_dqbuf(file, fh->m2m_ctx, buf); } @@ -1431,7 +1431,7 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_dqbuf); int v4l2_m2m_ioctl_prepare_buf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); return v4l2_m2m_prepare_buf(file, fh->m2m_ctx, buf); } @@ -1440,7 +1440,7 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_prepare_buf); int v4l2_m2m_ioctl_expbuf(struct file *file, void *priv, struct v4l2_exportbuffer *eb) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); return v4l2_m2m_expbuf(file, fh->m2m_ctx, eb); } @@ -1449,7 +1449,7 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_expbuf); int v4l2_m2m_ioctl_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); return v4l2_m2m_streamon(file, fh->m2m_ctx, type); } @@ -1458,7 +1458,7 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_streamon); int v4l2_m2m_ioctl_streamoff(struct file *file, void *priv, enum v4l2_buf_type type) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); return v4l2_m2m_streamoff(file, fh->m2m_ctx, type); } @@ -1542,7 +1542,7 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_decoder_cmd); int v4l2_m2m_ioctl_encoder_cmd(struct file *file, void *priv, struct v4l2_encoder_cmd *ec) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); return v4l2_m2m_encoder_cmd(file, fh->m2m_ctx, ec); } @@ -1551,7 +1551,7 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_encoder_cmd); int v4l2_m2m_ioctl_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *dc) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); return v4l2_m2m_decoder_cmd(file, fh->m2m_ctx, dc); } @@ -1572,7 +1572,7 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_stateless_try_decoder_cmd); int v4l2_m2m_ioctl_stateless_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *dc) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); struct vb2_v4l2_buffer *out_vb, *cap_vb; struct v4l2_m2m_dev *m2m_dev = fh->m2m_ctx->m2m_dev; unsigned long flags; @@ -1617,7 +1617,7 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_stateless_decoder_cmd); int v4l2_m2m_fop_mmap(struct file *file, struct vm_area_struct *vma) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); return v4l2_m2m_mmap(file, fh->m2m_ctx, vma); } @@ -1625,7 +1625,7 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_fop_mmap); __poll_t v4l2_m2m_fop_poll(struct file *file, poll_table *wait) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); struct v4l2_m2m_ctx *m2m_ctx = fh->m2m_ctx; __poll_t ret; diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 4fd25fea3b58..29d3b788b288 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -122,7 +122,7 @@ static int subdev_close(struct file *file) { struct video_device *vdev = video_devdata(file); struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh); if (sd->internal_ops && sd->internal_ops->close) @@ -612,7 +612,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg, { struct video_device *vdev = video_devdata(file); struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh); bool ro_subdev = test_bit(V4L2_FL_SUBDEV_RO_DEVNODE, &vdev->flags); bool streams_subdev = sd->flags & V4L2_SUBDEV_FL_STREAMS; @@ -1135,7 +1135,7 @@ static long subdev_do_ioctl_lock(struct file *file, unsigned int cmd, void *arg) if (video_is_registered(vdev)) { struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh); struct v4l2_subdev_state *state; @@ -1192,7 +1192,7 @@ static __poll_t subdev_poll(struct file *file, poll_table *wait) { struct video_device *vdev = video_devdata(file); struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) return EPOLLERR; diff --git a/include/media/v4l2-fh.h b/include/media/v4l2-fh.h index b5b3e00c8e6a..823fa8ebeb8f 100644 --- a/include/media/v4l2-fh.h +++ b/include/media/v4l2-fh.h @@ -56,6 +56,20 @@ struct v4l2_fh { struct v4l2_m2m_ctx *m2m_ctx; }; +/** + * file_to_v4l2_fh - Return the v4l2_fh associated with a struct file + * + * @filp: pointer to &struct file + * + * This function should be used by drivers to retrieve the &struct v4l2_fh + * instance pointer stored in the file private_data instead of accessing the + * private_data field directly. + */ +static inline struct v4l2_fh *file_to_v4l2_fh(struct file *filp) +{ + return filp->private_data; +} + /** * v4l2_fh_init - Initialise the file handle. * From 8003313d388f11cfcaaa88a731f113afda171887 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:29:51 +0300 Subject: [PATCH 00509/11391] media: Replace file->private_data access with file_to_v4l2_fh() Accessing file->private_data manually to retrieve the v4l2_fh pointer is error-prone, as the field is a void * and will happily cast implicitly to any pointer type. Replace all remaining locations that read the v4l2_fh pointer directly from file->private_data with usage of the file_to_v4l2_fh() function. The change was generated manually. No functional change is intended, this only paves the way to remove direct accesses to file->private_data and make V4L2 drivers safer. Other accesses to the field will be addressed separately. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/pci/cx18/cx18-driver.h | 2 +- drivers/media/pci/cx18/cx18-fileops.c | 2 +- drivers/media/pci/saa7164/saa7164.h | 4 ++-- drivers/media/platform/amphion/vpu.h | 2 +- drivers/media/platform/imagination/e5010-jpeg-enc.h | 2 +- drivers/media/platform/nxp/dw100/dw100.c | 2 +- drivers/media/platform/nxp/imx-pxp.c | 2 +- drivers/media/platform/qcom/iris/iris_vidc.c | 2 +- drivers/media/platform/qcom/venus/core.h | 2 +- .../media/platform/samsung/s3c-camif/camif-capture.c | 6 +++--- drivers/media/platform/sunxi/sun8i-di/sun8i-di.c | 2 +- .../media/platform/sunxi/sun8i-rotate/sun8i_rotate.c | 2 +- drivers/media/platform/ti/vpe/vpe.c | 2 +- drivers/media/test-drivers/vicodec/vicodec-core.c | 2 +- drivers/media/test-drivers/vim2m.c | 2 +- drivers/media/test-drivers/visl/visl.h | 2 +- drivers/media/test-drivers/vivid/vivid-core.c | 4 ++-- drivers/media/test-drivers/vivid/vivid-radio-rx.c | 4 ++-- drivers/media/test-drivers/vivid/vivid-radio-tx.c | 4 ++-- drivers/media/usb/hdpvr/hdpvr-video.c | 12 ++++++------ drivers/media/usb/pvrusb2/pvrusb2-v4l2.c | 2 +- drivers/media/usb/uvc/uvcvideo.h | 2 +- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 2 +- drivers/media/v4l2-core/v4l2-ioctl.c | 4 ++-- drivers/staging/most/video/video.c | 2 +- drivers/usb/gadget/function/uvc.h | 5 +++++ drivers/usb/gadget/function/uvc_v4l2.c | 2 +- 27 files changed, 43 insertions(+), 38 deletions(-) diff --git a/drivers/media/pci/cx18/cx18-driver.h b/drivers/media/pci/cx18/cx18-driver.h index 485ca9747c4c..92acd23a8c4d 100644 --- a/drivers/media/pci/cx18/cx18-driver.h +++ b/drivers/media/pci/cx18/cx18-driver.h @@ -414,7 +414,7 @@ static inline struct cx18_open_id *fh2id(struct v4l2_fh *fh) static inline struct cx18_open_id *file2id(struct file *file) { - return fh2id(file->private_data); + return fh2id(file_to_v4l2_fh(file)); } /* forward declaration of struct defined in cx18-cards.h */ diff --git a/drivers/media/pci/cx18/cx18-fileops.c b/drivers/media/pci/cx18/cx18-fileops.c index af25628b11ba..89e38b303630 100644 --- a/drivers/media/pci/cx18/cx18-fileops.c +++ b/drivers/media/pci/cx18/cx18-fileops.c @@ -709,7 +709,7 @@ int cx18_v4l2_close(struct file *filp) } if (id->type == CX18_ENC_STREAM_TYPE_YUV && - filp->private_data == vdev->queue->owner) { + file_to_v4l2_fh(filp) == vdev->queue->owner) { vb2_queue_release(vdev->queue); vdev->queue->owner = NULL; } diff --git a/drivers/media/pci/saa7164/saa7164.h b/drivers/media/pci/saa7164/saa7164.h index 7b511f7f1cfc..94e987e7b5e5 100644 --- a/drivers/media/pci/saa7164/saa7164.h +++ b/drivers/media/pci/saa7164/saa7164.h @@ -182,7 +182,7 @@ struct saa7164_encoder_fh { static inline struct saa7164_encoder_fh *to_saa7164_encoder_fh(struct file *filp) { - return container_of(filp->private_data, struct saa7164_encoder_fh, fh); + return container_of(file_to_v4l2_fh(filp), struct saa7164_encoder_fh, fh); } struct saa7164_vbi_fh { @@ -193,7 +193,7 @@ struct saa7164_vbi_fh { static inline struct saa7164_vbi_fh *to_saa7164_vbi_fh(struct file *filp) { - return container_of(filp->private_data, struct saa7164_vbi_fh, fh); + return container_of(file_to_v4l2_fh(filp), struct saa7164_vbi_fh, fh); } struct saa7164_histogram_bucket { diff --git a/drivers/media/platform/amphion/vpu.h b/drivers/media/platform/amphion/vpu.h index cac0f1a64fea..bfd171a3ded4 100644 --- a/drivers/media/platform/amphion/vpu.h +++ b/drivers/media/platform/amphion/vpu.h @@ -328,7 +328,7 @@ static inline const char *vpu_core_type_desc(enum vpu_core_type type) static inline struct vpu_inst *to_inst(struct file *filp) { - return container_of(filp->private_data, struct vpu_inst, fh); + return container_of(file_to_v4l2_fh(filp), struct vpu_inst, fh); } #define ctrl_to_inst(ctrl) \ diff --git a/drivers/media/platform/imagination/e5010-jpeg-enc.h b/drivers/media/platform/imagination/e5010-jpeg-enc.h index eefaf60489d3..da57bc1baa46 100644 --- a/drivers/media/platform/imagination/e5010-jpeg-enc.h +++ b/drivers/media/platform/imagination/e5010-jpeg-enc.h @@ -122,7 +122,7 @@ struct e5010_context { static inline struct e5010_context *to_e5010_context(struct file *filp) { - return container_of(filp->private_data, struct e5010_context, fh); + return container_of(file_to_v4l2_fh(filp), struct e5010_context, fh); } /* diff --git a/drivers/media/platform/nxp/dw100/dw100.c b/drivers/media/platform/nxp/dw100/dw100.c index 3d1db1121bf9..2460f09a6813 100644 --- a/drivers/media/platform/nxp/dw100/dw100.c +++ b/drivers/media/platform/nxp/dw100/dw100.c @@ -266,7 +266,7 @@ static inline int dw100_dump_regs(struct seq_file *m) static inline struct dw100_ctx *dw100_file2ctx(struct file *file) { - return container_of(file->private_data, struct dw100_ctx, fh); + return container_of(file_to_v4l2_fh(file), struct dw100_ctx, fh); } static struct dw100_q_data *dw100_get_q_data(struct dw100_ctx *ctx, diff --git a/drivers/media/platform/nxp/imx-pxp.c b/drivers/media/platform/nxp/imx-pxp.c index 7f8ffbac582f..879b1803a2b3 100644 --- a/drivers/media/platform/nxp/imx-pxp.c +++ b/drivers/media/platform/nxp/imx-pxp.c @@ -248,7 +248,7 @@ struct pxp_ctx { static inline struct pxp_ctx *file2ctx(struct file *file) { - return container_of(file->private_data, struct pxp_ctx, fh); + return container_of(file_to_v4l2_fh(file), struct pxp_ctx, fh); } static struct pxp_q_data *get_q_data(struct pxp_ctx *ctx, diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/qcom/iris/iris_vidc.c index c417e8c31f80..0c3b47b9958a 100644 --- a/drivers/media/platform/qcom/iris/iris_vidc.c +++ b/drivers/media/platform/qcom/iris/iris_vidc.c @@ -69,7 +69,7 @@ static void iris_remove_session(struct iris_inst *inst) static inline struct iris_inst *iris_get_inst(struct file *filp, void *fh) { - return container_of(filp->private_data, struct iris_inst, fh); + return container_of(file_to_v4l2_fh(filp), struct iris_inst, fh); } static void iris_m2m_device_run(void *priv) diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index 5b1ba1c69adb..3c0c5f9dbe7b 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -535,7 +535,7 @@ struct venus_inst { static inline struct venus_inst *to_inst(struct file *filp) { - return container_of(filp->private_data, struct venus_inst, fh); + return container_of(file_to_v4l2_fh(filp), struct venus_inst, fh); } static inline void *to_hfi_priv(struct venus_core *core) diff --git a/drivers/media/platform/samsung/s3c-camif/camif-capture.c b/drivers/media/platform/samsung/s3c-camif/camif-capture.c index 3e566b65f417..cae15a4ce5fd 100644 --- a/drivers/media/platform/samsung/s3c-camif/camif-capture.c +++ b/drivers/media/platform/samsung/s3c-camif/camif-capture.c @@ -572,7 +572,7 @@ static int s3c_camif_close(struct file *file) mutex_lock(&camif->lock); - if (vp->owner == file->private_data) { + if (vp->owner == file_to_v4l2_fh(file)) { camif_stop_capture(vp); vb2_queue_release(&vp->vb_queue); vp->owner = NULL; @@ -595,7 +595,7 @@ static __poll_t s3c_camif_poll(struct file *file, __poll_t ret; mutex_lock(&camif->lock); - if (vp->owner && vp->owner != file->private_data) + if (vp->owner && vp->owner != file_to_v4l2_fh(file)) ret = EPOLLERR; else ret = vb2_poll(&vp->vb_queue, file, wait); @@ -609,7 +609,7 @@ static int s3c_camif_mmap(struct file *file, struct vm_area_struct *vma) struct camif_vp *vp = video_drvdata(file); int ret; - if (vp->owner && vp->owner != file->private_data) + if (vp->owner && vp->owner != file_to_v4l2_fh(file)) ret = -EBUSY; else ret = vb2_mmap(&vp->vb_queue, vma); diff --git a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c index 3e7f2df70408..43755043e8af 100644 --- a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c +++ b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c @@ -309,7 +309,7 @@ static void deinterlace_init(struct deinterlace_dev *dev) static inline struct deinterlace_ctx *deinterlace_file2ctx(struct file *file) { - return container_of(file->private_data, struct deinterlace_ctx, fh); + return container_of(file_to_v4l2_fh(file), struct deinterlace_ctx, fh); } static bool deinterlace_check_format(u32 pixelformat) diff --git a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c index abd10b218aa1..d0608b5d900f 100644 --- a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c +++ b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c @@ -170,7 +170,7 @@ static irqreturn_t rotate_irq(int irq, void *data) static inline struct rotate_ctx *rotate_file2ctx(struct file *file) { - return container_of(file->private_data, struct rotate_ctx, fh); + return container_of(file_to_v4l2_fh(file), struct rotate_ctx, fh); } static void rotate_prepare_format(struct v4l2_pix_format *pix_fmt) diff --git a/drivers/media/platform/ti/vpe/vpe.c b/drivers/media/platform/ti/vpe/vpe.c index b76b5d18c963..4b9b2bec7377 100644 --- a/drivers/media/platform/ti/vpe/vpe.c +++ b/drivers/media/platform/ti/vpe/vpe.c @@ -424,7 +424,7 @@ struct vpe_ctx { static inline struct vpe_ctx *to_vpe_ctx(struct file *filp) { - return container_of(filp->private_data, struct vpe_ctx, fh); + return container_of(file_to_v4l2_fh(filp), struct vpe_ctx, fh); } /* diff --git a/drivers/media/test-drivers/vicodec/vicodec-core.c b/drivers/media/test-drivers/vicodec/vicodec-core.c index c45f5cf12ded..e27f6761cba1 100644 --- a/drivers/media/test-drivers/vicodec/vicodec-core.c +++ b/drivers/media/test-drivers/vicodec/vicodec-core.c @@ -144,7 +144,7 @@ static const struct v4l2_event vicodec_eos_event = { static inline struct vicodec_ctx *file2ctx(struct file *file) { - return container_of(file->private_data, struct vicodec_ctx, fh); + return container_of(file_to_v4l2_fh(file), struct vicodec_ctx, fh); } static struct vicodec_q_data *get_q_data(struct vicodec_ctx *ctx, diff --git a/drivers/media/test-drivers/vim2m.c b/drivers/media/test-drivers/vim2m.c index 1d1a9e768505..55d885be5bcc 100644 --- a/drivers/media/test-drivers/vim2m.c +++ b/drivers/media/test-drivers/vim2m.c @@ -236,7 +236,7 @@ struct vim2m_ctx { static inline struct vim2m_ctx *file2ctx(struct file *file) { - return container_of(file->private_data, struct vim2m_ctx, fh); + return container_of(file_to_v4l2_fh(file), struct vim2m_ctx, fh); } static struct vim2m_q_data *get_q_data(struct vim2m_ctx *ctx, diff --git a/drivers/media/test-drivers/visl/visl.h b/drivers/media/test-drivers/visl/visl.h index 434e9efbf9b2..ad3d0ab791d6 100644 --- a/drivers/media/test-drivers/visl/visl.h +++ b/drivers/media/test-drivers/visl/visl.h @@ -163,7 +163,7 @@ struct visl_ctrl_desc { static inline struct visl_ctx *visl_file_to_ctx(struct file *file) { - return container_of(file->private_data, struct visl_ctx, fh); + return container_of(file_to_v4l2_fh(file), struct visl_ctx, fh); } static inline struct visl_ctx *visl_v4l2fh_to_ctx(struct v4l2_fh *v4l2_fh) diff --git a/drivers/media/test-drivers/vivid/vivid-core.c b/drivers/media/test-drivers/vivid/vivid-core.c index 8d56168c72aa..9c9a93a3b540 100644 --- a/drivers/media/test-drivers/vivid/vivid-core.c +++ b/drivers/media/test-drivers/vivid/vivid-core.c @@ -654,11 +654,11 @@ static int vivid_fop_release(struct file *file) v4l2_info(&dev->v4l2_dev, "reconnect\n"); vivid_reconnect(dev); } - if (file->private_data == dev->radio_rx_rds_owner) { + if (file_to_v4l2_fh(file) == dev->radio_rx_rds_owner) { dev->radio_rx_rds_last_block = 0; dev->radio_rx_rds_owner = NULL; } - if (file->private_data == dev->radio_tx_rds_owner) { + if (file_to_v4l2_fh(file) == dev->radio_tx_rds_owner) { dev->radio_tx_rds_last_block = 0; dev->radio_tx_rds_owner = NULL; } diff --git a/drivers/media/test-drivers/vivid/vivid-radio-rx.c b/drivers/media/test-drivers/vivid/vivid-radio-rx.c index 79c1723bd84c..be711cae2d49 100644 --- a/drivers/media/test-drivers/vivid/vivid-radio-rx.c +++ b/drivers/media/test-drivers/vivid/vivid-radio-rx.c @@ -42,13 +42,13 @@ ssize_t vivid_radio_rx_read(struct file *file, char __user *buf, if (mutex_lock_interruptible(&dev->mutex)) return -ERESTARTSYS; if (dev->radio_rx_rds_owner && - file->private_data != dev->radio_rx_rds_owner) { + file_to_v4l2_fh(file) != dev->radio_rx_rds_owner) { mutex_unlock(&dev->mutex); return -EBUSY; } if (dev->radio_rx_rds_owner == NULL) { vivid_radio_rds_init(dev); - dev->radio_rx_rds_owner = file->private_data; + dev->radio_rx_rds_owner = file_to_v4l2_fh(file); } retry: diff --git a/drivers/media/test-drivers/vivid/vivid-radio-tx.c b/drivers/media/test-drivers/vivid/vivid-radio-tx.c index 049d40b948bb..f6e80b8d00a6 100644 --- a/drivers/media/test-drivers/vivid/vivid-radio-tx.c +++ b/drivers/media/test-drivers/vivid/vivid-radio-tx.c @@ -39,11 +39,11 @@ ssize_t vivid_radio_tx_write(struct file *file, const char __user *buf, if (mutex_lock_interruptible(&dev->mutex)) return -ERESTARTSYS; if (dev->radio_tx_rds_owner && - file->private_data != dev->radio_tx_rds_owner) { + file_to_v4l2_fh(file) != dev->radio_tx_rds_owner) { mutex_unlock(&dev->mutex); return -EBUSY; } - dev->radio_tx_rds_owner = file->private_data; + dev->radio_tx_rds_owner = file_to_v4l2_fh(file); retry: timestamp = ktime_sub(ktime_get(), dev->radio_rds_init_time); diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index 4c431bd9b503..ea17f1a5f5b0 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -390,7 +390,7 @@ static int hdpvr_release(struct file *file) struct hdpvr_device *dev = video_drvdata(file); mutex_lock(&dev->io_mutex); - if (file->private_data == dev->owner) { + if (file_to_v4l2_fh(file) == dev->owner) { hdpvr_stop_streaming(dev); dev->owner = NULL; } @@ -426,7 +426,7 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count, mutex_unlock(&dev->io_mutex); goto err; } - dev->owner = file->private_data; + dev->owner = file_to_v4l2_fh(file); print_buffer_status(); } mutex_unlock(&dev->io_mutex); @@ -541,7 +541,7 @@ static __poll_t hdpvr_poll(struct file *filp, poll_table *wait) "start_streaming failed\n"); dev->status = STATUS_IDLE; } else { - dev->owner = filp->private_data; + dev->owner = file_to_v4l2_fh(filp); } print_buffer_status(); @@ -1048,7 +1048,7 @@ static int vidioc_encoder_cmd(struct file *filp, void *priv, switch (a->cmd) { case V4L2_ENC_CMD_START: - if (dev->owner && filp->private_data != dev->owner) { + if (dev->owner && file_to_v4l2_fh(filp) != dev->owner) { res = -EBUSY; break; } @@ -1056,12 +1056,12 @@ static int vidioc_encoder_cmd(struct file *filp, void *priv, break; res = hdpvr_start_streaming(dev); if (!res) - dev->owner = filp->private_data; + dev->owner = file_to_v4l2_fh(filp); else dev->status = STATUS_IDLE; break; case V4L2_ENC_CMD_STOP: - if (dev->owner && filp->private_data != dev->owner) { + if (dev->owner && file_to_v4l2_fh(filp) != dev->owner) { res = -EBUSY; break; } diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index 7dc7c90ebf62..481b03bbecf8 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -48,7 +48,7 @@ struct pvr2_v4l2_fh { static inline struct pvr2_v4l2_fh *to_pvr2_v4l2_fh(struct file *filp) { - return container_of(filp->private_data, struct pvr2_v4l2_fh, fh); + return container_of(file_to_v4l2_fh(filp), struct pvr2_v4l2_fh, fh); } struct pvr2_v4l2 { diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 8b5625203048..70dc80e2b213 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -639,7 +639,7 @@ struct uvc_fh { static inline struct uvc_fh *to_uvc_fh(struct file *filp) { - return container_of(filp->private_data, struct uvc_fh, vfh); + return container_of(file_to_v4l2_fh(filp), struct uvc_fh, vfh); } /* ------------------------------------------------------------------------ diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 8c07400bd280..8a5559225ff2 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -678,7 +678,7 @@ static inline bool ctrl_is_pointer(struct file *file, u32 id) const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops; if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags)) - fh = file->private_data; + fh = file_to_v4l2_fh(file); if (fh && fh->ctrl_handler) hdl = fh->ctrl_handler; diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 46da373066f4..8c81852c3046 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1197,7 +1197,7 @@ static int v4l_s_priority(const struct v4l2_ioctl_ops *ops, vfd = video_devdata(file); if (!test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) return -ENOTTY; - vfh = file->private_data; + vfh = file_to_v4l2_fh(file); return v4l2_prio_change(vfd->prio, &vfh->prio, *p); } @@ -3084,7 +3084,7 @@ static long __video_do_ioctl(struct file *file, } if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) - vfh = file->private_data; + vfh = file_to_v4l2_fh(file); /* * We need to serialize streamon/off with queueing new requests. diff --git a/drivers/staging/most/video/video.c b/drivers/staging/most/video/video.c index bce7ffeac8fe..116331cead2a 100644 --- a/drivers/staging/most/video/video.c +++ b/drivers/staging/most/video/video.c @@ -54,7 +54,7 @@ struct comp_fh { static inline struct comp_fh *to_comp_fh(struct file *filp) { - return container_of(filp->private_data, struct comp_fh, fh); + return container_of(file_to_v4l2_fh(filp), struct comp_fh, fh); } static LIST_HEAD(video_devices); diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h index 6f44dd732315..9e79cbe50715 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -196,6 +196,11 @@ struct uvc_file_handle { #define to_uvc_file_handle(handle) \ container_of(handle, struct uvc_file_handle, vfh) +static inline struct uvc_file_handle *file_to_uvc_file_handle(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct uvc_file_handle, vfh); +} + /* ------------------------------------------------------------------------ * Functions */ diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c index fc9a8d31a1e9..886300a29b90 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -685,7 +685,7 @@ uvc_v4l2_release(struct file *file) { struct video_device *vdev = video_devdata(file); struct uvc_device *uvc = video_get_drvdata(vdev); - struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data); + struct uvc_file_handle *handle = file_to_uvc_file_handle(file); struct uvc_video *video = handle->device; mutex_lock(&video->mutex); From 72517d9f76fe3b14a5f73ce5491e722c229a14bf Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:29:52 +0300 Subject: [PATCH 00510/11391] media: nvidia: tegra-vde: Replace file->private_data access Accessing file->private_data manually to retrieve the v4l2_fh pointer is error-prone, as the field is a void * and will happily cast implicitly to any pointer type. The tegra-vde driver accesses file->private_data in the tegra_open() function, right after setting the field to &ctx->fh. Replace the accesses with usage of &ctx->fh. No functional change is intended, this only paves the way to remove direct accesses to file->private_data and make V4L2 drivers safer. Other accesses to the field will be addressed separately. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/platform/nvidia/tegra-vde/v4l2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/nvidia/tegra-vde/v4l2.c b/drivers/media/platform/nvidia/tegra-vde/v4l2.c index 531a85e3fe49..393dc3f07d5c 100644 --- a/drivers/media/platform/nvidia/tegra-vde/v4l2.c +++ b/drivers/media/platform/nvidia/tegra-vde/v4l2.c @@ -836,10 +836,10 @@ static int tegra_open(struct file *file) v4l2_fh_add(&ctx->fh); tegra_reset_coded_fmt(ctx); - tegra_try_coded_fmt(file, file->private_data, &ctx->coded_fmt); + tegra_try_coded_fmt(file, &ctx->fh, &ctx->coded_fmt); tegra_reset_decoded_fmt(ctx); - tegra_try_decoded_fmt(file, file->private_data, &ctx->decoded_fmt); + tegra_try_decoded_fmt(file, &ctx->fh, &ctx->decoded_fmt); return 0; From 4416df03ddf28566bb7c0169d9bd1e696d567899 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:29:53 +0300 Subject: [PATCH 00511/11391] media: Replace file->private_data access with custom functions Accessing file->private_data manually to retrieve the v4l2_fh pointer is error-prone, as the field is a void * and will happily cast implicitly to any pointer type. Replace all remaining locations that read the v4l2_fh pointer directly from file->private_data and cast it to driver-specific file handle structures with driver-specific functions that use file_to_v4l2_fh() and perform the same cast. No functional change is intended, this only paves the way to remove direct accesses to file->private_data and make V4L2 drivers safer. Other accesses to the field will be addressed separately. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/pci/ivtv/ivtv-driver.h | 5 +++ drivers/media/pci/ivtv/ivtv-fileops.c | 10 +++--- drivers/media/pci/ivtv/ivtv-ioctl.c | 8 ++--- .../media/platform/allegro-dvt/allegro-core.c | 7 ++++- .../media/platform/amlogic/meson-ge2d/ge2d.c | 8 +++-- .../platform/chips-media/coda/coda-common.c | 7 ++++- .../platform/chips-media/wave5/wave5-helper.c | 2 +- .../platform/chips-media/wave5/wave5-vpu.h | 5 +++ drivers/media/platform/m2m-deinterlace.c | 7 ++++- .../platform/mediatek/jpeg/mtk_jpeg_core.c | 7 ++++- .../media/platform/mediatek/mdp/mtk_mdp_m2m.c | 7 ++++- .../platform/mediatek/mdp3/mtk-mdp3-m2m.c | 7 ++++- .../vcodec/decoder/mtk_vcodec_dec_drv.c | 2 +- .../vcodec/decoder/mtk_vcodec_dec_drv.h | 5 +++ .../vcodec/encoder/mtk_vcodec_enc_drv.c | 2 +- .../vcodec/encoder/mtk_vcodec_enc_drv.h | 5 +++ .../media/platform/nxp/imx-jpeg/mxc-jpeg.c | 7 ++++- .../platform/nxp/imx8-isi/imx8-isi-m2m.c | 7 ++++- drivers/media/platform/nxp/mx2_emmaprp.c | 7 ++++- drivers/media/platform/renesas/rcar_fdp1.c | 7 ++++- drivers/media/platform/renesas/rcar_jpu.c | 7 ++++- drivers/media/platform/rockchip/rga/rga.c | 3 +- drivers/media/platform/rockchip/rga/rga.h | 5 +++ .../media/platform/rockchip/rkvdec/rkvdec.c | 2 +- .../media/platform/rockchip/rkvdec/rkvdec.h | 5 +++ .../platform/samsung/exynos-gsc/gsc-core.h | 6 ++++ .../platform/samsung/exynos-gsc/gsc-m2m.c | 6 ++-- .../platform/samsung/exynos4-is/fimc-core.h | 5 +++ .../platform/samsung/exynos4-is/fimc-m2m.c | 2 +- drivers/media/platform/samsung/s5p-g2d/g2d.c | 7 +++-- .../platform/samsung/s5p-jpeg/jpeg-core.c | 9 ++++-- .../media/platform/samsung/s5p-mfc/s5p_mfc.c | 6 ++-- .../platform/samsung/s5p-mfc/s5p_mfc_common.h | 6 ++++ .../media/platform/st/sti/bdisp/bdisp-v4l2.c | 7 ++++- .../media/platform/st/sti/delta/delta-v4l2.c | 26 ++++++++++------ drivers/media/platform/st/sti/hva/hva-v4l2.c | 31 ++++++++++--------- drivers/media/platform/st/sti/hva/hva.h | 2 -- drivers/media/platform/st/stm32/dma2d/dma2d.c | 7 +++-- .../media/platform/sunxi/sun8i-di/sun8i-di.c | 3 +- .../sunxi/sun8i-rotate/sun8i_rotate.c | 3 +- drivers/media/platform/ti/omap3isp/ispvideo.c | 4 +-- drivers/media/platform/ti/omap3isp/ispvideo.h | 6 ++++ drivers/media/platform/verisilicon/hantro.h | 5 +++ .../media/platform/verisilicon/hantro_drv.c | 3 +- .../staging/media/imx/imx-media-csc-scaler.c | 7 ++++- drivers/staging/media/meson/vdec/vdec.c | 24 +++++--------- drivers/staging/media/meson/vdec/vdec.h | 5 +++ drivers/staging/media/sunxi/cedrus/cedrus.c | 3 +- drivers/staging/media/sunxi/cedrus/cedrus.h | 5 +++ .../staging/media/sunxi/cedrus/cedrus_video.c | 5 --- 50 files changed, 237 insertions(+), 100 deletions(-) diff --git a/drivers/media/pci/ivtv/ivtv-driver.h b/drivers/media/pci/ivtv/ivtv-driver.h index a6ffa99e16bc..e4033c2bee5c 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.h +++ b/drivers/media/pci/ivtv/ivtv-driver.h @@ -388,6 +388,11 @@ static inline struct ivtv_open_id *fh2id(struct v4l2_fh *fh) return container_of(fh, struct ivtv_open_id, fh); } +static inline struct ivtv_open_id *file2id(struct file *filp) +{ + return fh2id(file_to_v4l2_fh(filp)); +} + struct yuv_frame_info { u32 update; diff --git a/drivers/media/pci/ivtv/ivtv-fileops.c b/drivers/media/pci/ivtv/ivtv-fileops.c index 230d498108b5..cc91695a5b76 100644 --- a/drivers/media/pci/ivtv/ivtv-fileops.c +++ b/drivers/media/pci/ivtv/ivtv-fileops.c @@ -502,7 +502,7 @@ int ivtv_start_capture(struct ivtv_open_id *id) ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_t * pos) { - struct ivtv_open_id *id = fh2id(filp->private_data); + struct ivtv_open_id *id = file2id(filp); struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; ssize_t rc; @@ -564,7 +564,7 @@ static int ivtv_schedule_dma(struct ivtv_stream *s) static ssize_t ivtv_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *pos) { - struct ivtv_open_id *id = fh2id(filp->private_data); + struct ivtv_open_id *id = file2id(filp); struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; struct yuv_playback_info *yi = &itv->yuv_info; @@ -719,7 +719,7 @@ static ssize_t ivtv_write(struct file *filp, const char __user *user_buf, size_t ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *pos) { - struct ivtv_open_id *id = fh2id(filp->private_data); + struct ivtv_open_id *id = file2id(filp); struct ivtv *itv = id->itv; ssize_t res; @@ -732,7 +732,7 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c __poll_t ivtv_v4l2_dec_poll(struct file *filp, poll_table *wait) { - struct ivtv_open_id *id = fh2id(filp->private_data); + struct ivtv_open_id *id = file2id(filp); struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; __poll_t res = 0; @@ -767,7 +767,7 @@ __poll_t ivtv_v4l2_dec_poll(struct file *filp, poll_table *wait) __poll_t ivtv_v4l2_enc_poll(struct file *filp, poll_table *wait) { __poll_t req_events = poll_requested_events(wait); - struct ivtv_open_id *id = fh2id(filp->private_data); + struct ivtv_open_id *id = file2id(filp); struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; int eof = test_bit(IVTV_F_S_STREAMOFF, &s->s_flags); diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index 7947dcd615e8..d888435b71fb 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -727,7 +727,7 @@ static int ivtv_s_register(struct file *file, void *fh, const struct v4l2_dbg_re static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vcap) { - struct ivtv_open_id *id = fh2id(file->private_data); + struct ivtv_open_id *id = fh2id(file_to_v4l2_fh(file)); struct ivtv *itv = id->itv; strscpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver)); @@ -1584,7 +1584,7 @@ static int ivtv_log_status(struct file *file, void *fh) static int ivtv_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dec) { - struct ivtv_open_id *id = fh2id(file->private_data); + struct ivtv_open_id *id = fh2id(file_to_v4l2_fh(file)); struct ivtv *itv = id->itv; IVTV_DEBUG_IOCTL("VIDIOC_DECODER_CMD %d\n", dec->cmd); @@ -1593,7 +1593,7 @@ static int ivtv_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd static int ivtv_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dec) { - struct ivtv_open_id *id = fh2id(file->private_data); + struct ivtv_open_id *id = fh2id(file_to_v4l2_fh(file)); struct ivtv *itv = id->itv; IVTV_DEBUG_IOCTL("VIDIOC_TRY_DECODER_CMD %d\n", dec->cmd); @@ -1602,7 +1602,7 @@ static int ivtv_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) { - struct ivtv_open_id *id = fh2id(filp->private_data); + struct ivtv_open_id *id = fh2id(file_to_v4l2_fh(filp)); struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/allegro-core.c index 1f134e08923a..74977f3ae484 100644 --- a/drivers/media/platform/allegro-dvt/allegro-core.c +++ b/drivers/media/platform/allegro-dvt/allegro-core.c @@ -302,6 +302,11 @@ struct allegro_channel { unsigned int error; }; +static inline struct allegro_channel *file_to_channel(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct allegro_channel, fh); +} + static inline int allegro_channel_get_i_frame_qp(struct allegro_channel *channel) { @@ -3229,7 +3234,7 @@ static int allegro_open(struct file *file) static int allegro_release(struct file *file) { - struct allegro_channel *channel = fh_to_channel(file->private_data); + struct allegro_channel *channel = file_to_channel(file); v4l2_m2m_ctx_release(channel->fh.m2m_ctx); diff --git a/drivers/media/platform/amlogic/meson-ge2d/ge2d.c b/drivers/media/platform/amlogic/meson-ge2d/ge2d.c index 0c004bb8ba05..c7df29a2d820 100644 --- a/drivers/media/platform/amlogic/meson-ge2d/ge2d.c +++ b/drivers/media/platform/amlogic/meson-ge2d/ge2d.c @@ -82,6 +82,11 @@ struct ge2d_ctx { u32 xy_swap; }; +static inline struct ge2d_ctx *file_to_ge2d_ctx(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct ge2d_ctx, fh); +} + struct meson_ge2d { struct v4l2_device v4l2_dev; struct v4l2_m2m_dev *m2m_dev; @@ -871,8 +876,7 @@ static int ge2d_open(struct file *file) static int ge2d_release(struct file *file) { - struct ge2d_ctx *ctx = - container_of(file->private_data, struct ge2d_ctx, fh); + struct ge2d_ctx *ctx = file_to_ge2d_ctx(file); struct meson_ge2d *ge2d = ctx->ge2d; mutex_lock(&ge2d->mutex); diff --git a/drivers/media/platform/chips-media/coda/coda-common.c b/drivers/media/platform/chips-media/coda/coda-common.c index e6e3f5ec24f6..459b59149390 100644 --- a/drivers/media/platform/chips-media/coda/coda-common.c +++ b/drivers/media/platform/chips-media/coda/coda-common.c @@ -56,6 +56,11 @@ #define fh_to_ctx(__fh) container_of(__fh, struct coda_ctx, fh) +static inline struct coda_ctx *file_to_ctx(struct file *filp) +{ + return fh_to_ctx(file_to_v4l2_fh(filp)); +} + int coda_debug; module_param(coda_debug, int, 0644); MODULE_PARM_DESC(coda_debug, "Debug level (0-2)"); @@ -2733,7 +2738,7 @@ static int coda_open(struct file *file) static int coda_release(struct file *file) { struct coda_dev *dev = video_drvdata(file); - struct coda_ctx *ctx = fh_to_ctx(file->private_data); + struct coda_ctx *ctx = file_to_ctx(file); coda_dbg(1, ctx, "release instance (%p)\n", ctx); diff --git a/drivers/media/platform/chips-media/wave5/wave5-helper.c b/drivers/media/platform/chips-media/wave5/wave5-helper.c index 2c9d8cbca6e4..031dea0ee61c 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-helper.c +++ b/drivers/media/platform/chips-media/wave5/wave5-helper.c @@ -59,7 +59,7 @@ int wave5_vpu_release_device(struct file *filp, int (*close_func)(struct vpu_instance *inst, u32 *fail_res), char *name) { - struct vpu_instance *inst = wave5_to_vpu_inst(filp->private_data); + struct vpu_instance *inst = file_to_vpu_inst(filp); int ret = 0; v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx); diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu.h b/drivers/media/platform/chips-media/wave5/wave5-vpu.h index 3847332551fc..5943bdaa9c4c 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu.h +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu.h @@ -46,6 +46,11 @@ static inline struct vpu_instance *wave5_to_vpu_inst(struct v4l2_fh *vfh) return container_of(vfh, struct vpu_instance, v4l2_fh); } +static inline struct vpu_instance *file_to_vpu_inst(struct file *filp) +{ + return wave5_to_vpu_inst(file_to_v4l2_fh(filp)); +} + static inline struct vpu_instance *wave5_ctrl_to_vpu_inst(struct v4l2_ctrl *vctrl) { return container_of(vctrl->handler, struct vpu_instance, v4l2_ctrl_hdl); diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c index 5188f3189096..1812c07837ad 100644 --- a/drivers/media/platform/m2m-deinterlace.c +++ b/drivers/media/platform/m2m-deinterlace.c @@ -142,6 +142,11 @@ struct deinterlace_ctx { struct dma_interleaved_template *xt; }; +static inline struct deinterlace_ctx *file_to_ctx(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct deinterlace_ctx, fh); +} + /* * mem2mem callbacks */ @@ -872,7 +877,7 @@ static int deinterlace_open(struct file *file) static int deinterlace_release(struct file *file) { struct deinterlace_dev *pcdev = video_drvdata(file); - struct deinterlace_ctx *ctx = file->private_data; + struct deinterlace_ctx *ctx = file_to_ctx(file); dprintk(pcdev, "Releasing instance %p\n", ctx); diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c index 329e5787c2c2..3a7a6eb53d89 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c @@ -124,6 +124,11 @@ static inline struct mtk_jpeg_ctx *mtk_jpeg_fh_to_ctx(struct v4l2_fh *fh) return container_of(fh, struct mtk_jpeg_ctx, fh); } +static inline struct mtk_jpeg_ctx *mtk_jpeg_file_to_ctx(struct file *filp) +{ + return mtk_jpeg_fh_to_ctx(file_to_v4l2_fh(filp)); +} + static inline struct mtk_jpeg_src_buf *mtk_jpeg_vb2_to_srcbuf( struct vb2_buffer *vb) { @@ -1208,7 +1213,7 @@ static int mtk_jpeg_open(struct file *file) static int mtk_jpeg_release(struct file *file) { struct mtk_jpeg_dev *jpeg = video_drvdata(file); - struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(file->private_data); + struct mtk_jpeg_ctx *ctx = mtk_jpeg_file_to_ctx(file); mutex_lock(&jpeg->lock); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); diff --git a/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c b/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c index d0fd77dcf8e2..2d894b5bfaa7 100644 --- a/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c +++ b/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c @@ -353,6 +353,11 @@ static inline struct mtk_mdp_ctx *fh_to_ctx(struct v4l2_fh *fh) return container_of(fh, struct mtk_mdp_ctx, fh); } +static inline struct mtk_mdp_ctx *file_to_ctx(struct file *filp) +{ + return fh_to_ctx(file_to_v4l2_fh(filp)); +} + static inline struct mtk_mdp_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl) { return container_of(ctrl->handler, struct mtk_mdp_ctx, ctrl_handler); @@ -1137,7 +1142,7 @@ static int mtk_mdp_m2m_open(struct file *file) static int mtk_mdp_m2m_release(struct file *file) { - struct mtk_mdp_ctx *ctx = fh_to_ctx(file->private_data); + struct mtk_mdp_ctx *ctx = file_to_ctx(file); struct mtk_mdp_dev *mdp = ctx->mdp_dev; flush_workqueue(mdp->job_wq); diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c index 59ce5cce0698..886ff25c70eb 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c @@ -15,6 +15,11 @@ static inline struct mdp_m2m_ctx *fh_to_ctx(struct v4l2_fh *fh) return container_of(fh, struct mdp_m2m_ctx, fh); } +static inline struct mdp_m2m_ctx *file_to_ctx(struct file *filp) +{ + return fh_to_ctx(file_to_v4l2_fh(filp)); +} + static inline struct mdp_m2m_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl) { return container_of(ctrl->handler, struct mdp_m2m_ctx, ctrl_handler); @@ -643,7 +648,7 @@ static int mdp_m2m_open(struct file *file) static int mdp_m2m_release(struct file *file) { - struct mdp_m2m_ctx *ctx = fh_to_ctx(file->private_data); + struct mdp_m2m_ctx *ctx = file_to_ctx(file); struct mdp_dev *mdp = video_drvdata(file); struct device *dev = &mdp->pdev->dev; diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c index 9247d92d431d..18801883c31a 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c @@ -294,7 +294,7 @@ static int fops_vcodec_open(struct file *file) static int fops_vcodec_release(struct file *file) { struct mtk_vcodec_dec_dev *dev = video_drvdata(file); - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(file->private_data); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); mtk_v4l2_vdec_dbg(0, ctx, "[%d] decoder", ctx->id); mutex_lock(&dev->dev_mutex); diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h index aececca7ecf8..d047d7c580fb 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h @@ -314,6 +314,11 @@ static inline struct mtk_vcodec_dec_ctx *fh_to_dec_ctx(struct v4l2_fh *fh) return container_of(fh, struct mtk_vcodec_dec_ctx, fh); } +static inline struct mtk_vcodec_dec_ctx *file_to_dec_ctx(struct file *filp) +{ + return fh_to_dec_ctx(file_to_v4l2_fh(filp)); +} + static inline struct mtk_vcodec_dec_ctx *ctrl_to_dec_ctx(struct v4l2_ctrl *ctrl) { return container_of(ctrl->handler, struct mtk_vcodec_dec_ctx, ctrl_hdl); diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c index a1e4483abcdb..e26a6c3ffa0c 100644 --- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c +++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c @@ -203,7 +203,7 @@ static int fops_vcodec_open(struct file *file) static int fops_vcodec_release(struct file *file) { struct mtk_vcodec_enc_dev *dev = video_drvdata(file); - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(file->private_data); + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); mtk_v4l2_venc_dbg(1, ctx, "[%d] encoder", ctx->id); mutex_lock(&dev->dev_mutex); diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.h b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.h index 0bd85d0fb379..a4fe2f453d8f 100644 --- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.h +++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.h @@ -222,6 +222,11 @@ static inline struct mtk_vcodec_enc_ctx *fh_to_enc_ctx(struct v4l2_fh *fh) return container_of(fh, struct mtk_vcodec_enc_ctx, fh); } +static inline struct mtk_vcodec_enc_ctx *file_to_enc_ctx(struct file *filp) +{ + return fh_to_enc_ctx(file_to_v4l2_fh(filp)); +} + static inline struct mtk_vcodec_enc_ctx *ctrl_to_enc_ctx(struct v4l2_ctrl *ctrl) { return container_of(ctrl->handler, struct mtk_vcodec_enc_ctx, ctrl_hdl); diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c index 1b2148578cb6..8eef7ebd0428 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c @@ -649,6 +649,11 @@ static inline struct mxc_jpeg_ctx *mxc_jpeg_fh_to_ctx(struct v4l2_fh *fh) return container_of(fh, struct mxc_jpeg_ctx, fh); } +static inline struct mxc_jpeg_ctx *mxc_jpeg_file_to_ctx(struct file *filp) +{ + return mxc_jpeg_fh_to_ctx(file_to_v4l2_fh(filp)); +} + static int enum_fmt(const struct mxc_jpeg_fmt *mxc_formats, int n, struct v4l2_fmtdesc *f, u32 type) { @@ -2735,7 +2740,7 @@ static const struct v4l2_ioctl_ops mxc_jpeg_ioctl_ops = { static int mxc_jpeg_release(struct file *file) { struct mxc_jpeg_dev *mxc_jpeg = video_drvdata(file); - struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(file->private_data); + struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file); struct device *dev = mxc_jpeg->dev; mutex_lock(&mxc_jpeg->lock); diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c index 22e49d3a1287..6444392c5e62 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c @@ -79,6 +79,11 @@ static inline struct mxc_isi_m2m_ctx *to_isi_m2m_ctx(struct v4l2_fh *fh) return container_of(fh, struct mxc_isi_m2m_ctx, fh); } +static inline struct mxc_isi_m2m_ctx *file_to_isi_m2m_ctx(struct file *filp) +{ + return to_isi_m2m_ctx(file_to_v4l2_fh(filp)); +} + static inline struct mxc_isi_m2m_ctx_queue_data * mxc_isi_m2m_ctx_qdata(struct mxc_isi_m2m_ctx *ctx, enum v4l2_buf_type type) { @@ -707,7 +712,7 @@ static int mxc_isi_m2m_open(struct file *file) static int mxc_isi_m2m_release(struct file *file) { struct mxc_isi_m2m *m2m = video_drvdata(file); - struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(file->private_data); + struct mxc_isi_m2m_ctx *ctx = file_to_isi_m2m_ctx(file); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); mxc_isi_m2m_ctx_ctrls_delete(ctx); diff --git a/drivers/media/platform/nxp/mx2_emmaprp.c b/drivers/media/platform/nxp/mx2_emmaprp.c index 0c6cc120fd2a..5c8c6285ec1e 100644 --- a/drivers/media/platform/nxp/mx2_emmaprp.c +++ b/drivers/media/platform/nxp/mx2_emmaprp.c @@ -214,6 +214,11 @@ struct emmaprp_ctx { struct emmaprp_q_data q_data[2]; }; +static inline struct emmaprp_ctx *file_to_emmaprp_ctx(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct emmaprp_ctx, fh); +} + static struct emmaprp_q_data *get_q_data(struct emmaprp_ctx *ctx, enum v4l2_buf_type type) { @@ -758,7 +763,7 @@ static int emmaprp_open(struct file *file) static int emmaprp_release(struct file *file) { struct emmaprp_dev *pcdev = video_drvdata(file); - struct emmaprp_ctx *ctx = file->private_data; + struct emmaprp_ctx *ctx = file_to_emmaprp_ctx(file); dprintk(pcdev, "Releasing instance %p\n", ctx); diff --git a/drivers/media/platform/renesas/rcar_fdp1.c b/drivers/media/platform/renesas/rcar_fdp1.c index 5d453a7a8988..12a5dcc0ca6c 100644 --- a/drivers/media/platform/renesas/rcar_fdp1.c +++ b/drivers/media/platform/renesas/rcar_fdp1.c @@ -635,6 +635,11 @@ static inline struct fdp1_ctx *fh_to_ctx(struct v4l2_fh *fh) return container_of(fh, struct fdp1_ctx, fh); } +static inline struct fdp1_ctx *file_to_ctx(struct file *filp) +{ + return fh_to_ctx(file_to_v4l2_fh(filp)); +} + static struct fdp1_q_data *get_q_data(struct fdp1_ctx *ctx, enum v4l2_buf_type type) { @@ -2158,7 +2163,7 @@ static int fdp1_open(struct file *file) static int fdp1_release(struct file *file) { struct fdp1_dev *fdp1 = video_drvdata(file); - struct fdp1_ctx *ctx = fh_to_ctx(file->private_data); + struct fdp1_ctx *ctx = file_to_ctx(file); dprintk(fdp1, "Releasing instance %p\n", ctx); diff --git a/drivers/media/platform/renesas/rcar_jpu.c b/drivers/media/platform/renesas/rcar_jpu.c index 81038df71bb5..7d5e9df53dfb 100644 --- a/drivers/media/platform/renesas/rcar_jpu.c +++ b/drivers/media/platform/renesas/rcar_jpu.c @@ -485,6 +485,11 @@ static struct jpu_ctx *fh_to_ctx(struct v4l2_fh *fh) return container_of(fh, struct jpu_ctx, fh); } +static struct jpu_ctx *file_to_ctx(struct file *filp) +{ + return fh_to_ctx(file_to_v4l2_fh(filp)); +} + static void jpu_set_tbl(struct jpu *jpu, u32 reg, const unsigned int *tbl, unsigned int len) { unsigned int i; @@ -1281,7 +1286,7 @@ static int jpu_open(struct file *file) static int jpu_release(struct file *file) { struct jpu *jpu = video_drvdata(file); - struct jpu_ctx *ctx = fh_to_ctx(file->private_data); + struct jpu_ctx *ctx = file_to_ctx(file); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); v4l2_ctrl_handler_free(&ctx->ctrl_handler); diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index 3dccab5fa4a1..8a6e618d605c 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -411,8 +411,7 @@ static int rga_open(struct file *file) static int rga_release(struct file *file) { - struct rga_ctx *ctx = - container_of(file->private_data, struct rga_ctx, fh); + struct rga_ctx *ctx = file_to_rga_ctx(file); struct rockchip_rga *rga = ctx->rga; mutex_lock(&rga->mutex); diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h index 530e12de73c4..72a28b120fab 100644 --- a/drivers/media/platform/rockchip/rga/rga.h +++ b/drivers/media/platform/rockchip/rga/rga.h @@ -68,6 +68,11 @@ struct rga_ctx { u32 fill_color; }; +static inline struct rga_ctx *file_to_rga_ctx(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct rga_ctx, fh); +} + struct rockchip_rga { struct v4l2_device v4l2_dev; struct v4l2_m2m_dev *m2m_dev; diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c index d707088ec0dc..41ab90cbcc0c 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c @@ -953,7 +953,7 @@ static int rkvdec_open(struct file *filp) static int rkvdec_release(struct file *filp) { - struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(filp->private_data); + struct rkvdec_ctx *ctx = file_to_rkvdec_ctx(filp); v4l2_fh_del(&ctx->fh); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h index f6e8bf38add3..3a6322d42b26 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h @@ -129,6 +129,11 @@ static inline struct rkvdec_ctx *fh_to_rkvdec_ctx(struct v4l2_fh *fh) return container_of(fh, struct rkvdec_ctx, fh); } +static inline struct rkvdec_ctx *file_to_rkvdec_ctx(struct file *filp) +{ + return fh_to_rkvdec_ctx(file_to_v4l2_fh(filp)); +} + struct rkvdec_aux_buf { void *cpu; dma_addr_t dma; diff --git a/drivers/media/platform/samsung/exynos-gsc/gsc-core.h b/drivers/media/platform/samsung/exynos-gsc/gsc-core.h index b9777e07fb6d..56856e9f9baf 100644 --- a/drivers/media/platform/samsung/exynos-gsc/gsc-core.h +++ b/drivers/media/platform/samsung/exynos-gsc/gsc-core.h @@ -86,6 +86,7 @@ enum gsc_yuv_fmt { }; #define fh_to_ctx(__fh) container_of(__fh, struct gsc_ctx, fh) + #define is_rgb(x) (!!((x) & 0x1)) #define is_yuv420(x) (!!((x) & 0x2)) #define is_yuv422(x) (!!((x) & 0x4)) @@ -381,6 +382,11 @@ struct gsc_ctx { enum v4l2_colorspace out_colorspace; }; +static inline struct gsc_ctx *file_to_ctx(struct file *filp) +{ + return fh_to_ctx(file_to_v4l2_fh(filp)); +} + void gsc_set_prefbuf(struct gsc_dev *gsc, struct gsc_frame *frm); int gsc_register_m2m_device(struct gsc_dev *gsc); void gsc_unregister_m2m_device(struct gsc_dev *gsc); diff --git a/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c b/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c index 4bda1c369c44..968bb4327b7a 100644 --- a/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c @@ -666,7 +666,7 @@ static int gsc_m2m_open(struct file *file) static int gsc_m2m_release(struct file *file) { - struct gsc_ctx *ctx = fh_to_ctx(file->private_data); + struct gsc_ctx *ctx = file_to_ctx(file); struct gsc_dev *gsc = ctx->gsc_dev; pr_debug("pid: %d, state: 0x%lx, refcnt= %d", @@ -690,7 +690,7 @@ static int gsc_m2m_release(struct file *file) static __poll_t gsc_m2m_poll(struct file *file, struct poll_table_struct *wait) { - struct gsc_ctx *ctx = fh_to_ctx(file->private_data); + struct gsc_ctx *ctx = file_to_ctx(file); struct gsc_dev *gsc = ctx->gsc_dev; __poll_t ret; @@ -705,7 +705,7 @@ static __poll_t gsc_m2m_poll(struct file *file, static int gsc_m2m_mmap(struct file *file, struct vm_area_struct *vma) { - struct gsc_ctx *ctx = fh_to_ctx(file->private_data); + struct gsc_ctx *ctx = file_to_ctx(file); struct gsc_dev *gsc = ctx->gsc_dev; int ret; diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-core.h b/drivers/media/platform/samsung/exynos4-is/fimc-core.h index 63385152a2ff..2b6c72d9442c 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-core.h +++ b/drivers/media/platform/samsung/exynos4-is/fimc-core.h @@ -498,6 +498,11 @@ struct fimc_ctx { #define fh_to_ctx(__fh) container_of(__fh, struct fimc_ctx, fh) +static inline struct fimc_ctx *file_to_ctx(struct file *filp) +{ + return fh_to_ctx(file_to_v4l2_fh(filp)); +} + static inline void set_frame_bounds(struct fimc_frame *f, u32 width, u32 height) { f->o_width = width; diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c b/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c index 951433c8e92a..feedf60dad09 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c @@ -675,7 +675,7 @@ static int fimc_m2m_open(struct file *file) static int fimc_m2m_release(struct file *file) { - struct fimc_ctx *ctx = fh_to_ctx(file->private_data); + struct fimc_ctx *ctx = file_to_ctx(file); struct fimc_dev *fimc = ctx->fimc_dev; dbg("pid: %d, state: 0x%lx, refcnt= %d", diff --git a/drivers/media/platform/samsung/s5p-g2d/g2d.c b/drivers/media/platform/samsung/s5p-g2d/g2d.c index ffed16a34493..44fcedbbc90a 100644 --- a/drivers/media/platform/samsung/s5p-g2d/g2d.c +++ b/drivers/media/platform/samsung/s5p-g2d/g2d.c @@ -25,7 +25,10 @@ #include "g2d.h" #include "g2d-regs.h" -#define fh2ctx(__fh) container_of(__fh, struct g2d_ctx, fh) +static inline struct g2d_ctx *file2ctx(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct g2d_ctx, fh); +} static struct g2d_fmt formats[] = { { @@ -272,7 +275,7 @@ static int g2d_open(struct file *file) static int g2d_release(struct file *file) { struct g2d_dev *dev = video_drvdata(file); - struct g2d_ctx *ctx = fh2ctx(file->private_data); + struct g2d_ctx *ctx = file2ctx(file); mutex_lock(&dev->mutex); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); diff --git a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c index ac4cf269456a..a5ecfe03db09 100644 --- a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c @@ -585,6 +585,11 @@ static inline struct s5p_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh) return container_of(fh, struct s5p_jpeg_ctx, fh); } +static inline struct s5p_jpeg_ctx *file_to_ctx(struct file *filp) +{ + return fh_to_ctx(file_to_v4l2_fh(filp)); +} + static int s5p_jpeg_to_user_subsampling(struct s5p_jpeg_ctx *ctx) { switch (ctx->jpeg->variant->version) { @@ -1012,7 +1017,7 @@ static int s5p_jpeg_open(struct file *file) static int s5p_jpeg_release(struct file *file) { struct s5p_jpeg *jpeg = video_drvdata(file); - struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data); + struct s5p_jpeg_ctx *ctx = file_to_ctx(file); mutex_lock(&jpeg->lock); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); @@ -1828,7 +1833,7 @@ static int s5p_jpeg_g_selection(struct file *file, void *priv, static int s5p_jpeg_s_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data); + struct s5p_jpeg_ctx *ctx = file_to_ctx(file); struct v4l2_rect *rect = &s->r; int ret = -EINVAL; diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c index 73fdcd362265..dd9761df59df 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c @@ -970,7 +970,7 @@ static int s5p_mfc_open(struct file *file) /* Release MFC context */ static int s5p_mfc_release(struct file *file) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); struct s5p_mfc_dev *dev = ctx->dev; /* if dev is null, do cleanup that doesn't need dev */ @@ -1027,7 +1027,7 @@ static int s5p_mfc_release(struct file *file) static __poll_t s5p_mfc_poll(struct file *file, struct poll_table_struct *wait) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); struct s5p_mfc_dev *dev = ctx->dev; struct vb2_queue *src_q, *dst_q; struct vb2_buffer *src_vb = NULL, *dst_vb = NULL; @@ -1078,7 +1078,7 @@ static __poll_t s5p_mfc_poll(struct file *file, /* Mmap */ static int s5p_mfc_mmap(struct file *file, struct vm_area_struct *vma) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; int ret; diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h index 86c316c1ff8f..a29228b4207f 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h @@ -768,6 +768,12 @@ struct mfc_control { ((f && f->op) ? f->op(args) : (typeof(f->op(args)))(-ENODEV)) #define fh_to_ctx(__fh) container_of(__fh, struct s5p_mfc_ctx, fh) + +static inline struct s5p_mfc_ctx *file_to_ctx(struct file *filp) +{ + return fh_to_ctx(file_to_v4l2_fh(filp)); +} + #define ctrl_to_ctx(__ctrl) \ container_of((__ctrl)->handler, struct s5p_mfc_ctx, ctrl_handler) diff --git a/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c index 1eb934490c0b..f3844e4e47ca 100644 --- a/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c +++ b/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c @@ -35,6 +35,11 @@ #define fh_to_ctx(__fh) container_of(__fh, struct bdisp_ctx, fh) +static inline struct bdisp_ctx *file_to_ctx(struct file *filp) +{ + return fh_to_ctx(file_to_v4l2_fh(filp)); +} + enum bdisp_dev_flags { ST_M2M_OPEN, /* Driver opened */ ST_M2M_RUNNING, /* HW device running */ @@ -644,7 +649,7 @@ static int bdisp_open(struct file *file) static int bdisp_release(struct file *file) { - struct bdisp_ctx *ctx = fh_to_ctx(file->private_data); + struct bdisp_ctx *ctx = file_to_ctx(file); struct bdisp_dev *bdisp = ctx->bdisp_dev; dev_dbg(bdisp->dev, "%s\n", __func__); diff --git a/drivers/media/platform/st/sti/delta/delta-v4l2.c b/drivers/media/platform/st/sti/delta/delta-v4l2.c index 196e6a40335d..a12fdbd8abed 100644 --- a/drivers/media/platform/st/sti/delta/delta-v4l2.c +++ b/drivers/media/platform/st/sti/delta/delta-v4l2.c @@ -25,6 +25,12 @@ #define DELTA_PREFIX "[---:----]" #define to_ctx(__fh) container_of(__fh, struct delta_ctx, fh) + +static inline struct delta_ctx *file_to_ctx(struct file *filp) +{ + return to_ctx(file_to_v4l2_fh(filp)); +} + #define to_au(__vbuf) container_of(__vbuf, struct delta_au, vbuf) #define to_frame(__vbuf) container_of(__vbuf, struct delta_frame, vbuf) @@ -382,7 +388,7 @@ static int delta_open_decoder(struct delta_ctx *ctx, u32 streamformat, static int delta_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct delta_ctx *ctx = to_ctx(file->private_data); + struct delta_ctx *ctx = file_to_ctx(file); struct delta_dev *delta = ctx->dev; strscpy(cap->driver, DELTA_NAME, sizeof(cap->driver)); @@ -396,7 +402,7 @@ static int delta_querycap(struct file *file, void *priv, static int delta_enum_fmt_stream(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct delta_ctx *ctx = to_ctx(file->private_data); + struct delta_ctx *ctx = file_to_ctx(file); struct delta_dev *delta = ctx->dev; if (unlikely(f->index >= delta->nb_of_streamformats)) @@ -410,7 +416,7 @@ static int delta_enum_fmt_stream(struct file *file, void *priv, static int delta_enum_fmt_frame(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct delta_ctx *ctx = to_ctx(file->private_data); + struct delta_ctx *ctx = file_to_ctx(file); struct delta_dev *delta = ctx->dev; if (unlikely(f->index >= delta->nb_of_pixelformats)) @@ -424,7 +430,7 @@ static int delta_enum_fmt_frame(struct file *file, void *priv, static int delta_g_fmt_stream(struct file *file, void *fh, struct v4l2_format *f) { - struct delta_ctx *ctx = to_ctx(file->private_data); + struct delta_ctx *ctx = file_to_ctx(file); struct delta_dev *delta = ctx->dev; struct v4l2_pix_format *pix = &f->fmt.pix; struct delta_streaminfo *streaminfo = &ctx->streaminfo; @@ -452,7 +458,7 @@ static int delta_g_fmt_stream(struct file *file, void *fh, static int delta_g_fmt_frame(struct file *file, void *fh, struct v4l2_format *f) { - struct delta_ctx *ctx = to_ctx(file->private_data); + struct delta_ctx *ctx = file_to_ctx(file); struct delta_dev *delta = ctx->dev; struct v4l2_pix_format *pix = &f->fmt.pix; struct delta_frameinfo *frameinfo = &ctx->frameinfo; @@ -491,7 +497,7 @@ static int delta_g_fmt_frame(struct file *file, void *fh, struct v4l2_format *f) static int delta_try_fmt_stream(struct file *file, void *priv, struct v4l2_format *f) { - struct delta_ctx *ctx = to_ctx(file->private_data); + struct delta_ctx *ctx = file_to_ctx(file); struct delta_dev *delta = ctx->dev; struct v4l2_pix_format *pix = &f->fmt.pix; u32 streamformat = pix->pixelformat; @@ -545,7 +551,7 @@ static int delta_try_fmt_stream(struct file *file, void *priv, static int delta_try_fmt_frame(struct file *file, void *priv, struct v4l2_format *f) { - struct delta_ctx *ctx = to_ctx(file->private_data); + struct delta_ctx *ctx = file_to_ctx(file); struct delta_dev *delta = ctx->dev; struct v4l2_pix_format *pix = &f->fmt.pix; u32 pixelformat = pix->pixelformat; @@ -605,7 +611,7 @@ static int delta_try_fmt_frame(struct file *file, void *priv, static int delta_s_fmt_stream(struct file *file, void *fh, struct v4l2_format *f) { - struct delta_ctx *ctx = to_ctx(file->private_data); + struct delta_ctx *ctx = file_to_ctx(file); struct delta_dev *delta = ctx->dev; struct vb2_queue *vq; struct v4l2_pix_format *pix = &f->fmt.pix; @@ -641,7 +647,7 @@ static int delta_s_fmt_stream(struct file *file, void *fh, static int delta_s_fmt_frame(struct file *file, void *fh, struct v4l2_format *f) { - struct delta_ctx *ctx = to_ctx(file->private_data); + struct delta_ctx *ctx = file_to_ctx(file); struct delta_dev *delta = ctx->dev; const struct delta_dec *dec = ctx->dec; struct v4l2_pix_format *pix = &f->fmt.pix; @@ -1690,7 +1696,7 @@ static int delta_open(struct file *file) static int delta_release(struct file *file) { - struct delta_ctx *ctx = to_ctx(file->private_data); + struct delta_ctx *ctx = file_to_ctx(file); struct delta_dev *delta = ctx->dev; const struct delta_dec *dec = ctx->dec; diff --git a/drivers/media/platform/st/sti/hva/hva-v4l2.c b/drivers/media/platform/st/sti/hva/hva-v4l2.c index 5366c0f92549..29142c806cb7 100644 --- a/drivers/media/platform/st/sti/hva/hva-v4l2.c +++ b/drivers/media/platform/st/sti/hva/hva-v4l2.c @@ -36,7 +36,10 @@ #define to_type_str(type) (type == V4L2_BUF_TYPE_VIDEO_OUTPUT ? \ "frame" : "stream") -#define fh_to_ctx(f) (container_of(f, struct hva_ctx, fh)) +static inline struct hva_ctx *file_to_ctx(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct hva_ctx, fh); +} /* registry of available encoders */ static const struct hva_enc *hva_encoders[] = { @@ -254,7 +257,7 @@ static void hva_dbg_summary(struct hva_ctx *ctx) static int hva_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct hva_ctx *ctx = fh_to_ctx(file->private_data); + struct hva_ctx *ctx = file_to_ctx(file); struct hva_dev *hva = ctx_to_hdev(ctx); strscpy(cap->driver, HVA_NAME, sizeof(cap->driver)); @@ -268,7 +271,7 @@ static int hva_querycap(struct file *file, void *priv, static int hva_enum_fmt_stream(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct hva_ctx *ctx = fh_to_ctx(file->private_data); + struct hva_ctx *ctx = file_to_ctx(file); struct hva_dev *hva = ctx_to_hdev(ctx); if (unlikely(f->index >= hva->nb_of_streamformats)) @@ -282,7 +285,7 @@ static int hva_enum_fmt_stream(struct file *file, void *priv, static int hva_enum_fmt_frame(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct hva_ctx *ctx = fh_to_ctx(file->private_data); + struct hva_ctx *ctx = file_to_ctx(file); struct hva_dev *hva = ctx_to_hdev(ctx); if (unlikely(f->index >= hva->nb_of_pixelformats)) @@ -295,7 +298,7 @@ static int hva_enum_fmt_frame(struct file *file, void *priv, static int hva_g_fmt_stream(struct file *file, void *fh, struct v4l2_format *f) { - struct hva_ctx *ctx = fh_to_ctx(file->private_data); + struct hva_ctx *ctx = file_to_ctx(file); struct hva_streaminfo *streaminfo = &ctx->streaminfo; f->fmt.pix.width = streaminfo->width; @@ -314,7 +317,7 @@ static int hva_g_fmt_stream(struct file *file, void *fh, struct v4l2_format *f) static int hva_g_fmt_frame(struct file *file, void *fh, struct v4l2_format *f) { - struct hva_ctx *ctx = fh_to_ctx(file->private_data); + struct hva_ctx *ctx = file_to_ctx(file); struct hva_frameinfo *frameinfo = &ctx->frameinfo; f->fmt.pix.width = frameinfo->width; @@ -335,7 +338,7 @@ static int hva_g_fmt_frame(struct file *file, void *fh, struct v4l2_format *f) static int hva_try_fmt_stream(struct file *file, void *priv, struct v4l2_format *f) { - struct hva_ctx *ctx = fh_to_ctx(file->private_data); + struct hva_ctx *ctx = file_to_ctx(file); struct device *dev = ctx_to_dev(ctx); struct v4l2_pix_format *pix = &f->fmt.pix; u32 streamformat = pix->pixelformat; @@ -399,7 +402,7 @@ static int hva_try_fmt_stream(struct file *file, void *priv, static int hva_try_fmt_frame(struct file *file, void *priv, struct v4l2_format *f) { - struct hva_ctx *ctx = fh_to_ctx(file->private_data); + struct hva_ctx *ctx = file_to_ctx(file); struct device *dev = ctx_to_dev(ctx); struct v4l2_pix_format *pix = &f->fmt.pix; u32 pixelformat = pix->pixelformat; @@ -449,7 +452,7 @@ static int hva_try_fmt_frame(struct file *file, void *priv, static int hva_s_fmt_stream(struct file *file, void *fh, struct v4l2_format *f) { - struct hva_ctx *ctx = fh_to_ctx(file->private_data); + struct hva_ctx *ctx = file_to_ctx(file); struct device *dev = ctx_to_dev(ctx); struct vb2_queue *vq; int ret; @@ -479,7 +482,7 @@ static int hva_s_fmt_stream(struct file *file, void *fh, struct v4l2_format *f) static int hva_s_fmt_frame(struct file *file, void *fh, struct v4l2_format *f) { - struct hva_ctx *ctx = fh_to_ctx(file->private_data); + struct hva_ctx *ctx = file_to_ctx(file); struct device *dev = ctx_to_dev(ctx); struct v4l2_pix_format *pix = &f->fmt.pix; struct vb2_queue *vq; @@ -517,7 +520,7 @@ static int hva_s_fmt_frame(struct file *file, void *fh, struct v4l2_format *f) static int hva_g_parm(struct file *file, void *fh, struct v4l2_streamparm *sp) { - struct hva_ctx *ctx = fh_to_ctx(file->private_data); + struct hva_ctx *ctx = file_to_ctx(file); struct v4l2_fract *time_per_frame = &ctx->ctrls.time_per_frame; if (sp->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) @@ -533,7 +536,7 @@ static int hva_g_parm(struct file *file, void *fh, struct v4l2_streamparm *sp) static int hva_s_parm(struct file *file, void *fh, struct v4l2_streamparm *sp) { - struct hva_ctx *ctx = fh_to_ctx(file->private_data); + struct hva_ctx *ctx = file_to_ctx(file); struct v4l2_fract *time_per_frame = &ctx->ctrls.time_per_frame; if (sp->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) @@ -553,7 +556,7 @@ static int hva_s_parm(struct file *file, void *fh, struct v4l2_streamparm *sp) static int hva_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct hva_ctx *ctx = fh_to_ctx(file->private_data); + struct hva_ctx *ctx = file_to_ctx(file); struct device *dev = ctx_to_dev(ctx); if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { @@ -1225,7 +1228,7 @@ static int hva_open(struct file *file) static int hva_release(struct file *file) { - struct hva_ctx *ctx = fh_to_ctx(file->private_data); + struct hva_ctx *ctx = file_to_ctx(file); struct hva_dev *hva = ctx_to_hdev(ctx); struct device *dev = ctx_to_dev(ctx); const struct hva_enc *enc = ctx->enc; diff --git a/drivers/media/platform/st/sti/hva/hva.h b/drivers/media/platform/st/sti/hva/hva.h index ba6b893416ec..1fe561082a74 100644 --- a/drivers/media/platform/st/sti/hva/hva.h +++ b/drivers/media/platform/st/sti/hva/hva.h @@ -13,8 +13,6 @@ #include #include -#define fh_to_ctx(f) (container_of(f, struct hva_ctx, fh)) - #define hva_to_dev(h) (h->dev) #define ctx_to_dev(c) (c->hva_dev->dev) diff --git a/drivers/media/platform/st/stm32/dma2d/dma2d.c b/drivers/media/platform/st/stm32/dma2d/dma2d.c index 48fa781aab06..f4c5d73447a7 100644 --- a/drivers/media/platform/st/stm32/dma2d/dma2d.c +++ b/drivers/media/platform/st/stm32/dma2d/dma2d.c @@ -45,7 +45,10 @@ * whole of a destination image with a pixel format conversion. */ -#define fh2ctx(__fh) container_of(__fh, struct dma2d_ctx, fh) +static inline struct dma2d_ctx *file2ctx(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct dma2d_ctx, fh); +} static const struct dma2d_fmt formats[] = { { @@ -318,7 +321,7 @@ static int dma2d_open(struct file *file) static int dma2d_release(struct file *file) { struct dma2d_dev *dev = video_drvdata(file); - struct dma2d_ctx *ctx = fh2ctx(file->private_data); + struct dma2d_ctx *ctx = file2ctx(file); mutex_lock(&dev->mutex); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); diff --git a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c index 43755043e8af..e9c7c99fbc55 100644 --- a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c +++ b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c @@ -756,8 +756,7 @@ static int deinterlace_open(struct file *file) static int deinterlace_release(struct file *file) { struct deinterlace_dev *dev = video_drvdata(file); - struct deinterlace_ctx *ctx = container_of(file->private_data, - struct deinterlace_ctx, fh); + struct deinterlace_ctx *ctx = deinterlace_file2ctx(file); mutex_lock(&dev->dev_mutex); diff --git a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c index d0608b5d900f..9ea65cb7187f 100644 --- a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c +++ b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c @@ -691,8 +691,7 @@ static int rotate_open(struct file *file) static int rotate_release(struct file *file) { struct rotate_dev *dev = video_drvdata(file); - struct rotate_ctx *ctx = container_of(file->private_data, - struct rotate_ctx, fh); + struct rotate_ctx *ctx = rotate_file2ctx(file); mutex_lock(&dev->dev_mutex); diff --git a/drivers/media/platform/ti/omap3isp/ispvideo.c b/drivers/media/platform/ti/omap3isp/ispvideo.c index a777135c6a6c..b76d40aeca17 100644 --- a/drivers/media/platform/ti/omap3isp/ispvideo.c +++ b/drivers/media/platform/ti/omap3isp/ispvideo.c @@ -1373,7 +1373,7 @@ static int isp_video_release(struct file *file) static __poll_t isp_video_poll(struct file *file, poll_table *wait) { - struct isp_video_fh *vfh = to_isp_video_fh(file->private_data); + struct isp_video_fh *vfh = file_to_isp_video_fh(file); struct isp_video *video = video_drvdata(file); __poll_t ret; @@ -1386,7 +1386,7 @@ static __poll_t isp_video_poll(struct file *file, poll_table *wait) static int isp_video_mmap(struct file *file, struct vm_area_struct *vma) { - struct isp_video_fh *vfh = to_isp_video_fh(file->private_data); + struct isp_video_fh *vfh = file_to_isp_video_fh(file); return vb2_mmap(&vfh->queue, vma); } diff --git a/drivers/media/platform/ti/omap3isp/ispvideo.h b/drivers/media/platform/ti/omap3isp/ispvideo.h index 1d23df576e6b..4364b4b14fb4 100644 --- a/drivers/media/platform/ti/omap3isp/ispvideo.h +++ b/drivers/media/platform/ti/omap3isp/ispvideo.h @@ -195,6 +195,12 @@ struct isp_video_fh { }; #define to_isp_video_fh(fh) container_of(fh, struct isp_video_fh, vfh) + +static inline struct isp_video_fh *file_to_isp_video_fh(struct file *filp) +{ + return to_isp_video_fh(file_to_v4l2_fh(filp)); +} + #define isp_video_queue_to_isp_video_fh(q) \ container_of(q, struct isp_video_fh, queue) diff --git a/drivers/media/platform/verisilicon/hantro.h b/drivers/media/platform/verisilicon/hantro.h index 81328c63b796..5b85c8a44706 100644 --- a/drivers/media/platform/verisilicon/hantro.h +++ b/drivers/media/platform/verisilicon/hantro.h @@ -387,6 +387,11 @@ static __always_inline struct hantro_ctx *fh_to_ctx(struct v4l2_fh *fh) return container_of(fh, struct hantro_ctx, fh); } +static __always_inline struct hantro_ctx *file_to_ctx(struct file *filp) +{ + return fh_to_ctx(file_to_v4l2_fh(filp)); +} + /* Register accessors. */ static __always_inline void vepu_write_relaxed(struct hantro_dev *vpu, u32 val, u32 reg) diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c index 8542238e0fb1..b20b9c7f4131 100644 --- a/drivers/media/platform/verisilicon/hantro_drv.c +++ b/drivers/media/platform/verisilicon/hantro_drv.c @@ -687,8 +687,7 @@ static int hantro_open(struct file *filp) static int hantro_release(struct file *filp) { - struct hantro_ctx *ctx = - container_of(filp->private_data, struct hantro_ctx, fh); + struct hantro_ctx *ctx = file_to_ctx(filp); /* * No need for extra locking because this was the last reference diff --git a/drivers/staging/media/imx/imx-media-csc-scaler.c b/drivers/staging/media/imx/imx-media-csc-scaler.c index 19fd31cb9bb0..fb67b383436d 100644 --- a/drivers/staging/media/imx/imx-media-csc-scaler.c +++ b/drivers/staging/media/imx/imx-media-csc-scaler.c @@ -66,6 +66,11 @@ struct ipu_csc_scaler_ctx { unsigned int sequence; }; +static inline struct ipu_csc_scaler_ctx *file_to_ctx(struct file *filp) +{ + return fh_to_ctx(file_to_v4l2_fh(filp)); +} + static struct ipu_csc_scaler_q_data *get_q_data(struct ipu_csc_scaler_ctx *ctx, enum v4l2_buf_type type) { @@ -797,7 +802,7 @@ static int ipu_csc_scaler_open(struct file *file) static int ipu_csc_scaler_release(struct file *file) { struct ipu_csc_scaler_priv *priv = video_drvdata(file); - struct ipu_csc_scaler_ctx *ctx = fh_to_ctx(file->private_data); + struct ipu_csc_scaler_ctx *ctx = file_to_ctx(file); dev_dbg(priv->dev, "Releasing instance %p\n", ctx); diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c index 6d34a482492e..f1ee53f9f298 100644 --- a/drivers/staging/media/meson/vdec/vdec.c +++ b/drivers/staging/media/meson/vdec/vdec.c @@ -558,8 +558,7 @@ vdec_try_fmt_common(struct amvdec_session *sess, u32 size, static int vdec_try_fmt(struct file *file, void *fh, struct v4l2_format *f) { - struct amvdec_session *sess = - container_of(file->private_data, struct amvdec_session, fh); + struct amvdec_session *sess = file_to_amvdec_session(file); vdec_try_fmt_common(sess, sess->core->platform->num_formats, f); @@ -568,8 +567,7 @@ static int vdec_try_fmt(struct file *file, void *fh, struct v4l2_format *f) static int vdec_g_fmt(struct file *file, void *fh, struct v4l2_format *f) { - struct amvdec_session *sess = - container_of(file->private_data, struct amvdec_session, fh); + struct amvdec_session *sess = file_to_amvdec_session(file); struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) @@ -596,8 +594,7 @@ static int vdec_g_fmt(struct file *file, void *fh, struct v4l2_format *f) static int vdec_s_fmt(struct file *file, void *fh, struct v4l2_format *f) { - struct amvdec_session *sess = - container_of(file->private_data, struct amvdec_session, fh); + struct amvdec_session *sess = file_to_amvdec_session(file); struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; u32 num_formats = sess->core->platform->num_formats; const struct amvdec_format *fmt_out; @@ -658,8 +655,7 @@ static int vdec_s_fmt(struct file *file, void *fh, struct v4l2_format *f) static int vdec_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) { - struct amvdec_session *sess = - container_of(file->private_data, struct amvdec_session, fh); + struct amvdec_session *sess = file_to_amvdec_session(file); const struct vdec_platform *platform = sess->core->platform; const struct amvdec_format *fmt_out; @@ -688,8 +684,7 @@ static int vdec_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) static int vdec_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize) { - struct amvdec_session *sess = - container_of(file->private_data, struct amvdec_session, fh); + struct amvdec_session *sess = file_to_amvdec_session(file); const struct amvdec_format *formats = sess->core->platform->formats; const struct amvdec_format *fmt; u32 num_formats = sess->core->platform->num_formats; @@ -713,8 +708,7 @@ static int vdec_enum_framesizes(struct file *file, void *fh, static int vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd) { - struct amvdec_session *sess = - container_of(file->private_data, struct amvdec_session, fh); + struct amvdec_session *sess = file_to_amvdec_session(file); struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; struct device *dev = sess->core->dev; int ret; @@ -773,8 +767,7 @@ static int vdec_subscribe_event(struct v4l2_fh *fh, static int vdec_g_pixelaspect(struct file *file, void *fh, int type, struct v4l2_fract *f) { - struct amvdec_session *sess = - container_of(file->private_data, struct amvdec_session, fh); + struct amvdec_session *sess = file_to_amvdec_session(file); if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) return -EINVAL; @@ -930,8 +923,7 @@ static int vdec_open(struct file *file) static int vdec_close(struct file *file) { - struct amvdec_session *sess = - container_of(file->private_data, struct amvdec_session, fh); + struct amvdec_session *sess = file_to_amvdec_session(file); v4l2_m2m_ctx_release(sess->m2m_ctx); v4l2_m2m_release(sess->m2m_dev); diff --git a/drivers/staging/media/meson/vdec/vdec.h b/drivers/staging/media/meson/vdec/vdec.h index 258685177700..7a5d8e871d70 100644 --- a/drivers/staging/media/meson/vdec/vdec.h +++ b/drivers/staging/media/meson/vdec/vdec.h @@ -282,6 +282,11 @@ struct amvdec_session { void *priv; }; +static inline struct amvdec_session *file_to_amvdec_session(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct amvdec_session, fh); +} + u32 amvdec_get_output_size(struct amvdec_session *sess); #endif diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index 52a9588462ce..80b43187f6ee 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -401,8 +401,7 @@ static int cedrus_open(struct file *file) static int cedrus_release(struct file *file) { struct cedrus_dev *dev = video_drvdata(file); - struct cedrus_ctx *ctx = container_of(file->private_data, - struct cedrus_ctx, fh); + struct cedrus_ctx *ctx = cedrus_file2ctx(file); mutex_lock(&dev->dev_mutex); diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h index 522c184e2afc..c4b1217c14b6 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus.h @@ -155,6 +155,11 @@ struct cedrus_ctx { } codec; }; +static inline struct cedrus_ctx *cedrus_file2ctx(struct file *file) +{ + return container_of(file_to_v4l2_fh(file), struct cedrus_ctx, fh); +} + struct cedrus_dec_ops { void (*irq_clear)(struct cedrus_ctx *ctx); void (*irq_disable)(struct cedrus_ctx *ctx); diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c index 9fae2c7493d0..ad4ec3490775 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c @@ -83,11 +83,6 @@ static struct cedrus_format cedrus_formats[] = { #define CEDRUS_FORMATS_COUNT ARRAY_SIZE(cedrus_formats) -static inline struct cedrus_ctx *cedrus_file2ctx(struct file *file) -{ - return container_of(file->private_data, struct cedrus_ctx, fh); -} - static struct cedrus_format *cedrus_find_format(struct cedrus_ctx *ctx, u32 pixelformat, u32 directions) { From cc6e8d1ccea792d8550428e0831e3a35b0ccfddc Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:29:54 +0300 Subject: [PATCH 00512/11391] media: pci: ivtv: Don't create fake v4l2_fh The ivtv driver has a structure named ivtv_open_id that models an open file handle for the device. It embeds a v4l2_fh instance for file handles that correspond to a V4L2 video device, and stores a pointer to that v4l2_fh in struct ivtv_stream to identify which open file handle owns a particular stream. In addition to video devices, streams can be owned by ALSA PCM devices. Those devices do not make use of the v4l2_fh instance for obvious reasons, but the snd_ivtv_pcm_capture_open() function still initializes a "fake" v4l2_fh for the sole purpose of using it as an open file handle identifier. The v4l2_fh is not properly destroyed when the ALSA PCM device is closed, leading to possible resource leaks. Fortunately, the v4l2_fh instance pointed to by ivtv_stream is not accessed, only the pointer value is used for comparison. Replace it with a pointer to the ivtv_open_id structure that embeds the v4l2_fh, and don't initialize the v4l2_fh for ALSA PCM devices. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/pci/ivtv/ivtv-alsa-pcm.c | 2 -- drivers/media/pci/ivtv/ivtv-driver.h | 3 ++- drivers/media/pci/ivtv/ivtv-fileops.c | 18 +++++++++--------- drivers/media/pci/ivtv/ivtv-irq.c | 4 ++-- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c index 8f346d7da9c8..269a799ec046 100644 --- a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c +++ b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c @@ -148,14 +148,12 @@ static int snd_ivtv_pcm_capture_open(struct snd_pcm_substream *substream) s = &itv->streams[IVTV_ENC_STREAM_TYPE_PCM]; - v4l2_fh_init(&item.fh, &s->vdev); item.itv = itv; item.type = s->type; /* See if the stream is available */ if (ivtv_claim_stream(&item, item.type)) { /* No, it's already in use */ - v4l2_fh_exit(&item.fh); snd_ivtv_unlock(itvsc); return -EBUSY; } diff --git a/drivers/media/pci/ivtv/ivtv-driver.h b/drivers/media/pci/ivtv/ivtv-driver.h index e4033c2bee5c..3d84004d4e90 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.h +++ b/drivers/media/pci/ivtv/ivtv-driver.h @@ -322,6 +322,7 @@ struct ivtv_queue { }; struct ivtv; /* forward reference */ +struct ivtv_open_id; struct ivtv_stream { /* These first four fields are always set, even if the stream @@ -331,7 +332,7 @@ struct ivtv_stream { const char *name; /* name of the stream */ int type; /* stream type */ - struct v4l2_fh *fh; /* pointer to the streaming filehandle */ + struct ivtv_open_id *id; /* pointer to the streaming ivtv_open_id */ spinlock_t qlock; /* locks access to the queues */ unsigned long s_flags; /* status flags, see above */ int dma; /* can be PCI_DMA_TODEVICE, PCI_DMA_FROMDEVICE or PCI_DMA_NONE */ diff --git a/drivers/media/pci/ivtv/ivtv-fileops.c b/drivers/media/pci/ivtv/ivtv-fileops.c index cc91695a5b76..67964a3c382c 100644 --- a/drivers/media/pci/ivtv/ivtv-fileops.c +++ b/drivers/media/pci/ivtv/ivtv-fileops.c @@ -39,16 +39,16 @@ int ivtv_claim_stream(struct ivtv_open_id *id, int type) if (test_and_set_bit(IVTV_F_S_CLAIMED, &s->s_flags)) { /* someone already claimed this stream */ - if (s->fh == &id->fh) { + if (s->id == id) { /* yes, this file descriptor did. So that's OK. */ return 0; } - if (s->fh == NULL && (type == IVTV_DEC_STREAM_TYPE_VBI || + if (s->id == NULL && (type == IVTV_DEC_STREAM_TYPE_VBI || type == IVTV_ENC_STREAM_TYPE_VBI)) { /* VBI is handled already internally, now also assign the file descriptor to this stream for external reading of the stream. */ - s->fh = &id->fh; + s->id = id; IVTV_DEBUG_INFO("Start Read VBI\n"); return 0; } @@ -56,7 +56,7 @@ int ivtv_claim_stream(struct ivtv_open_id *id, int type) IVTV_DEBUG_INFO("Stream %d is busy\n", type); return -EBUSY; } - s->fh = &id->fh; + s->id = id; if (type == IVTV_DEC_STREAM_TYPE_VBI) { /* Enable reinsertion interrupt */ ivtv_clear_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT); @@ -94,7 +94,7 @@ void ivtv_release_stream(struct ivtv_stream *s) struct ivtv *itv = s->itv; struct ivtv_stream *s_vbi; - s->fh = NULL; + s->id = NULL; if ((s->type == IVTV_DEC_STREAM_TYPE_VBI || s->type == IVTV_ENC_STREAM_TYPE_VBI) && test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) { /* this stream is still in use internally */ @@ -126,7 +126,7 @@ void ivtv_release_stream(struct ivtv_stream *s) /* was already cleared */ return; } - if (s_vbi->fh) { + if (s_vbi->id) { /* VBI stream still claimed by a file descriptor */ return; } @@ -359,7 +359,7 @@ static ssize_t ivtv_read(struct ivtv_stream *s, char __user *ubuf, size_t tot_co size_t tot_written = 0; int single_frame = 0; - if (atomic_read(&itv->capturing) == 0 && s->fh == NULL) { + if (atomic_read(&itv->capturing) == 0 && s->id == NULL) { /* shouldn't happen */ IVTV_DEBUG_WARN("Stream %s not initialized before read\n", s->name); return -EIO; @@ -831,7 +831,7 @@ void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end) id->type == IVTV_ENC_STREAM_TYPE_VBI) && test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) { /* Also used internally, don't stop capturing */ - s->fh = NULL; + s->id = NULL; } else { ivtv_stop_v4l2_encode_stream(s, gop_end); @@ -915,7 +915,7 @@ int ivtv_v4l2_close(struct file *filp) v4l2_fh_exit(fh); /* Easy case first: this stream was never claimed by us */ - if (s->fh != &id->fh) + if (s->id != id) goto close_done; /* 'Unclaim' this stream */ diff --git a/drivers/media/pci/ivtv/ivtv-irq.c b/drivers/media/pci/ivtv/ivtv-irq.c index 748c14e87963..20ba5ae9c6d1 100644 --- a/drivers/media/pci/ivtv/ivtv-irq.c +++ b/drivers/media/pci/ivtv/ivtv-irq.c @@ -305,7 +305,7 @@ static void dma_post(struct ivtv_stream *s) ivtv_process_vbi_data(itv, buf, 0, s->type); s->q_dma.bytesused += buf->bytesused; } - if (s->fh == NULL) { + if (s->id == NULL) { ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0); return; } @@ -330,7 +330,7 @@ static void dma_post(struct ivtv_stream *s) set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); } - if (s->fh) + if (s->id) wake_up(&s->waitq); } From 5d1e54bb4dc6741284a3ed587e994308ddee2f16 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:29:55 +0300 Subject: [PATCH 00513/11391] media: amphion: Make some vpu_v4l2 functions static Some functions defined in vpu_v4l2.c are never used outside of that compilation unit. Make them static. Signed-off-by: Laurent Pinchart Reviewed-by: Ming Qian Signed-off-by: Hans Verkuil --- drivers/media/platform/amphion/vpu_v4l2.c | 12 +++++++++--- drivers/media/platform/amphion/vpu_v4l2.h | 8 -------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c index 74668fa362e2..306d94e0f8e7 100644 --- a/drivers/media/platform/amphion/vpu_v4l2.c +++ b/drivers/media/platform/amphion/vpu_v4l2.c @@ -24,6 +24,11 @@ #include "vpu_msgs.h" #include "vpu_helpers.h" +static char *vpu_type_name(u32 type) +{ + return V4L2_TYPE_IS_OUTPUT(type) ? "output" : "capture"; +} + void vpu_inst_lock(struct vpu_inst *inst) { mutex_lock(&inst->lock); @@ -42,7 +47,7 @@ dma_addr_t vpu_get_vb_phy_addr(struct vb2_buffer *vb, u32 plane_no) vb->planes[plane_no].data_offset; } -unsigned int vpu_get_vb_length(struct vb2_buffer *vb, u32 plane_no) +static unsigned int vpu_get_vb_length(struct vb2_buffer *vb, u32 plane_no) { if (plane_no >= vb->num_planes) return 0; @@ -81,7 +86,7 @@ void vpu_v4l2_set_error(struct vpu_inst *inst) vpu_inst_unlock(inst); } -int vpu_notify_eos(struct vpu_inst *inst) +static int vpu_notify_eos(struct vpu_inst *inst) { static const struct v4l2_event ev = { .id = 0, @@ -573,7 +578,8 @@ static void vpu_vb2_buf_finish(struct vb2_buffer *vb) call_void_vop(inst, on_queue_empty, q->type); } -void vpu_vb2_buffers_return(struct vpu_inst *inst, unsigned int type, enum vb2_buffer_state state) +static void vpu_vb2_buffers_return(struct vpu_inst *inst, unsigned int type, + enum vb2_buffer_state state) { struct vb2_v4l2_buffer *buf; diff --git a/drivers/media/platform/amphion/vpu_v4l2.h b/drivers/media/platform/amphion/vpu_v4l2.h index 56f2939fa84d..4a87b06ae520 100644 --- a/drivers/media/platform/amphion/vpu_v4l2.h +++ b/drivers/media/platform/amphion/vpu_v4l2.h @@ -26,15 +26,12 @@ void vpu_skip_frame(struct vpu_inst *inst, int count); struct vb2_v4l2_buffer *vpu_find_buf_by_sequence(struct vpu_inst *inst, u32 type, u32 sequence); struct vb2_v4l2_buffer *vpu_find_buf_by_idx(struct vpu_inst *inst, u32 type, u32 idx); void vpu_v4l2_set_error(struct vpu_inst *inst); -int vpu_notify_eos(struct vpu_inst *inst); int vpu_notify_source_change(struct vpu_inst *inst); int vpu_set_last_buffer_dequeued(struct vpu_inst *inst, bool eos); -void vpu_vb2_buffers_return(struct vpu_inst *inst, unsigned int type, enum vb2_buffer_state state); int vpu_get_num_buffers(struct vpu_inst *inst, u32 type); bool vpu_is_source_empty(struct vpu_inst *inst); dma_addr_t vpu_get_vb_phy_addr(struct vb2_buffer *vb, u32 plane_no); -unsigned int vpu_get_vb_length(struct vb2_buffer *vb, u32 plane_no); static inline struct vpu_format *vpu_get_format(struct vpu_inst *inst, u32 type) { if (V4L2_TYPE_IS_OUTPUT(type)) @@ -43,11 +40,6 @@ static inline struct vpu_format *vpu_get_format(struct vpu_inst *inst, u32 type) return &inst->cap_format; } -static inline char *vpu_type_name(u32 type) -{ - return V4L2_TYPE_IS_OUTPUT(type) ? "output" : "capture"; -} - static inline int vpu_vb_is_codecconfig(struct vb2_v4l2_buffer *vbuf) { #ifdef V4L2_BUF_FLAG_CODECCONFIG From 19fb9c5b815f70eb90d5b545f65b83bc9c490ecd Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:29:56 +0300 Subject: [PATCH 00514/11391] media: amphion: Delete v4l2_fh synchronously in .release() The v4l2_fh initialized and added in vpu_v4l2_open() is delete and cleaned up when the last reference to the vpu_inst is released. This may happen later than at vpu_v4l2_close() time. Not deleting and cleaning up the v4l2_fh when closing the file handle to the video device is not ideal, as the v4l2_fh will still be present in the video device's fh_list, and will store a copy of events queued to the video device. There may also be other side effects of keeping alive an object that represents an open file handle after the file handle is closed. The v4l2_fh instance is embedded in the vpu_inst structure, and is accessed in two different ways: - in vpu_notify_eos() and vpu_notify_source_change(), to queue V4L2 events to the file handle ; and - through the driver to access the v4l2_fh.m2m_ctx pointer. The v4l2_fh.m2m_ctx pointer is not touched by v4l2_fh_del() and v4l2_fh_exit(). It is set to NULL by the driver when closing the file handle, in vpu_v4l2_close(). The vpu_notify_eos() and vpu_notify_source_change() functions are called in vpu_set_last_buffer_dequeued() and vdec_handle_resolution_change() respectively, only if the v4l2_fh.m2m_ctx pointer is not NULL. There is therefore a guarantee that no new event will be queued to the v4l2_fh after vpu_v4l2_close() destroys the m2m_ctx. The vpu_notify_eos() function is also called from vpu_vb2_buf_finish(), which is guaranteed to be called for all queued buffers when vpu_v4l2_close() calls v4l2_m2m_ctx_release(), and will not be called later. It is therefore safe to assume that the driver will not touch the v4l2_fh, except to check the m2m_ctx pointer, after vpu_v4l2_close() destroys the m2m_ctx. We can safely delete and cleanup the v4l2_fh synchronously in vpu_v4l2_close(). Signed-off-by: Laurent Pinchart Reviewed-by: Ming Qian Signed-off-by: Hans Verkuil --- drivers/media/platform/amphion/vpu_v4l2.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c index 306d94e0f8e7..57ca6262bb04 100644 --- a/drivers/media/platform/amphion/vpu_v4l2.c +++ b/drivers/media/platform/amphion/vpu_v4l2.c @@ -724,8 +724,6 @@ static int vpu_v4l2_release(struct vpu_inst *inst) v4l2_ctrl_handler_free(&inst->ctrl_handler); mutex_destroy(&inst->lock); - v4l2_fh_del(&inst->fh); - v4l2_fh_exit(&inst->fh); call_void_vop(inst, cleanup); @@ -794,6 +792,8 @@ int vpu_v4l2_open(struct file *file, struct vpu_inst *inst) return 0; error: + v4l2_fh_del(&inst->fh); + v4l2_fh_exit(&inst->fh); vpu_inst_put(inst); return ret; } @@ -813,6 +813,9 @@ int vpu_v4l2_close(struct file *file) call_void_vop(inst, release); vpu_inst_unlock(inst); + v4l2_fh_del(&inst->fh); + v4l2_fh_exit(&inst->fh); + vpu_inst_unregister(inst); vpu_inst_put(inst); From 1b847fa1bc9509150433aa16a1a1d3bac8a2bd38 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:29:57 +0300 Subject: [PATCH 00515/11391] media: visl: Drop visl_v4l2fh_to_ctx() function The visl_v4l2fh_to_ctx() function is unused. Drop it. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/test-drivers/visl/visl.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/media/test-drivers/visl/visl.h b/drivers/media/test-drivers/visl/visl.h index ad3d0ab791d6..2971e8b37ff6 100644 --- a/drivers/media/test-drivers/visl/visl.h +++ b/drivers/media/test-drivers/visl/visl.h @@ -166,11 +166,6 @@ static inline struct visl_ctx *visl_file_to_ctx(struct file *file) return container_of(file_to_v4l2_fh(file), struct visl_ctx, fh); } -static inline struct visl_ctx *visl_v4l2fh_to_ctx(struct v4l2_fh *v4l2_fh) -{ - return container_of(v4l2_fh, struct visl_ctx, fh); -} - void *visl_find_control_data(struct visl_ctx *ctx, u32 id); struct v4l2_ctrl *visl_find_control(struct visl_ctx *ctx, u32 id); u32 visl_control_num_elems(struct visl_ctx *ctx, u32 id); From bbe4debfaa6a16f11064d5c40ef6d468dad4398d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:29:58 +0300 Subject: [PATCH 00516/11391] media: v4l2-fh: Move piece of documentation to correct function The paragraph in the v4l2_fh_del() documentation that indicates the function sets filp->private_data was added in the wrong place. It is meant for v4l2_fh_open(). Move it to where it belongs. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- include/media/v4l2-fh.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/media/v4l2-fh.h b/include/media/v4l2-fh.h index 823fa8ebeb8f..14e7136e693f 100644 --- a/include/media/v4l2-fh.h +++ b/include/media/v4l2-fh.h @@ -101,6 +101,9 @@ void v4l2_fh_add(struct v4l2_fh *fh); * * It allocates a v4l2_fh and inits and adds it to the &struct video_device * associated with the file pointer. + * + * On error filp->private_data will be %NULL, otherwise it will point to + * the &struct v4l2_fh. */ int v4l2_fh_open(struct file *filp); @@ -109,9 +112,6 @@ int v4l2_fh_open(struct file *filp); * * @fh: pointer to &struct v4l2_fh * - * On error filp->private_data will be %NULL, otherwise it will point to - * the &struct v4l2_fh. - * * .. note:: * Must be called in v4l2_file_operations->release\(\) handler if the driver * uses &struct v4l2_fh. From 78b2c8a6cd2fed89ad98213558531a7db52a0eea Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:29:59 +0300 Subject: [PATCH 00517/11391] media: rcar-vin: Do not set file->private_data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The R-Car VIN driver sets file->private_data to the driver-specific structure, but the following call to v4l2_fh_open() overwrites it with a pointer to the just allocated v4l2_fh. Remove the mis-leading assignment in the driver. Signed-off-by: Jacopo Mondi Reviewed-by: Niklas Söderlund Signed-off-by: Hans Verkuil --- drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c b/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c index 62eddf3a35fc..079dbaf016c2 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c @@ -588,8 +588,6 @@ static int rvin_open(struct file *file) if (ret) goto err_pm; - file->private_data = vin; - ret = v4l2_fh_open(file); if (ret) goto err_unlock; From ff9c50a4a92ac72e42c132ef08bd50b5fa933b68 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:00 +0300 Subject: [PATCH 00518/11391] media: rzg2l-cru: Do not set file->private_data The RZ G2/L CRU driver sets file->private_data to the driver-specific structure, but the following call to v4l2_fh_open() overwrites it with a pointer to the just allocated v4l2_fh. Remove the mis-leading assignment in the driver. Signed-off-by: Jacopo Mondi Tested-by: Tommaso Merciai Reviewed-by: Tommaso Merciai Signed-off-by: Hans Verkuil --- drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c index a8817a7066b2..941badc90ff5 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c @@ -1078,7 +1078,6 @@ static int rzg2l_cru_open(struct file *file) if (ret) return ret; - file->private_data = cru; ret = v4l2_fh_open(file); if (ret) goto err_unlock; From caa5c3439af793a727a9dcb69b1fdec7ece66302 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:30:01 +0300 Subject: [PATCH 00519/11391] media: camss: Replace .open() file operation with v4l2_fh_open() The custom video_open() function in the camss driver open-codes the v4l2_fh_open() helper, with an additional mutex that protects the whole function. Given that the function does not modify any data guarded by the lock, there's no need for using the mutex and the function can be replaced by v4l2_fh_open(). Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- .../media/platform/qcom/camss/camss-video.c | 32 +------------------ 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c index 8d05802d1735..c5d02f9ebc6a 100644 --- a/drivers/media/platform/qcom/camss/camss-video.c +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -604,36 +604,6 @@ static const struct v4l2_ioctl_ops msm_vid_ioctl_ops = { * V4L2 file operations */ -static int video_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct camss_video *video = video_drvdata(file); - struct v4l2_fh *vfh; - int ret; - - mutex_lock(&video->lock); - - vfh = kzalloc(sizeof(*vfh), GFP_KERNEL); - if (vfh == NULL) { - ret = -ENOMEM; - goto error_alloc; - } - - v4l2_fh_init(vfh, vdev); - v4l2_fh_add(vfh); - - file->private_data = vfh; - - mutex_unlock(&video->lock); - - return 0; - -error_alloc: - mutex_unlock(&video->lock); - - return ret; -} - static int video_release(struct file *file) { vb2_fop_release(file); @@ -646,7 +616,7 @@ static int video_release(struct file *file) static const struct v4l2_file_operations msm_vid_fops = { .owner = THIS_MODULE, .unlocked_ioctl = video_ioctl2, - .open = video_open, + .open = v4l2_fh_open, .release = video_release, .poll = vb2_fop_poll, .mmap = vb2_fop_mmap, From 9c7ee499483d493152d5fd7cf477754099af14ed Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:02 +0300 Subject: [PATCH 00520/11391] media: camss: Remove custom .release fop() The 'file->private_data' pointer is reset in the vb2_fop_release() call path. For this reason a custom handler for the .release file operation is not needed and the driver can use vb2_fop_release() directly. Signed-off-by: Jacopo Mondi Signed-off-by: Hans Verkuil --- drivers/media/platform/qcom/camss/camss-video.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c index c5d02f9ebc6a..831486e14754 100644 --- a/drivers/media/platform/qcom/camss/camss-video.c +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -604,20 +604,11 @@ static const struct v4l2_ioctl_ops msm_vid_ioctl_ops = { * V4L2 file operations */ -static int video_release(struct file *file) -{ - vb2_fop_release(file); - - file->private_data = NULL; - - return 0; -} - static const struct v4l2_file_operations msm_vid_fops = { .owner = THIS_MODULE, .unlocked_ioctl = video_ioctl2, .open = v4l2_fh_open, - .release = video_release, + .release = vb2_fop_release, .poll = vb2_fop_poll, .mmap = vb2_fop_mmap, .read = vb2_fop_read, From b2eeb35c6137c8b04b6cb1b4b272e269c63e99d1 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:30:03 +0300 Subject: [PATCH 00521/11391] media: chips-media: wave5: Pass file pointer to wave5_cleanup_instance() In preparation for a tree-wide rework automated with coccinelle that will need to access a struct file pointer in the wave5_cleanup_instance() function, pass it from the callers. There is not functional change yet. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/platform/chips-media/wave5/wave5-helper.c | 4 ++-- drivers/media/platform/chips-media/wave5/wave5-helper.h | 2 +- drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c | 2 +- drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/chips-media/wave5/wave5-helper.c b/drivers/media/platform/chips-media/wave5/wave5-helper.c index 031dea0ee61c..ed8ff04a899d 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-helper.c +++ b/drivers/media/platform/chips-media/wave5/wave5-helper.c @@ -27,7 +27,7 @@ const char *state_to_str(enum vpu_instance_state state) } } -void wave5_cleanup_instance(struct vpu_instance *inst) +void wave5_cleanup_instance(struct vpu_instance *inst, struct file *filp) { int i; @@ -78,7 +78,7 @@ int wave5_vpu_release_device(struct file *filp, } } - wave5_cleanup_instance(inst); + wave5_cleanup_instance(inst, filp); return ret; } diff --git a/drivers/media/platform/chips-media/wave5/wave5-helper.h b/drivers/media/platform/chips-media/wave5/wave5-helper.h index 9937fce553fc..976a402e426f 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-helper.h +++ b/drivers/media/platform/chips-media/wave5/wave5-helper.h @@ -14,7 +14,7 @@ #define MAX_FMTS 12 const char *state_to_str(enum vpu_instance_state state); -void wave5_cleanup_instance(struct vpu_instance *inst); +void wave5_cleanup_instance(struct vpu_instance *inst, struct file *filp); int wave5_vpu_release_device(struct file *filp, int (*close_func)(struct vpu_instance *inst, u32 *fail_res), char *name); diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c index fd71f0c43ac3..f3188d720ed3 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c @@ -1840,7 +1840,7 @@ static int wave5_vpu_open_dec(struct file *filp) return 0; cleanup_inst: - wave5_cleanup_instance(inst); + wave5_cleanup_instance(inst, filp); return ret; } diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c index 1e5fc5f8b856..b69a1206fa12 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c @@ -1784,7 +1784,7 @@ static int wave5_vpu_open_enc(struct file *filp) return 0; cleanup_inst: - wave5_cleanup_instance(inst); + wave5_cleanup_instance(inst, filp); return ret; } From c284b5ab97a6ad8bdac9375dff0115ea49088c38 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:30:04 +0300 Subject: [PATCH 00522/11391] media: qcom: iris: Pass file pointer to iris_v4l2_fh_(de)init() In preparation for a tree-wide rework automated with coccinelle that will need to access a struct file pointer in the iris_v4l2_fh_init() and iris_v4l2_fh_deinit() functions, pass it from the callers. There is not functional change yet. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/platform/qcom/iris/iris_vidc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/qcom/iris/iris_vidc.c index 0c3b47b9958a..d5f99519def4 100644 --- a/drivers/media/platform/qcom/iris/iris_vidc.c +++ b/drivers/media/platform/qcom/iris/iris_vidc.c @@ -21,14 +21,14 @@ #define STEP_WIDTH 1 #define STEP_HEIGHT 1 -static void iris_v4l2_fh_init(struct iris_inst *inst) +static void iris_v4l2_fh_init(struct iris_inst *inst, struct file *filp) { v4l2_fh_init(&inst->fh, inst->core->vdev_dec); inst->fh.ctrl_handler = &inst->ctrl_handler; v4l2_fh_add(&inst->fh); } -static void iris_v4l2_fh_deinit(struct iris_inst *inst) +static void iris_v4l2_fh_deinit(struct iris_inst *inst, struct file *filp) { v4l2_fh_del(&inst->fh); inst->fh.ctrl_handler = NULL; @@ -164,7 +164,7 @@ int iris_open(struct file *filp) init_completion(&inst->completion); init_completion(&inst->flush_completion); - iris_v4l2_fh_init(inst); + iris_v4l2_fh_init(inst, filp); inst->m2m_dev = v4l2_m2m_init(&iris_m2m_ops); if (IS_ERR_OR_NULL(inst->m2m_dev)) { @@ -194,7 +194,7 @@ int iris_open(struct file *filp) fail_m2m_release: v4l2_m2m_release(inst->m2m_dev); fail_v4l2_fh_deinit: - iris_v4l2_fh_deinit(inst); + iris_v4l2_fh_deinit(inst, filp); mutex_destroy(&inst->ctx_q_lock); mutex_destroy(&inst->lock); kfree(inst); @@ -259,7 +259,7 @@ int iris_close(struct file *filp) iris_vdec_inst_deinit(inst); iris_session_close(inst); iris_inst_change_state(inst, IRIS_INST_DEINIT); - iris_v4l2_fh_deinit(inst); + iris_v4l2_fh_deinit(inst, filp); iris_destroy_all_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); iris_destroy_all_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); iris_check_num_queued_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); From 61a08386dcf48c708f42da9917a28f5ffe0701f6 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:30:05 +0300 Subject: [PATCH 00523/11391] media: qcom: iris: Set file->private_data in iris_v4l2_fh_(de)init() In preparation for a tree-wide rework automated with coccinelle that will affect file->private_data, v4l2_fh_add() and v4l2_fh_del(), move setting file->private_data from the callers to the iris_v4l2_fh_init() and iris_v4l2_fh_deinit() functions. There is not functional change yet. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/platform/qcom/iris/iris_vidc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/qcom/iris/iris_vidc.c index d5f99519def4..73c96498759c 100644 --- a/drivers/media/platform/qcom/iris/iris_vidc.c +++ b/drivers/media/platform/qcom/iris/iris_vidc.c @@ -26,10 +26,12 @@ static void iris_v4l2_fh_init(struct iris_inst *inst, struct file *filp) v4l2_fh_init(&inst->fh, inst->core->vdev_dec); inst->fh.ctrl_handler = &inst->ctrl_handler; v4l2_fh_add(&inst->fh); + filp->private_data = &inst->fh; } static void iris_v4l2_fh_deinit(struct iris_inst *inst, struct file *filp) { + filp->private_data = NULL; v4l2_fh_del(&inst->fh); inst->fh.ctrl_handler = NULL; v4l2_fh_exit(&inst->fh); @@ -185,7 +187,6 @@ int iris_open(struct file *filp) iris_add_session(inst); inst->fh.m2m_ctx = inst->m2m_ctx; - filp->private_data = &inst->fh; return 0; @@ -269,7 +270,6 @@ int iris_close(struct file *filp) mutex_destroy(&inst->ctx_q_lock); mutex_destroy(&inst->lock); kfree(inst); - filp->private_data = NULL; return 0; } From 99c414252648c9e59b3cdfda5916f156d1cee00e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:30:06 +0300 Subject: [PATCH 00524/11391] media: qcom: iris: Drop unused argument to iris_get_inst() The second argument to the iris_get_inst() function is never used. Drop it. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/platform/qcom/iris/iris_vidc.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/qcom/iris/iris_vidc.c index 73c96498759c..64ebec2ca6b3 100644 --- a/drivers/media/platform/qcom/iris/iris_vidc.c +++ b/drivers/media/platform/qcom/iris/iris_vidc.c @@ -69,7 +69,7 @@ static void iris_remove_session(struct iris_inst *inst) mutex_unlock(&core->lock); } -static inline struct iris_inst *iris_get_inst(struct file *filp, void *fh) +static inline struct iris_inst *iris_get_inst(struct file *filp) { return container_of(file_to_v4l2_fh(filp), struct iris_inst, fh); } @@ -251,7 +251,7 @@ static void iris_check_num_queued_internal_buffers(struct iris_inst *inst, u32 p int iris_close(struct file *filp) { - struct iris_inst *inst = iris_get_inst(filp, NULL); + struct iris_inst *inst = iris_get_inst(filp); v4l2_ctrl_handler_free(&inst->ctrl_handler); v4l2_m2m_ctx_release(inst->m2m_ctx); @@ -276,14 +276,14 @@ int iris_close(struct file *filp) static int iris_enum_fmt(struct file *filp, void *fh, struct v4l2_fmtdesc *f) { - struct iris_inst *inst = iris_get_inst(filp, NULL); + struct iris_inst *inst = iris_get_inst(filp); return iris_vdec_enum_fmt(inst, f); } static int iris_try_fmt_vid_mplane(struct file *filp, void *fh, struct v4l2_format *f) { - struct iris_inst *inst = iris_get_inst(filp, NULL); + struct iris_inst *inst = iris_get_inst(filp); int ret; mutex_lock(&inst->lock); @@ -295,7 +295,7 @@ static int iris_try_fmt_vid_mplane(struct file *filp, void *fh, struct v4l2_form static int iris_s_fmt_vid_mplane(struct file *filp, void *fh, struct v4l2_format *f) { - struct iris_inst *inst = iris_get_inst(filp, NULL); + struct iris_inst *inst = iris_get_inst(filp); int ret; mutex_lock(&inst->lock); @@ -307,7 +307,7 @@ static int iris_s_fmt_vid_mplane(struct file *filp, void *fh, struct v4l2_format static int iris_g_fmt_vid_mplane(struct file *filp, void *fh, struct v4l2_format *f) { - struct iris_inst *inst = iris_get_inst(filp, NULL); + struct iris_inst *inst = iris_get_inst(filp); int ret = 0; mutex_lock(&inst->lock); @@ -326,7 +326,7 @@ static int iris_g_fmt_vid_mplane(struct file *filp, void *fh, struct v4l2_format static int iris_enum_framesizes(struct file *filp, void *fh, struct v4l2_frmsizeenum *fsize) { - struct iris_inst *inst = iris_get_inst(filp, NULL); + struct iris_inst *inst = iris_get_inst(filp); struct platform_inst_caps *caps; if (fsize->index) @@ -359,7 +359,7 @@ static int iris_querycap(struct file *filp, void *fh, struct v4l2_capability *ca static int iris_g_selection(struct file *filp, void *fh, struct v4l2_selection *s) { - struct iris_inst *inst = iris_get_inst(filp, NULL); + struct iris_inst *inst = iris_get_inst(filp); if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -394,7 +394,7 @@ static int iris_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subs static int iris_dec_cmd(struct file *filp, void *fh, struct v4l2_decoder_cmd *dec) { - struct iris_inst *inst = iris_get_inst(filp, NULL); + struct iris_inst *inst = iris_get_inst(filp); int ret = 0; mutex_lock(&inst->lock); From 32eab51811051c23a1b9dfd6024e0b41b7a64261 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:30:07 +0300 Subject: [PATCH 00525/11391] media: qcom: venus: Pass file pointer to venus_close_common() In preparation for a tree-wide rework automated with coccinelle that will need to access a struct file pointer in the venus_close_common() function, pass it from the callers. There is not functional change yet. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/platform/qcom/venus/core.c | 2 +- drivers/media/platform/qcom/venus/core.h | 2 +- drivers/media/platform/qcom/venus/vdec.c | 2 +- drivers/media/platform/qcom/venus/venc.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index 4c049c694d9c..5e1ace16a490 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -596,7 +596,7 @@ static __maybe_unused int venus_runtime_suspend(struct device *dev) return ret; } -void venus_close_common(struct venus_inst *inst) +void venus_close_common(struct venus_inst *inst, struct file *filp) { /* * Make sure we don't have IRQ/IRQ-thread currently running diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index 3c0c5f9dbe7b..db7b69b91db5 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -573,5 +573,5 @@ is_fw_rev_or_older(struct venus_core *core, u32 vmajor, u32 vminor, u32 vrev) (core)->venus_ver.rev <= vrev); } -void venus_close_common(struct venus_inst *inst); +void venus_close_common(struct venus_inst *inst, struct file *filp); #endif diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index 29b0d6a5303d..d10ca6d89f6d 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -1755,7 +1755,7 @@ static int vdec_close(struct file *file) vdec_pm_get(inst); cancel_work_sync(&inst->delayed_process_work); - venus_close_common(inst); + venus_close_common(inst, file); ida_destroy(&inst->dpb_ids); vdec_pm_put(inst, false); diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index c0a0ccdded80..0838d64ce8fe 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -1537,7 +1537,7 @@ static int venc_close(struct file *file) struct venus_inst *inst = to_inst(file); venc_pm_get(inst); - venus_close_common(inst); + venus_close_common(inst, file); inst->enc_state = VENUS_ENC_STATE_DEINIT; venc_pm_put(inst, false); From 47f4b1acb4d505b1e7e81d8e0ebce774422b8c2e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:30:08 +0300 Subject: [PATCH 00526/11391] media: Set file->private_data in v4l2_fh_add() All the drivers that use v4l2_fh and call v4l2_fh_add() manually store a pointer to the v4l2_fh instance in file->private_data in their video device .open() file operation handler. Move the code to the v4l2_fh_add() function to avoid direct access to file->private_data in drivers. This requires adding a file pointer argument to the function. Changes to drivers have been generated with the following coccinelle semantic patch: @@ expression fh; identifier filp; identifier open; type ret; @@ ret open(..., struct file *filp, ...) { <... - filp->private_data = fh; ... - v4l2_fh_add(fh); + v4l2_fh_add(fh, filp); ...> } @@ expression fh; identifier filp; identifier open; type ret; @@ ret open(..., struct file *filp, ...) { <... - v4l2_fh_add(fh); + v4l2_fh_add(fh, filp); ... - filp->private_data = fh; ...> } Manual changes have been applied to Documentation/ to update the usage patterns, to drivers/media/v4l2-core/v4l2-fh.c to update the v4l2_fh_add() prototype set file->private_data, and to include/media/v4l2-fh.h to update the v4l2_fh_add() function prototype and its documentation. Additionally, white space issues have been fixed manually in drivers/media/platform/nvidia/tegra-vde/v4l2.c, drivers/media/platform/rockchip/rkvdec/rkvdec.c, drivers/media/v4l2-core/v4l2-fh.c and drivers/staging/most/video/video.c. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- Documentation/driver-api/media/v4l2-fh.rst | 42 ++++++++++--------- .../zh_CN/video4linux/v4l2-framework.txt | 5 +-- drivers/media/pci/cx18/cx18-fileops.c | 3 +- drivers/media/pci/ivtv/ivtv-fileops.c | 4 +- drivers/media/pci/saa7164/saa7164-encoder.c | 3 +- drivers/media/pci/saa7164/saa7164-vbi.c | 3 +- .../media/platform/allegro-dvt/allegro-core.c | 3 +- .../media/platform/amlogic/meson-ge2d/ge2d.c | 3 +- drivers/media/platform/amphion/vpu_v4l2.c | 3 +- .../platform/chips-media/coda/coda-common.c | 3 +- .../chips-media/wave5/wave5-vpu-dec.c | 3 +- .../chips-media/wave5/wave5-vpu-enc.c | 3 +- .../platform/imagination/e5010-jpeg-enc.c | 3 +- drivers/media/platform/m2m-deinterlace.c | 3 +- .../platform/mediatek/jpeg/mtk_jpeg_core.c | 3 +- .../media/platform/mediatek/mdp/mtk_mdp_m2m.c | 3 +- .../platform/mediatek/mdp3/mtk-mdp3-m2m.c | 3 +- .../vcodec/decoder/mtk_vcodec_dec_drv.c | 3 +- .../vcodec/encoder/mtk_vcodec_enc_drv.c | 3 +- .../media/platform/nvidia/tegra-vde/v4l2.c | 3 +- drivers/media/platform/nxp/dw100/dw100.c | 3 +- .../media/platform/nxp/imx-jpeg/mxc-jpeg.c | 3 +- drivers/media/platform/nxp/imx-pxp.c | 3 +- .../platform/nxp/imx8-isi/imx8-isi-m2m.c | 3 +- drivers/media/platform/nxp/mx2_emmaprp.c | 3 +- drivers/media/platform/qcom/iris/iris_vidc.c | 3 +- drivers/media/platform/qcom/venus/vdec.c | 3 +- drivers/media/platform/qcom/venus/venc.c | 3 +- drivers/media/platform/renesas/rcar_fdp1.c | 3 +- drivers/media/platform/renesas/rcar_jpu.c | 3 +- .../media/platform/renesas/vsp1/vsp1_video.c | 4 +- drivers/media/platform/rockchip/rga/rga.c | 3 +- .../media/platform/rockchip/rkvdec/rkvdec.c | 3 +- .../platform/samsung/exynos-gsc/gsc-m2m.c | 3 +- .../platform/samsung/exynos4-is/fimc-m2m.c | 3 +- drivers/media/platform/samsung/s5p-g2d/g2d.c | 3 +- .../platform/samsung/s5p-jpeg/jpeg-core.c | 3 +- .../media/platform/samsung/s5p-mfc/s5p_mfc.c | 3 +- .../media/platform/st/sti/bdisp/bdisp-v4l2.c | 3 +- .../media/platform/st/sti/delta/delta-v4l2.c | 3 +- drivers/media/platform/st/sti/hva/hva-v4l2.c | 3 +- drivers/media/platform/st/stm32/dma2d/dma2d.c | 3 +- .../media/platform/sunxi/sun8i-di/sun8i-di.c | 3 +- .../sunxi/sun8i-rotate/sun8i_rotate.c | 3 +- drivers/media/platform/ti/omap3isp/ispvideo.c | 3 +- drivers/media/platform/ti/vpe/vpe.c | 3 +- .../media/platform/verisilicon/hantro_drv.c | 3 +- .../media/test-drivers/vicodec/vicodec-core.c | 3 +- drivers/media/test-drivers/vim2m.c | 3 +- drivers/media/test-drivers/visl/visl-core.c | 3 +- drivers/media/usb/hdpvr/hdpvr-video.c | 3 +- drivers/media/usb/pvrusb2/pvrusb2-v4l2.c | 3 +- drivers/media/usb/uvc/uvc_v4l2.c | 3 +- drivers/media/v4l2-core/v4l2-fh.c | 7 ++-- drivers/media/v4l2-core/v4l2-subdev.c | 3 +- .../staging/media/imx/imx-media-csc-scaler.c | 3 +- drivers/staging/media/meson/vdec/vdec.c | 3 +- drivers/staging/media/sunxi/cedrus/cedrus.c | 3 +- drivers/staging/most/video/video.c | 4 +- drivers/usb/gadget/function/uvc_v4l2.c | 3 +- include/media/v4l2-fh.h | 5 ++- 61 files changed, 89 insertions(+), 144 deletions(-) diff --git a/Documentation/driver-api/media/v4l2-fh.rst b/Documentation/driver-api/media/v4l2-fh.rst index 2c87b74578d9..a7393067f5db 100644 --- a/Documentation/driver-api/media/v4l2-fh.rst +++ b/Documentation/driver-api/media/v4l2-fh.rst @@ -11,25 +11,22 @@ data that is used by the V4L2 framework. since it is also used to implement priority handling (:ref:`VIDIOC_G_PRIORITY`). -The users of :c:type:`v4l2_fh` (in the V4L2 framework, not the driver) know -whether a driver uses :c:type:`v4l2_fh` as its ``file->private_data`` pointer -by testing the ``V4L2_FL_USES_V4L2_FH`` bit in :c:type:`video_device`->flags. -This bit is set whenever :c:func:`v4l2_fh_init` is called. +struct v4l2_fh is allocated in the driver's ``open()`` file operation handler. +It is typically embedded in a larger driver-specific structure. The +:c:type:`v4l2_fh` must be initialized with a call to :c:func:`v4l2_fh_init`, +and added to the video device with :c:func:`v4l2_fh_add`. This associates the +:c:type:`v4l2_fh` with the :c:type:`file` by setting ``file->private_data`` to +point to the :c:type:`v4l2_fh`. -struct v4l2_fh is allocated as a part of the driver's own file handle -structure and ``file->private_data`` is set to it in the driver's ``open()`` -function by the driver. The :c:type:`v4l2_fh` file handle can be retrieved -from the :c:type:`file` using :c:func:`file_to_v4l2_fh`. Drivers must not -access ``file->private_data`` directly. +Similarly, the struct v4l2_fh is freed in the driver's ``release()`` file +operation handler. It must be removed from the video device with +:c:func:`v4l2_fh_del` and cleaned up with :c:func:`v4l2_fh_exit` before being +freed. -In many cases the struct v4l2_fh will be embedded in a larger -structure. In that case you should call: - -#) :c:func:`v4l2_fh_init` and :c:func:`v4l2_fh_add` in ``open()`` -#) :c:func:`v4l2_fh_del` and :c:func:`v4l2_fh_exit` in ``release()`` - -Drivers can extract their own file handle structure by using the container_of -macro. +Drivers must not access ``file->private_data`` directly. They can retrieve the +:c:type:`v4l2_fh` associated with a :c:type:`file` by calling +:c:func:`file_to_v4l2_fh`. Drivers can extract their own file handle structure +by using the container_of macro. Example: @@ -58,8 +55,7 @@ Example: ... - file->private_data = &my_fh->fh; - v4l2_fh_add(&my_fh->fh); + v4l2_fh_add(&my_fh->fh, file); return 0; } @@ -84,7 +80,7 @@ Below is a short description of the :c:type:`v4l2_fh` functions used: :c:type:`v4l2_file_operations`->open() handler. :c:func:`v4l2_fh_add ` -(:c:type:`fh `) +(:c:type:`fh `, struct file \*filp) - Add a :c:type:`v4l2_fh` to :c:type:`video_device` file handle list. Must be called once the file handle is completely initialized. @@ -138,6 +134,12 @@ associated device node: - Same, but it calls v4l2_fh_is_singular with filp->private_data. +.. note:: + The V4L2 framework knows whether a driver uses :c:type:`v4l2_fh` as its + ``file->private_data`` pointer by testing the ``V4L2_FL_USES_V4L2_FH`` + bit in :c:type:`video_device`->flags. This bit is set whenever + :c:func:`v4l2_fh_init` is called. + V4L2 fh functions and data structures ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/Documentation/translations/zh_CN/video4linux/v4l2-framework.txt b/Documentation/translations/zh_CN/video4linux/v4l2-framework.txt index a9eb62fa1531..2d38ae17d940 100644 --- a/Documentation/translations/zh_CN/video4linux/v4l2-framework.txt +++ b/Documentation/translations/zh_CN/video4linux/v4l2-framework.txt @@ -812,8 +812,7 @@ int my_open(struct file *file) ... - file->private_data = &my_fh->fh; - v4l2_fh_add(&my_fh->fh); + v4l2_fh_add(&my_fh->fh, file); return 0; } @@ -836,7 +835,7 @@ void v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev) 初始化文件句柄。这*必须*在驱动的 v4l2_file_operations->open() 函数中执行。 -void v4l2_fh_add(struct v4l2_fh *fh) +void v4l2_fh_add(struct v4l2_fh *fh, struct file *filp) 添加一个 v4l2_fh 到 video_device 文件句柄列表。一旦文件句柄 初始化完成就必须调用。 diff --git a/drivers/media/pci/cx18/cx18-fileops.c b/drivers/media/pci/cx18/cx18-fileops.c index 89e38b303630..f90b547f5d67 100644 --- a/drivers/media/pci/cx18/cx18-fileops.c +++ b/drivers/media/pci/cx18/cx18-fileops.c @@ -743,8 +743,7 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp) item->type = s->type; item->open_id = cx->open_id++; - filp->private_data = &item->fh; - v4l2_fh_add(&item->fh); + v4l2_fh_add(&item->fh, filp); if (item->type == CX18_ENC_STREAM_TYPE_RAD && v4l2_fh_is_singular_file(filp)) { diff --git a/drivers/media/pci/ivtv/ivtv-fileops.c b/drivers/media/pci/ivtv/ivtv-fileops.c index 67964a3c382c..aa5f5f16427c 100644 --- a/drivers/media/pci/ivtv/ivtv-fileops.c +++ b/drivers/media/pci/ivtv/ivtv-fileops.c @@ -998,9 +998,7 @@ static int ivtv_open(struct file *filp) v4l2_fh_init(&item->fh, &s->vdev); item->itv = itv; item->type = s->type; - - filp->private_data = &item->fh; - v4l2_fh_add(&item->fh); + v4l2_fh_add(&item->fh, filp); if (item->type == IVTV_ENC_STREAM_TYPE_RAD && v4l2_fh_is_singular_file(filp)) { diff --git a/drivers/media/pci/saa7164/saa7164-encoder.c b/drivers/media/pci/saa7164/saa7164-encoder.c index 296f50b6b8d3..e6e353a251cf 100644 --- a/drivers/media/pci/saa7164/saa7164-encoder.c +++ b/drivers/media/pci/saa7164/saa7164-encoder.c @@ -725,8 +725,7 @@ static int fops_open(struct file *file) fh->port = port; v4l2_fh_init(&fh->fh, video_devdata(file)); - v4l2_fh_add(&fh->fh); - file->private_data = &fh->fh; + v4l2_fh_add(&fh->fh, file); return 0; } diff --git a/drivers/media/pci/saa7164/saa7164-vbi.c b/drivers/media/pci/saa7164/saa7164-vbi.c index a7e398f30472..181442fcb43b 100644 --- a/drivers/media/pci/saa7164/saa7164-vbi.c +++ b/drivers/media/pci/saa7164/saa7164-vbi.c @@ -428,8 +428,7 @@ static int fops_open(struct file *file) fh->port = port; v4l2_fh_init(&fh->fh, video_devdata(file)); - v4l2_fh_add(&fh->fh); - file->private_data = &fh->fh; + v4l2_fh_add(&fh->fh, file); return 0; } diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/allegro-core.c index 74977f3ae484..8c30f3cd4fc5 100644 --- a/drivers/media/platform/allegro-dvt/allegro-core.c +++ b/drivers/media/platform/allegro-dvt/allegro-core.c @@ -3219,8 +3219,7 @@ static int allegro_open(struct file *file) } list_add(&channel->list, &dev->channels); - file->private_data = &channel->fh; - v4l2_fh_add(&channel->fh); + v4l2_fh_add(&channel->fh, file); allegro_channel_adjust(channel); diff --git a/drivers/media/platform/amlogic/meson-ge2d/ge2d.c b/drivers/media/platform/amlogic/meson-ge2d/ge2d.c index c7df29a2d820..d36891b546bc 100644 --- a/drivers/media/platform/amlogic/meson-ge2d/ge2d.c +++ b/drivers/media/platform/amlogic/meson-ge2d/ge2d.c @@ -860,8 +860,7 @@ static int ge2d_open(struct file *file) return ret; } v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); ge2d_setup_ctrls(ctx); diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c index 57ca6262bb04..e13bfe09af1b 100644 --- a/drivers/media/platform/amphion/vpu_v4l2.c +++ b/drivers/media/platform/amphion/vpu_v4l2.c @@ -760,7 +760,7 @@ int vpu_v4l2_open(struct file *file, struct vpu_inst *inst) inst->min_buffer_cap = 2; inst->min_buffer_out = 2; v4l2_fh_init(&inst->fh, func->vfd); - v4l2_fh_add(&inst->fh); + v4l2_fh_add(&inst->fh, file); ret = call_vop(inst, ctrl_init); if (ret) @@ -774,7 +774,6 @@ int vpu_v4l2_open(struct file *file, struct vpu_inst *inst) } inst->fh.ctrl_handler = &inst->ctrl_handler; - file->private_data = &inst->fh; inst->state = VPU_CODEC_STATE_DEINIT; inst->workqueue = alloc_ordered_workqueue("vpu_inst", WQ_MEM_RECLAIM); if (inst->workqueue) { diff --git a/drivers/media/platform/chips-media/coda/coda-common.c b/drivers/media/platform/chips-media/coda/coda-common.c index 459b59149390..7d874fd502b8 100644 --- a/drivers/media/platform/chips-media/coda/coda-common.c +++ b/drivers/media/platform/chips-media/coda/coda-common.c @@ -2642,8 +2642,7 @@ static int coda_open(struct file *file) if (ctx->ops->seq_end_work) INIT_WORK(&ctx->seq_end_work, ctx->ops->seq_end_work); v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); ctx->dev = dev; ctx->idx = idx; diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c index f3188d720ed3..88eb933a5144 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c @@ -1761,8 +1761,7 @@ static int wave5_vpu_open_dec(struct file *filp) return -ENOMEM; v4l2_fh_init(&inst->v4l2_fh, vdev); - filp->private_data = &inst->v4l2_fh; - v4l2_fh_add(&inst->v4l2_fh); + v4l2_fh_add(&inst->v4l2_fh, filp); INIT_LIST_HEAD(&inst->list); diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c index b69a1206fa12..322c1498758a 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c @@ -1587,8 +1587,7 @@ static int wave5_vpu_open_enc(struct file *filp) return -ENOMEM; v4l2_fh_init(&inst->v4l2_fh, vdev); - filp->private_data = &inst->v4l2_fh; - v4l2_fh_add(&inst->v4l2_fh); + v4l2_fh_add(&inst->v4l2_fh, filp); INIT_LIST_HEAD(&inst->list); diff --git a/drivers/media/platform/imagination/e5010-jpeg-enc.c b/drivers/media/platform/imagination/e5010-jpeg-enc.c index 295461325862..1da00ff4b1e3 100644 --- a/drivers/media/platform/imagination/e5010-jpeg-enc.c +++ b/drivers/media/platform/imagination/e5010-jpeg-enc.c @@ -742,8 +742,7 @@ static int e5010_open(struct file *file) } v4l2_fh_init(&ctx->fh, vdev); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); ctx->e5010 = e5010; ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(e5010->m2m_dev, ctx, queue_init); diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c index 1812c07837ad..a343dffd19f0 100644 --- a/drivers/media/platform/m2m-deinterlace.c +++ b/drivers/media/platform/m2m-deinterlace.c @@ -847,7 +847,6 @@ static int deinterlace_open(struct file *file) return -ENOMEM; v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; ctx->dev = pcdev; ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init); @@ -866,7 +865,7 @@ static int deinterlace_open(struct file *file) } ctx->colorspace = V4L2_COLORSPACE_REC709; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->fh.m2m_ctx); diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c index 3a7a6eb53d89..5178a1b170fe 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c @@ -1176,8 +1176,7 @@ static int mtk_jpeg_open(struct file *file) INIT_LIST_HEAD(&ctx->dst_done_queue); spin_lock_init(&ctx->done_queue_lock); v4l2_fh_init(&ctx->fh, vfd); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); ctx->jpeg = jpeg; ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, diff --git a/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c b/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c index 2d894b5bfaa7..7a1a8e51dbca 100644 --- a/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c +++ b/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c @@ -1070,14 +1070,13 @@ static int mtk_mdp_m2m_open(struct file *file) mutex_init(&ctx->slock); ctx->id = mdp->id_counter++; v4l2_fh_init(&ctx->fh, vfd); - file->private_data = &ctx->fh; ret = mtk_mdp_ctrls_create(ctx); if (ret) goto error_ctrls; /* Use separate control handler per file handle */ ctx->fh.ctrl_handler = &ctx->ctrl_handler; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); INIT_LIST_HEAD(&ctx->list); ctx->mdp_dev = mdp; diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c index 886ff25c70eb..847d6b310e74 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c @@ -590,14 +590,13 @@ static int mdp_m2m_open(struct file *file) ctx->mdp_dev = mdp; v4l2_fh_init(&ctx->fh, vdev); - file->private_data = &ctx->fh; ret = mdp_m2m_ctrls_create(ctx); if (ret) goto err_exit_fh; /* Use separate control handler per file handle */ ctx->fh.ctrl_handler = &ctx->ctrl_handler; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); mutex_init(&ctx->ctx_lock); ctx->m2m_ctx = v4l2_m2m_ctx_init(mdp->m2m_dev, ctx, mdp_m2m_queue_init); diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c index 18801883c31a..952a77c383bd 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c @@ -206,8 +206,7 @@ static int fops_vcodec_open(struct file *file) mutex_lock(&dev->dev_mutex); ctx->id = dev->id_counter++; v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); INIT_LIST_HEAD(&ctx->list); ctx->dev = dev; if (ctx->dev->vdec_pdata->is_subdev_supported) { diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c index e26a6c3ffa0c..9cacb6cbcf28 100644 --- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c +++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c @@ -129,8 +129,7 @@ static int fops_vcodec_open(struct file *file) */ ctx->id = dev->id_counter++; v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); INIT_LIST_HEAD(&ctx->list); ctx->dev = dev; init_waitqueue_head(&ctx->queue[0]); diff --git a/drivers/media/platform/nvidia/tegra-vde/v4l2.c b/drivers/media/platform/nvidia/tegra-vde/v4l2.c index 393dc3f07d5c..688b776b3010 100644 --- a/drivers/media/platform/nvidia/tegra-vde/v4l2.c +++ b/drivers/media/platform/nvidia/tegra-vde/v4l2.c @@ -832,8 +832,7 @@ static int tegra_open(struct file *file) goto free_ctrls; } - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); tegra_reset_coded_fmt(ctx); tegra_try_coded_fmt(file, &ctx->fh, &ctx->coded_fmt); diff --git a/drivers/media/platform/nxp/dw100/dw100.c b/drivers/media/platform/nxp/dw100/dw100.c index 2460f09a6813..2bd30910ddf9 100644 --- a/drivers/media/platform/nxp/dw100/dw100.c +++ b/drivers/media/platform/nxp/dw100/dw100.c @@ -607,7 +607,6 @@ static int dw100_open(struct file *file) mutex_init(&ctx->vq_mutex); v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; ctx->dw_dev = dw_dev; ctx->q_data[DW100_QUEUE_SRC].fmt = &formats[0]; @@ -651,7 +650,7 @@ static int dw100_open(struct file *file) goto err; } - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); return 0; diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c index 8eef7ebd0428..d7cecc56a9eb 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c @@ -2205,8 +2205,7 @@ static int mxc_jpeg_open(struct file *file) } v4l2_fh_init(&ctx->fh, mxc_vfd); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); ctx->mxc_jpeg = mxc_jpeg; diff --git a/drivers/media/platform/nxp/imx-pxp.c b/drivers/media/platform/nxp/imx-pxp.c index 879b1803a2b3..9602409f3ece 100644 --- a/drivers/media/platform/nxp/imx-pxp.c +++ b/drivers/media/platform/nxp/imx-pxp.c @@ -1660,7 +1660,6 @@ static int pxp_open(struct file *file) } v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; ctx->dev = dev; hdl = &ctx->hdl; v4l2_ctrl_handler_init(hdl, 4); @@ -1699,7 +1698,7 @@ static int pxp_open(struct file *file) goto open_unlock; } - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); atomic_inc(&dev->num_inst); dprintk(dev, "Created instance: %p, m2m_ctx: %p\n", diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c index 6444392c5e62..d6df6e2725f5 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c @@ -673,7 +673,6 @@ static int mxc_isi_m2m_open(struct file *file) mutex_init(&ctx->vb2_lock); v4l2_fh_init(&ctx->fh, vdev); - file->private_data = &ctx->fh; ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(m2m->m2m_dev, ctx, &mxc_isi_m2m_queue_init); @@ -694,7 +693,7 @@ static int mxc_isi_m2m_open(struct file *file) if (ret) goto err_ctrls; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); return 0; diff --git a/drivers/media/platform/nxp/mx2_emmaprp.c b/drivers/media/platform/nxp/mx2_emmaprp.c index 5c8c6285ec1e..8c8f834e6250 100644 --- a/drivers/media/platform/nxp/mx2_emmaprp.c +++ b/drivers/media/platform/nxp/mx2_emmaprp.c @@ -730,7 +730,6 @@ static int emmaprp_open(struct file *file) return -ENOMEM; v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; ctx->dev = pcdev; if (mutex_lock_interruptible(&pcdev->dev_mutex)) { @@ -752,7 +751,7 @@ static int emmaprp_open(struct file *file) clk_prepare_enable(pcdev->clk_emma_ahb); ctx->q_data[V4L2_M2M_SRC].fmt = &formats[1]; ctx->q_data[V4L2_M2M_DST].fmt = &formats[0]; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); mutex_unlock(&pcdev->dev_mutex); dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->fh.m2m_ctx); diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/qcom/iris/iris_vidc.c index 64ebec2ca6b3..cdd34a3b71ff 100644 --- a/drivers/media/platform/qcom/iris/iris_vidc.c +++ b/drivers/media/platform/qcom/iris/iris_vidc.c @@ -25,8 +25,7 @@ static void iris_v4l2_fh_init(struct iris_inst *inst, struct file *filp) { v4l2_fh_init(&inst->fh, inst->core->vdev_dec); inst->fh.ctrl_handler = &inst->ctrl_handler; - v4l2_fh_add(&inst->fh); - filp->private_data = &inst->fh; + v4l2_fh_add(&inst->fh, filp); } static void iris_v4l2_fh_deinit(struct iris_inst *inst, struct file *filp) diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index d10ca6d89f6d..55c27345b7d8 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -1732,9 +1732,8 @@ static int vdec_open(struct file *file) v4l2_fh_init(&inst->fh, core->vdev_dec); inst->fh.ctrl_handler = &inst->ctrl_handler; - v4l2_fh_add(&inst->fh); + v4l2_fh_add(&inst->fh, file); inst->fh.m2m_ctx = inst->m2m_ctx; - file->private_data = &inst->fh; return 0; diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index 0838d64ce8fe..fba07557a399 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -1515,9 +1515,8 @@ static int venc_open(struct file *file) v4l2_fh_init(&inst->fh, core->vdev_enc); inst->fh.ctrl_handler = &inst->ctrl_handler; - v4l2_fh_add(&inst->fh); + v4l2_fh_add(&inst->fh, file); inst->fh.m2m_ctx = inst->m2m_ctx; - file->private_data = &inst->fh; return 0; diff --git a/drivers/media/platform/renesas/rcar_fdp1.c b/drivers/media/platform/renesas/rcar_fdp1.c index 12a5dcc0ca6c..f1ea303ac038 100644 --- a/drivers/media/platform/renesas/rcar_fdp1.c +++ b/drivers/media/platform/renesas/rcar_fdp1.c @@ -2093,7 +2093,6 @@ static int fdp1_open(struct file *file) } v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; ctx->fdp1 = fdp1; /* Initialise Queues */ @@ -2142,7 +2141,7 @@ static int fdp1_open(struct file *file) if (ret < 0) goto error_pm; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); dprintk(fdp1, "Created instance: %p, m2m_ctx: %p\n", ctx, ctx->fh.m2m_ctx); diff --git a/drivers/media/platform/renesas/rcar_jpu.c b/drivers/media/platform/renesas/rcar_jpu.c index 7d5e9df53dfb..d0d4ee3f8bdc 100644 --- a/drivers/media/platform/renesas/rcar_jpu.c +++ b/drivers/media/platform/renesas/rcar_jpu.c @@ -1231,8 +1231,7 @@ static int jpu_open(struct file *file) v4l2_fh_init(&ctx->fh, vfd); ctx->fh.ctrl_handler = &ctx->ctrl_handler; - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); ctx->jpu = jpu; ctx->encoder = vfd == &jpu->vfd_encoder; diff --git a/drivers/media/platform/renesas/vsp1/vsp1_video.c b/drivers/media/platform/renesas/vsp1/vsp1_video.c index 656fb5e6cb30..b6dc1ee3dc50 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_video.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_video.c @@ -1079,9 +1079,7 @@ static int vsp1_video_open(struct file *file) return -ENOMEM; v4l2_fh_init(vfh, &video->video); - v4l2_fh_add(vfh); - - file->private_data = vfh; + v4l2_fh_add(vfh, file); ret = vsp1_device_get(video->vsp1); if (ret < 0) { diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index 8a6e618d605c..d88817023996 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -395,8 +395,7 @@ static int rga_open(struct file *file) return ret; } v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); rga_setup_ctrls(ctx); diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c index 41ab90cbcc0c..2fbad685e92c 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c @@ -938,8 +938,7 @@ static int rkvdec_open(struct file *filp) if (ret) goto err_cleanup_m2m_ctx; - filp->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, filp); return 0; diff --git a/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c b/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c index 968bb4327b7a..39d84ffd1b05 100644 --- a/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c @@ -625,8 +625,7 @@ static int gsc_m2m_open(struct file *file) /* Use separate control handler per file handle */ ctx->fh.ctrl_handler = &ctx->ctrl_handler; - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); ctx->gsc_dev = gsc; /* Default color format */ diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c b/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c index feedf60dad09..b002b02a899e 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c @@ -634,8 +634,7 @@ static int fimc_m2m_open(struct file *file) /* Use separate control handler per file handle */ ctx->fh.ctrl_handler = &ctx->ctrls.handler; - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); /* Setup the device context for memory-to-memory mode */ ctx->state = FIMC_CTX_M2M; diff --git a/drivers/media/platform/samsung/s5p-g2d/g2d.c b/drivers/media/platform/samsung/s5p-g2d/g2d.c index 44fcedbbc90a..e34cae9c9cf6 100644 --- a/drivers/media/platform/samsung/s5p-g2d/g2d.c +++ b/drivers/media/platform/samsung/s5p-g2d/g2d.c @@ -257,8 +257,7 @@ static int g2d_open(struct file *file) return ret; } v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); g2d_setup_ctrls(ctx); diff --git a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c index a5ecfe03db09..9e35dd939ad7 100644 --- a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c @@ -970,8 +970,7 @@ static int s5p_jpeg_open(struct file *file) v4l2_fh_init(&ctx->fh, vfd); /* Use separate control handler per file handle */ ctx->fh.ctrl_handler = &ctx->ctrl_handler; - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); ctx->jpeg = jpeg; if (vfd == jpeg->vfd_encoder) { diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c index dd9761df59df..74629db05121 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c @@ -801,8 +801,7 @@ static int s5p_mfc_open(struct file *file) } init_waitqueue_head(&ctx->queue); v4l2_fh_init(&ctx->fh, vdev); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); ctx->dev = dev; INIT_LIST_HEAD(&ctx->src_queue); INIT_LIST_HEAD(&ctx->dst_queue); diff --git a/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c index f3844e4e47ca..5e983799e298 100644 --- a/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c +++ b/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c @@ -608,8 +608,7 @@ static int bdisp_open(struct file *file) /* Use separate control handler per file handle */ ctx->fh.ctrl_handler = &ctx->ctrl_handler; - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); /* Default format */ ctx->src = bdisp_dflt_fmt; diff --git a/drivers/media/platform/st/sti/delta/delta-v4l2.c b/drivers/media/platform/st/sti/delta/delta-v4l2.c index a12fdbd8abed..3063a98ed25b 100644 --- a/drivers/media/platform/st/sti/delta/delta-v4l2.c +++ b/drivers/media/platform/st/sti/delta/delta-v4l2.c @@ -1639,8 +1639,7 @@ static int delta_open(struct file *file) ctx->dev = delta; v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); INIT_WORK(&ctx->run_work, delta_run_work); mutex_init(&ctx->lock); diff --git a/drivers/media/platform/st/sti/hva/hva-v4l2.c b/drivers/media/platform/st/sti/hva/hva-v4l2.c index 29142c806cb7..2f9413fa7318 100644 --- a/drivers/media/platform/st/sti/hva/hva-v4l2.c +++ b/drivers/media/platform/st/sti/hva/hva-v4l2.c @@ -1174,8 +1174,7 @@ static int hva_open(struct file *file) INIT_WORK(&ctx->run_work, hva_run_work); v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); ret = hva_ctrls_setup(ctx); if (ret) { diff --git a/drivers/media/platform/st/stm32/dma2d/dma2d.c b/drivers/media/platform/st/stm32/dma2d/dma2d.c index f4c5d73447a7..b2bced06a1e6 100644 --- a/drivers/media/platform/st/stm32/dma2d/dma2d.c +++ b/drivers/media/platform/st/stm32/dma2d/dma2d.c @@ -304,8 +304,7 @@ static int dma2d_open(struct file *file) } v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); dma2d_setup_ctrls(ctx); diff --git a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c index e9c7c99fbc55..7823eb97faf7 100644 --- a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c +++ b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c @@ -730,7 +730,6 @@ static int deinterlace_open(struct file *file) deinterlace_prepare_format(&ctx->dst_fmt); v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; ctx->dev = dev; ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, @@ -740,7 +739,7 @@ static int deinterlace_open(struct file *file) goto err_free; } - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); mutex_unlock(&dev->dev_mutex); diff --git a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c index 9ea65cb7187f..368a858b8c0f 100644 --- a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c +++ b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c @@ -659,7 +659,6 @@ static int rotate_open(struct file *file) rotate_set_cap_format(ctx, &ctx->dst_fmt, ctx->rotate); v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; ctx->dev = dev; ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, @@ -669,7 +668,7 @@ static int rotate_open(struct file *file) goto err_free; } - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); ret = rotate_setup_ctrls(ctx); if (ret) diff --git a/drivers/media/platform/ti/omap3isp/ispvideo.c b/drivers/media/platform/ti/omap3isp/ispvideo.c index b76d40aeca17..d10a2b96c13c 100644 --- a/drivers/media/platform/ti/omap3isp/ispvideo.c +++ b/drivers/media/platform/ti/omap3isp/ispvideo.c @@ -1297,7 +1297,7 @@ static int isp_video_open(struct file *file) return -ENOMEM; v4l2_fh_init(&handle->vfh, &video->video); - v4l2_fh_add(&handle->vfh); + v4l2_fh_add(&handle->vfh, file); /* If this is the first user, initialise the pipeline. */ if (omap3isp_get(video->isp) == NULL) { @@ -1333,7 +1333,6 @@ static int isp_video_open(struct file *file) handle->timeperframe.denominator = 1; handle->video = video; - file->private_data = &handle->vfh; done: if (ret < 0) { diff --git a/drivers/media/platform/ti/vpe/vpe.c b/drivers/media/platform/ti/vpe/vpe.c index 4b9b2bec7377..a47c5d31c475 100644 --- a/drivers/media/platform/ti/vpe/vpe.c +++ b/drivers/media/platform/ti/vpe/vpe.c @@ -2310,7 +2310,6 @@ static int vpe_open(struct file *file) init_adb_hdrs(ctx); v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; hdl = &ctx->hdl; v4l2_ctrl_handler_init(hdl, 1); @@ -2364,7 +2363,7 @@ static int vpe_open(struct file *file) goto exit_fh; } - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); /* * for now, just report the creation of the first instance, we can later diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c index b20b9c7f4131..aadc3d8fb3d1 100644 --- a/drivers/media/platform/verisilicon/hantro_drv.c +++ b/drivers/media/platform/verisilicon/hantro_drv.c @@ -663,8 +663,7 @@ static int hantro_open(struct file *filp) } v4l2_fh_init(&ctx->fh, vdev); - filp->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, filp); hantro_reset_fmts(ctx); diff --git a/drivers/media/test-drivers/vicodec/vicodec-core.c b/drivers/media/test-drivers/vicodec/vicodec-core.c index e27f6761cba1..f20d9d9643f5 100644 --- a/drivers/media/test-drivers/vicodec/vicodec-core.c +++ b/drivers/media/test-drivers/vicodec/vicodec-core.c @@ -1848,7 +1848,6 @@ static int vicodec_open(struct file *file) ctx->is_stateless = true; v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; ctx->dev = dev; hdl = &ctx->hdl; v4l2_ctrl_handler_init(hdl, 5); @@ -1932,7 +1931,7 @@ static int vicodec_open(struct file *file) goto open_unlock; } - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); open_unlock: mutex_unlock(vfd->lock); diff --git a/drivers/media/test-drivers/vim2m.c b/drivers/media/test-drivers/vim2m.c index 55d885be5bcc..24574025f58f 100644 --- a/drivers/media/test-drivers/vim2m.c +++ b/drivers/media/test-drivers/vim2m.c @@ -1389,7 +1389,6 @@ static int vim2m_open(struct file *file) } v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; ctx->dev = dev; hdl = &ctx->hdl; v4l2_ctrl_handler_init(hdl, 4); @@ -1433,7 +1432,7 @@ static int vim2m_open(struct file *file) goto open_unlock; } - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); atomic_inc(&dev->num_inst); dprintk(dev, 1, "Created instance: %p, m2m_ctx: %p\n", diff --git a/drivers/media/test-drivers/visl/visl-core.c b/drivers/media/test-drivers/visl/visl-core.c index 5bf3136b36eb..0f43ec23f40b 100644 --- a/drivers/media/test-drivers/visl/visl-core.c +++ b/drivers/media/test-drivers/visl/visl-core.c @@ -341,7 +341,6 @@ static int visl_open(struct file *file) ctx->tpg_str_buf = kzalloc(TPG_STR_BUF_SZ, GFP_KERNEL); v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; ctx->dev = dev; rc = visl_init_ctrls(ctx); @@ -361,7 +360,7 @@ static int visl_open(struct file *file) if (rc) goto free_m2m_ctx; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); dprintk(dev, "Created instance: %p, m2m_ctx: %p\n", ctx, ctx->fh.m2m_ctx); diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index ea17f1a5f5b0..6c6e467f8554 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -380,8 +380,7 @@ static int hdpvr_open(struct file *file) return -ENOMEM; fh->legacy_mode = true; v4l2_fh_init(&fh->fh, video_devdata(file)); - v4l2_fh_add(&fh->fh); - file->private_data = &fh->fh; + v4l2_fh_add(&fh->fh, file); return 0; } diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index 481b03bbecf8..04c77af0c51e 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -1003,10 +1003,9 @@ static int pvr2_v4l2_open(struct file *file) } fhp->file = file; - file->private_data = &fhp->fh; fhp->fw_mode_flag = pvr2_hdw_cpufw_get_enabled(hdw); - v4l2_fh_add(&fhp->fh); + v4l2_fh_add(&fhp->fh, file); return 0; } diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 6dd329a972fd..09677ed639ae 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -600,10 +600,9 @@ static int uvc_v4l2_open(struct file *file) return -ENOMEM; v4l2_fh_init(&handle->vfh, &stream->vdev); - v4l2_fh_add(&handle->vfh); + v4l2_fh_add(&handle->vfh, file); handle->chain = stream->chain; handle->stream = stream; - file->private_data = &handle->vfh; return 0; } diff --git a/drivers/media/v4l2-core/v4l2-fh.c b/drivers/media/v4l2-core/v4l2-fh.c index 7a5f7aa5e253..b59b1084d8cd 100644 --- a/drivers/media/v4l2-core/v4l2-fh.c +++ b/drivers/media/v4l2-core/v4l2-fh.c @@ -41,10 +41,12 @@ void v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev) } EXPORT_SYMBOL_GPL(v4l2_fh_init); -void v4l2_fh_add(struct v4l2_fh *fh) +void v4l2_fh_add(struct v4l2_fh *fh, struct file *filp) { unsigned long flags; + filp->private_data = fh; + v4l2_prio_open(fh->vdev->prio, &fh->prio); spin_lock_irqsave(&fh->vdev->fh_lock, flags); list_add(&fh->list, &fh->vdev->fh_list); @@ -57,11 +59,10 @@ int v4l2_fh_open(struct file *filp) struct video_device *vdev = video_devdata(filp); struct v4l2_fh *fh = kzalloc(sizeof(*fh), GFP_KERNEL); - filp->private_data = fh; if (fh == NULL) return -ENOMEM; v4l2_fh_init(fh, vdev); - v4l2_fh_add(fh); + v4l2_fh_add(fh, filp); return 0; } EXPORT_SYMBOL_GPL(v4l2_fh_open); diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 29d3b788b288..bf35ac436249 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -86,8 +86,7 @@ static int subdev_open(struct file *file) } v4l2_fh_init(&subdev_fh->vfh, vdev); - v4l2_fh_add(&subdev_fh->vfh); - file->private_data = &subdev_fh->vfh; + v4l2_fh_add(&subdev_fh->vfh, file); if (sd->v4l2_dev->mdev && sd->entity.graph_obj.mdev->dev) { struct module *owner; diff --git a/drivers/staging/media/imx/imx-media-csc-scaler.c b/drivers/staging/media/imx/imx-media-csc-scaler.c index fb67b383436d..7fedb33dda34 100644 --- a/drivers/staging/media/imx/imx-media-csc-scaler.c +++ b/drivers/staging/media/imx/imx-media-csc-scaler.c @@ -765,8 +765,7 @@ static int ipu_csc_scaler_open(struct file *file) ctx->rot_mode = IPU_ROTATE_NONE; v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); ctx->priv = priv; ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(priv->m2m_dev, ctx, diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c index f1ee53f9f298..b92666ff50a1 100644 --- a/drivers/staging/media/meson/vdec/vdec.c +++ b/drivers/staging/media/meson/vdec/vdec.c @@ -908,9 +908,8 @@ static int vdec_open(struct file *file) v4l2_fh_init(&sess->fh, core->vdev_dec); sess->fh.ctrl_handler = &sess->ctrl_handler; - v4l2_fh_add(&sess->fh); + v4l2_fh_add(&sess->fh, file); sess->fh.m2m_ctx = sess->m2m_ctx; - file->private_data = &sess->fh; return 0; diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index 80b43187f6ee..ebefd646dbdb 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -366,7 +366,6 @@ static int cedrus_open(struct file *file) } v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; ctx->dev = dev; ctx->bit_depth = 8; @@ -383,7 +382,7 @@ static int cedrus_open(struct file *file) if (ret) goto err_m2m_release; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); mutex_unlock(&dev->dev_mutex); diff --git a/drivers/staging/most/video/video.c b/drivers/staging/most/video/video.c index 116331cead2a..24a68e3e5419 100644 --- a/drivers/staging/most/video/video.c +++ b/drivers/staging/most/video/video.c @@ -96,9 +96,7 @@ static int comp_vdev_open(struct file *filp) fh->mdev = mdev; v4l2_fh_init(&fh->fh, vdev); - filp->private_data = &fh->fh; - - v4l2_fh_add(&fh->fh); + v4l2_fh_add(&fh->fh, filp); ret = most_start_channel(mdev->iface, mdev->ch_idx, &comp); if (ret) { diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c index 886300a29b90..680f25d17dc2 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -672,10 +672,9 @@ uvc_v4l2_open(struct file *file) return -ENOMEM; v4l2_fh_init(&handle->vfh, vdev); - v4l2_fh_add(&handle->vfh); + v4l2_fh_add(&handle->vfh, file); handle->device = &uvc->video; - file->private_data = &handle->vfh; return 0; } diff --git a/include/media/v4l2-fh.h b/include/media/v4l2-fh.h index 14e7136e693f..d8fcf49f10e0 100644 --- a/include/media/v4l2-fh.h +++ b/include/media/v4l2-fh.h @@ -87,11 +87,14 @@ void v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev); * v4l2_fh_add - Add the fh to the list of file handles on a video_device. * * @fh: pointer to &struct v4l2_fh + * @filp: pointer to &struct file associated with @fh + * + * The function sets filp->private_data to point to @fh. * * .. note:: * The @fh file handle must be initialised first. */ -void v4l2_fh_add(struct v4l2_fh *fh); +void v4l2_fh_add(struct v4l2_fh *fh, struct file *filp); /** * v4l2_fh_open - Ancillary routine that can be used as the open\(\) op From 277966749f46bc6292c4052b4e66a554f193a78a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:30:09 +0300 Subject: [PATCH 00527/11391] media: Reset file->private_data to NULL in v4l2_fh_del() Multiple drivers that use v4l2_fh and call v4l2_fh_del() manually reset the file->private_data pointer to NULL in their video device .release() file operation handler. Move the code to the v4l2_fh_del() function to avoid direct access to file->private_data in drivers. This requires adding a file pointer argument to the function. Changes to drivers have been generated with the following coccinelle semantic patch: @@ expression fh; identifier filp; identifier release; type ret; @@ ret release(..., struct file *filp, ...) { <... - filp->private_data = NULL; ... - v4l2_fh_del(fh); + v4l2_fh_del(fh, filp); ...> } @@ expression fh; identifier filp; identifier release; type ret; @@ ret release(..., struct file *filp, ...) { <... - v4l2_fh_del(fh); + v4l2_fh_del(fh, filp); ... - filp->private_data = NULL; ...> } @@ expression fh; identifier filp; identifier release; type ret; @@ ret release(..., struct file *filp, ...) { <... - v4l2_fh_del(fh); + v4l2_fh_del(fh, filp); ...> } Manual changes have been applied to Documentation/ to update the usage patterns, to drivers/media/v4l2-core/v4l2-fh.c to update the v4l2_fh_del() prototype and reset file->private_data, and to include/media/v4l2-fh.h to update the v4l2_fh_del() function prototype and its documentation. Additionally, white space issues have been fixed manually in drivers/usb/gadget/function/uvc_v4l2.c Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- Documentation/driver-api/media/v4l2-fh.rst | 4 ++-- .../translations/zh_CN/video4linux/v4l2-framework.txt | 4 ++-- drivers/media/pci/cx18/cx18-fileops.c | 4 ++-- drivers/media/pci/ivtv/ivtv-fileops.c | 4 ++-- drivers/media/pci/saa7164/saa7164-encoder.c | 2 +- drivers/media/pci/saa7164/saa7164-vbi.c | 2 +- drivers/media/platform/allegro-dvt/allegro-core.c | 2 +- drivers/media/platform/amlogic/meson-ge2d/ge2d.c | 2 +- drivers/media/platform/amphion/vpu_v4l2.c | 4 ++-- drivers/media/platform/chips-media/coda/coda-common.c | 4 ++-- drivers/media/platform/chips-media/wave5/wave5-helper.c | 2 +- drivers/media/platform/imagination/e5010-jpeg-enc.c | 4 ++-- drivers/media/platform/m2m-deinterlace.c | 2 +- drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c | 4 ++-- drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c | 4 ++-- drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c | 4 ++-- .../platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c | 4 ++-- .../platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c | 4 ++-- drivers/media/platform/nvidia/tegra-vde/v4l2.c | 2 +- drivers/media/platform/nxp/dw100/dw100.c | 2 +- drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c | 4 ++-- drivers/media/platform/nxp/imx-pxp.c | 2 +- drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c | 2 +- drivers/media/platform/nxp/mx2_emmaprp.c | 2 +- drivers/media/platform/qcom/iris/iris_vidc.c | 3 +-- drivers/media/platform/qcom/venus/core.c | 2 +- drivers/media/platform/renesas/rcar_fdp1.c | 2 +- drivers/media/platform/renesas/rcar_jpu.c | 4 ++-- drivers/media/platform/renesas/vsp1/vsp1_video.c | 2 +- drivers/media/platform/rockchip/rga/rga.c | 2 +- drivers/media/platform/rockchip/rkvdec/rkvdec.c | 2 +- drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c | 4 ++-- drivers/media/platform/samsung/exynos4-is/fimc-m2m.c | 4 ++-- drivers/media/platform/samsung/s5p-g2d/g2d.c | 2 +- drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c | 4 ++-- drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c | 4 ++-- drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c | 4 ++-- drivers/media/platform/st/sti/delta/delta-v4l2.c | 4 ++-- drivers/media/platform/st/sti/hva/hva-v4l2.c | 4 ++-- drivers/media/platform/st/stm32/dma2d/dma2d.c | 2 +- drivers/media/platform/sunxi/sun8i-di/sun8i-di.c | 2 +- drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c | 2 +- drivers/media/platform/ti/omap3isp/ispvideo.c | 5 ++--- drivers/media/platform/ti/vpe/vpe.c | 2 +- drivers/media/platform/verisilicon/hantro_drv.c | 4 ++-- drivers/media/test-drivers/vicodec/vicodec-core.c | 2 +- drivers/media/test-drivers/vim2m.c | 2 +- drivers/media/test-drivers/visl/visl-core.c | 2 +- drivers/media/usb/pvrusb2/pvrusb2-v4l2.c | 3 +-- drivers/media/v4l2-core/v4l2-fh.c | 7 ++++--- drivers/media/v4l2-core/v4l2-subdev.c | 5 ++--- drivers/staging/media/imx/imx-media-csc-scaler.c | 4 ++-- drivers/staging/media/meson/vdec/vdec.c | 2 +- drivers/staging/media/sunxi/cedrus/cedrus.c | 2 +- drivers/staging/most/video/video.c | 4 ++-- drivers/usb/gadget/function/uvc_v4l2.c | 3 +-- include/media/v4l2-fh.h | 5 ++++- 57 files changed, 89 insertions(+), 90 deletions(-) diff --git a/Documentation/driver-api/media/v4l2-fh.rst b/Documentation/driver-api/media/v4l2-fh.rst index a7393067f5db..afcad22ead7c 100644 --- a/Documentation/driver-api/media/v4l2-fh.rst +++ b/Documentation/driver-api/media/v4l2-fh.rst @@ -65,7 +65,7 @@ Example: struct my_fh *my_fh = container_of(fh, struct my_fh, fh); ... - v4l2_fh_del(&my_fh->fh); + v4l2_fh_del(&my_fh->fh, file); v4l2_fh_exit(&my_fh->fh); kfree(my_fh); return 0; @@ -86,7 +86,7 @@ Below is a short description of the :c:type:`v4l2_fh` functions used: Must be called once the file handle is completely initialized. :c:func:`v4l2_fh_del ` -(:c:type:`fh `) +(:c:type:`fh `, struct file \*filp) - Unassociate the file handle from :c:type:`video_device`. The file handle exit function may now be called. diff --git a/Documentation/translations/zh_CN/video4linux/v4l2-framework.txt b/Documentation/translations/zh_CN/video4linux/v4l2-framework.txt index 2d38ae17d940..1653c6e2cb46 100644 --- a/Documentation/translations/zh_CN/video4linux/v4l2-framework.txt +++ b/Documentation/translations/zh_CN/video4linux/v4l2-framework.txt @@ -822,7 +822,7 @@ int my_release(struct file *file) struct my_fh *my_fh = container_of(fh, struct my_fh, fh); ... - v4l2_fh_del(&my_fh->fh); + v4l2_fh_del(&my_fh->fh, file); v4l2_fh_exit(&my_fh->fh); kfree(my_fh); return 0; @@ -840,7 +840,7 @@ void v4l2_fh_add(struct v4l2_fh *fh, struct file *filp) 添加一个 v4l2_fh 到 video_device 文件句柄列表。一旦文件句柄 初始化完成就必须调用。 -void v4l2_fh_del(struct v4l2_fh *fh) +void v4l2_fh_del(struct v4l2_fh *fh, struct file *filp) 从 video_device() 中解除文件句柄的关联。文件句柄的退出函数也 将被调用。 diff --git a/drivers/media/pci/cx18/cx18-fileops.c b/drivers/media/pci/cx18/cx18-fileops.c index f90b547f5d67..d49fa4c4119b 100644 --- a/drivers/media/pci/cx18/cx18-fileops.c +++ b/drivers/media/pci/cx18/cx18-fileops.c @@ -713,7 +713,7 @@ int cx18_v4l2_close(struct file *filp) vb2_queue_release(vdev->queue); vdev->queue->owner = NULL; } - v4l2_fh_del(fh); + v4l2_fh_del(fh, filp); v4l2_fh_exit(fh); /* 'Unclaim' this stream */ @@ -751,7 +751,7 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp) if (atomic_read(&cx->ana_capturing) > 0) { /* switching to radio while capture is in progress is not polite */ - v4l2_fh_del(&item->fh); + v4l2_fh_del(&item->fh, filp); v4l2_fh_exit(&item->fh); kfree(item); return -EBUSY; diff --git a/drivers/media/pci/ivtv/ivtv-fileops.c b/drivers/media/pci/ivtv/ivtv-fileops.c index aa5f5f16427c..0040a5e7f654 100644 --- a/drivers/media/pci/ivtv/ivtv-fileops.c +++ b/drivers/media/pci/ivtv/ivtv-fileops.c @@ -911,7 +911,7 @@ int ivtv_v4l2_close(struct file *filp) ivtv_unmute(itv); } - v4l2_fh_del(fh); + v4l2_fh_del(fh, filp); v4l2_fh_exit(fh); /* Easy case first: this stream was never claimed by us */ @@ -1006,7 +1006,7 @@ static int ivtv_open(struct file *filp) if (atomic_read(&itv->capturing) > 0) { /* switching to radio while capture is in progress is not polite */ - v4l2_fh_del(&item->fh); + v4l2_fh_del(&item->fh, filp); v4l2_fh_exit(&item->fh); kfree(item); return -EBUSY; diff --git a/drivers/media/pci/saa7164/saa7164-encoder.c b/drivers/media/pci/saa7164/saa7164-encoder.c index e6e353a251cf..66d650b5f69a 100644 --- a/drivers/media/pci/saa7164/saa7164-encoder.c +++ b/drivers/media/pci/saa7164/saa7164-encoder.c @@ -746,7 +746,7 @@ static int fops_release(struct file *file) } } - v4l2_fh_del(&fh->fh); + v4l2_fh_del(&fh->fh, file); v4l2_fh_exit(&fh->fh); kfree(fh); diff --git a/drivers/media/pci/saa7164/saa7164-vbi.c b/drivers/media/pci/saa7164/saa7164-vbi.c index 181442fcb43b..57e4362c0d19 100644 --- a/drivers/media/pci/saa7164/saa7164-vbi.c +++ b/drivers/media/pci/saa7164/saa7164-vbi.c @@ -449,7 +449,7 @@ static int fops_release(struct file *file) } } - v4l2_fh_del(&fh->fh); + v4l2_fh_del(&fh->fh, file); v4l2_fh_exit(&fh->fh); kfree(fh); diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/allegro-core.c index 8c30f3cd4fc5..5e3b1f5d7206 100644 --- a/drivers/media/platform/allegro-dvt/allegro-core.c +++ b/drivers/media/platform/allegro-dvt/allegro-core.c @@ -3241,7 +3241,7 @@ static int allegro_release(struct file *file) v4l2_ctrl_handler_free(&channel->ctrl_handler); - v4l2_fh_del(&channel->fh); + v4l2_fh_del(&channel->fh, file); v4l2_fh_exit(&channel->fh); kfree(channel); diff --git a/drivers/media/platform/amlogic/meson-ge2d/ge2d.c b/drivers/media/platform/amlogic/meson-ge2d/ge2d.c index d36891b546bc..b1b0b6535fb1 100644 --- a/drivers/media/platform/amlogic/meson-ge2d/ge2d.c +++ b/drivers/media/platform/amlogic/meson-ge2d/ge2d.c @@ -883,7 +883,7 @@ static int ge2d_release(struct file *file) v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); v4l2_ctrl_handler_free(&ctx->ctrl_handler); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c index e13bfe09af1b..fcb2eff813ac 100644 --- a/drivers/media/platform/amphion/vpu_v4l2.c +++ b/drivers/media/platform/amphion/vpu_v4l2.c @@ -791,7 +791,7 @@ int vpu_v4l2_open(struct file *file, struct vpu_inst *inst) return 0; error: - v4l2_fh_del(&inst->fh); + v4l2_fh_del(&inst->fh, file); v4l2_fh_exit(&inst->fh); vpu_inst_put(inst); return ret; @@ -812,7 +812,7 @@ int vpu_v4l2_close(struct file *file) call_void_vop(inst, release); vpu_inst_unlock(inst); - v4l2_fh_del(&inst->fh); + v4l2_fh_del(&inst->fh, file); v4l2_fh_exit(&inst->fh); vpu_inst_unregister(inst); diff --git a/drivers/media/platform/chips-media/coda/coda-common.c b/drivers/media/platform/chips-media/coda/coda-common.c index 7d874fd502b8..583759eed610 100644 --- a/drivers/media/platform/chips-media/coda/coda-common.c +++ b/drivers/media/platform/chips-media/coda/coda-common.c @@ -2725,7 +2725,7 @@ static int coda_open(struct file *file) err_clk_enable: pm_runtime_put_sync(dev->dev); err_pm_get: - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); err_coda_name_init: ida_free(&dev->ida, ctx->idx); @@ -2763,7 +2763,7 @@ static int coda_release(struct file *file) clk_disable_unprepare(dev->clk_ahb); clk_disable_unprepare(dev->clk_per); pm_runtime_put_sync(dev->dev); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); ida_free(&dev->ida, ctx->idx); if (ctx->ops->release) diff --git a/drivers/media/platform/chips-media/wave5/wave5-helper.c b/drivers/media/platform/chips-media/wave5/wave5-helper.c index ed8ff04a899d..0bce62f0c039 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-helper.c +++ b/drivers/media/platform/chips-media/wave5/wave5-helper.c @@ -46,7 +46,7 @@ void wave5_cleanup_instance(struct vpu_instance *inst, struct file *filp) wave5_vdi_free_dma_memory(inst->dev, &inst->bitstream_vbuf); v4l2_ctrl_handler_free(&inst->v4l2_ctrl_hdl); if (inst->v4l2_fh.vdev) { - v4l2_fh_del(&inst->v4l2_fh); + v4l2_fh_del(&inst->v4l2_fh, filp); v4l2_fh_exit(&inst->v4l2_fh); } list_del_init(&inst->list); diff --git a/drivers/media/platform/imagination/e5010-jpeg-enc.c b/drivers/media/platform/imagination/e5010-jpeg-enc.c index 1da00ff4b1e3..c4e0097cb8b7 100644 --- a/drivers/media/platform/imagination/e5010-jpeg-enc.c +++ b/drivers/media/platform/imagination/e5010-jpeg-enc.c @@ -769,7 +769,7 @@ static int e5010_open(struct file *file) err_ctrls_setup: v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); exit: - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); mutex_unlock(&e5010->mutex); free: @@ -786,7 +786,7 @@ static int e5010_release(struct file *file) mutex_lock(&e5010->mutex); v4l2_ctrl_handler_free(&ctx->ctrl_handler); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); mutex_unlock(&e5010->mutex); diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c index a343dffd19f0..51c2f206cb1f 100644 --- a/drivers/media/platform/m2m-deinterlace.c +++ b/drivers/media/platform/m2m-deinterlace.c @@ -880,7 +880,7 @@ static int deinterlace_release(struct file *file) dprintk(pcdev, "Releasing instance %p\n", ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); kfree(ctx->xt); diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c index 5178a1b170fe..de15d6f0b490 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c @@ -1201,7 +1201,7 @@ static int mtk_jpeg_open(struct file *file) return 0; error: - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); mutex_unlock(&jpeg->lock); free: @@ -1217,7 +1217,7 @@ static int mtk_jpeg_release(struct file *file) mutex_lock(&jpeg->lock); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); v4l2_ctrl_handler_free(&ctx->ctrl_hdl); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); mutex_unlock(&jpeg->lock); diff --git a/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c b/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c index 7a1a8e51dbca..7e89a8443707 100644 --- a/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c +++ b/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c @@ -1130,7 +1130,7 @@ static int mtk_mdp_m2m_open(struct file *file) error_m2m_ctx: v4l2_ctrl_handler_free(&ctx->ctrl_handler); error_ctrls: - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); mutex_unlock(&mdp->lock); err_lock: @@ -1148,7 +1148,7 @@ static int mtk_mdp_m2m_release(struct file *file) mutex_lock(&mdp->lock); v4l2_m2m_ctx_release(ctx->m2m_ctx); v4l2_ctrl_handler_free(&ctx->ctrl_handler); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); mtk_mdp_vpu_deinit(&ctx->vpu); mdp->ctx_num--; diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c index 847d6b310e74..e68ae19d71a9 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c @@ -633,7 +633,7 @@ static int mdp_m2m_open(struct file *file) v4l2_m2m_ctx_release(ctx->m2m_ctx); err_release_handler: v4l2_ctrl_handler_free(&ctx->ctrl_handler); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); err_exit_fh: v4l2_fh_exit(&ctx->fh); ida_free(&mdp->mdp_ida, ctx->id); @@ -657,7 +657,7 @@ static int mdp_m2m_release(struct file *file) mdp_vpu_put_locked(mdp); v4l2_ctrl_handler_free(&ctx->ctrl_handler); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); ida_free(&mdp->mdp_ida, ctx->id); mutex_unlock(&mdp->m2m_lock); diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c index 952a77c383bd..46d176e6de63 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c @@ -282,7 +282,7 @@ static int fops_vcodec_open(struct file *file) err_m2m_ctx_init: v4l2_ctrl_handler_free(&ctx->ctrl_hdl); err_ctrls_setup: - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); mutex_unlock(&dev->dev_mutex); @@ -307,7 +307,7 @@ static int fops_vcodec_release(struct file *file) v4l2_m2m_ctx_release(ctx->m2m_ctx); mtk_vcodec_dec_release(ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); v4l2_ctrl_handler_free(&ctx->ctrl_hdl); diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c index 9cacb6cbcf28..fb1c3bdc2dae 100644 --- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c +++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c @@ -191,7 +191,7 @@ static int fops_vcodec_open(struct file *file) err_m2m_ctx_init: v4l2_ctrl_handler_free(&ctx->ctrl_hdl); err_ctrls_setup: - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); mutex_unlock(&dev->dev_mutex); @@ -209,7 +209,7 @@ static int fops_vcodec_release(struct file *file) v4l2_m2m_ctx_release(ctx->m2m_ctx); mtk_vcodec_enc_release(ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); v4l2_ctrl_handler_free(&ctx->ctrl_hdl); diff --git a/drivers/media/platform/nvidia/tegra-vde/v4l2.c b/drivers/media/platform/nvidia/tegra-vde/v4l2.c index 688b776b3010..0c50f4ff82e0 100644 --- a/drivers/media/platform/nvidia/tegra-vde/v4l2.c +++ b/drivers/media/platform/nvidia/tegra-vde/v4l2.c @@ -856,7 +856,7 @@ static int tegra_release(struct file *file) struct tegra_ctx *ctx = fh_to_tegra_ctx(fh); struct tegra_vde *vde = ctx->vde; - v4l2_fh_del(fh); + v4l2_fh_del(fh, file); v4l2_m2m_ctx_release(fh->m2m_ctx); v4l2_ctrl_handler_free(&ctx->hdl); v4l2_fh_exit(fh); diff --git a/drivers/media/platform/nxp/dw100/dw100.c b/drivers/media/platform/nxp/dw100/dw100.c index 2bd30910ddf9..97744c7b7c03 100644 --- a/drivers/media/platform/nxp/dw100/dw100.c +++ b/drivers/media/platform/nxp/dw100/dw100.c @@ -667,7 +667,7 @@ static int dw100_release(struct file *file) { struct dw100_ctx *ctx = dw100_file2ctx(file); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); v4l2_ctrl_handler_free(&ctx->hdl); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c index d7cecc56a9eb..a34e644b2cb1 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c @@ -2238,7 +2238,7 @@ static int mxc_jpeg_open(struct file *file) err_ctrls_setup: v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); error: - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); mutex_unlock(&mxc_jpeg->lock); free: @@ -2751,7 +2751,7 @@ static int mxc_jpeg_release(struct file *file) ctx->slot); v4l2_ctrl_handler_free(&ctx->ctrl_handler); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); mutex_unlock(&mxc_jpeg->lock); diff --git a/drivers/media/platform/nxp/imx-pxp.c b/drivers/media/platform/nxp/imx-pxp.c index 9602409f3ece..6cc9b07ea53a 100644 --- a/drivers/media/platform/nxp/imx-pxp.c +++ b/drivers/media/platform/nxp/imx-pxp.c @@ -1716,7 +1716,7 @@ static int pxp_release(struct file *file) dprintk(dev, "Releasing instance %p\n", ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); v4l2_ctrl_handler_free(&ctx->hdl); mutex_lock(&dev->dev_mutex); diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c index d6df6e2725f5..31298307c672 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c @@ -716,7 +716,7 @@ static int mxc_isi_m2m_release(struct file *file) v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); mxc_isi_m2m_ctx_ctrls_delete(ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); mutex_destroy(&ctx->vb2_lock); diff --git a/drivers/media/platform/nxp/mx2_emmaprp.c b/drivers/media/platform/nxp/mx2_emmaprp.c index 8c8f834e6250..d23da93304bd 100644 --- a/drivers/media/platform/nxp/mx2_emmaprp.c +++ b/drivers/media/platform/nxp/mx2_emmaprp.c @@ -769,7 +769,7 @@ static int emmaprp_release(struct file *file) mutex_lock(&pcdev->dev_mutex); clk_disable_unprepare(pcdev->clk_emma_ahb); clk_disable_unprepare(pcdev->clk_emma_ipg); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); mutex_unlock(&pcdev->dev_mutex); diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/qcom/iris/iris_vidc.c index cdd34a3b71ff..541ae86f7892 100644 --- a/drivers/media/platform/qcom/iris/iris_vidc.c +++ b/drivers/media/platform/qcom/iris/iris_vidc.c @@ -30,8 +30,7 @@ static void iris_v4l2_fh_init(struct iris_inst *inst, struct file *filp) static void iris_v4l2_fh_deinit(struct iris_inst *inst, struct file *filp) { - filp->private_data = NULL; - v4l2_fh_del(&inst->fh); + v4l2_fh_del(&inst->fh, filp); inst->fh.ctrl_handler = NULL; v4l2_fh_exit(&inst->fh); } diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index 5e1ace16a490..90de29f166ad 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -607,7 +607,7 @@ void venus_close_common(struct venus_inst *inst, struct file *filp) v4l2_m2m_ctx_release(inst->m2m_ctx); v4l2_m2m_release(inst->m2m_dev); hfi_session_destroy(inst); - v4l2_fh_del(&inst->fh); + v4l2_fh_del(&inst->fh, filp); v4l2_fh_exit(&inst->fh); v4l2_ctrl_handler_free(&inst->ctrl_handler); diff --git a/drivers/media/platform/renesas/rcar_fdp1.c b/drivers/media/platform/renesas/rcar_fdp1.c index f1ea303ac038..e2dba0e4f315 100644 --- a/drivers/media/platform/renesas/rcar_fdp1.c +++ b/drivers/media/platform/renesas/rcar_fdp1.c @@ -2166,7 +2166,7 @@ static int fdp1_release(struct file *file) dprintk(fdp1, "Releasing instance %p\n", ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); v4l2_ctrl_handler_free(&ctx->hdl); mutex_lock(&fdp1->dev_mutex); diff --git a/drivers/media/platform/renesas/rcar_jpu.c b/drivers/media/platform/renesas/rcar_jpu.c index d0d4ee3f8bdc..0b479dfa2917 100644 --- a/drivers/media/platform/renesas/rcar_jpu.c +++ b/drivers/media/platform/renesas/rcar_jpu.c @@ -1276,7 +1276,7 @@ static int jpu_open(struct file *file) device_prepare_rollback: mutex_unlock(&jpu->mutex); v4l_prepare_rollback: - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); return ret; @@ -1289,7 +1289,7 @@ static int jpu_release(struct file *file) v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); v4l2_ctrl_handler_free(&ctx->ctrl_handler); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); diff --git a/drivers/media/platform/renesas/vsp1/vsp1_video.c b/drivers/media/platform/renesas/vsp1/vsp1_video.c index b6dc1ee3dc50..75f9a1a85d55 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_video.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_video.c @@ -1083,7 +1083,7 @@ static int vsp1_video_open(struct file *file) ret = vsp1_device_get(video->vsp1); if (ret < 0) { - v4l2_fh_del(vfh); + v4l2_fh_del(vfh, file); v4l2_fh_exit(vfh); kfree(vfh); } diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index d88817023996..45c42c7ad846 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -418,7 +418,7 @@ static int rga_release(struct file *file) v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); v4l2_ctrl_handler_free(&ctx->ctrl_handler); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c index 2fbad685e92c..481c2488f9ac 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c @@ -954,7 +954,7 @@ static int rkvdec_release(struct file *filp) { struct rkvdec_ctx *ctx = file_to_rkvdec_ctx(filp); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, filp); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); v4l2_ctrl_handler_free(&ctx->ctrl_hdl); v4l2_fh_exit(&ctx->fh); diff --git a/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c b/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c index 39d84ffd1b05..2999fb2610f0 100644 --- a/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c @@ -654,7 +654,7 @@ static int gsc_m2m_open(struct file *file) error_ctrls: gsc_ctrls_delete(ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); error_fh: v4l2_fh_exit(&ctx->fh); kfree(ctx); @@ -675,7 +675,7 @@ static int gsc_m2m_release(struct file *file) v4l2_m2m_ctx_release(ctx->m2m_ctx); gsc_ctrls_delete(ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); if (--gsc->m2m.refcnt <= 0) diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c b/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c index b002b02a899e..609fd84f89d4 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c @@ -663,7 +663,7 @@ static int fimc_m2m_open(struct file *file) v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); error_c: fimc_ctrls_delete(ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); error_fh: v4l2_fh_exit(&ctx->fh); kfree(ctx); @@ -684,7 +684,7 @@ static int fimc_m2m_release(struct file *file) v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); fimc_ctrls_delete(ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); if (--fimc->m2m.refcnt <= 0) diff --git a/drivers/media/platform/samsung/s5p-g2d/g2d.c b/drivers/media/platform/samsung/s5p-g2d/g2d.c index e34cae9c9cf6..922262f61e7b 100644 --- a/drivers/media/platform/samsung/s5p-g2d/g2d.c +++ b/drivers/media/platform/samsung/s5p-g2d/g2d.c @@ -280,7 +280,7 @@ static int g2d_release(struct file *file) v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); mutex_unlock(&dev->mutex); v4l2_ctrl_handler_free(&ctx->ctrl_handler); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); v4l2_info(&dev->v4l2_dev, "instance closed\n"); diff --git a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c index 9e35dd939ad7..65f256db4c76 100644 --- a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c @@ -1005,7 +1005,7 @@ static int s5p_jpeg_open(struct file *file) return 0; error: - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); mutex_unlock(&jpeg->lock); free: @@ -1021,7 +1021,7 @@ static int s5p_jpeg_release(struct file *file) mutex_lock(&jpeg->lock); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); v4l2_ctrl_handler_free(&ctx->ctrl_handler); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); mutex_unlock(&jpeg->lock); diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c index 74629db05121..a5e756049620 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c @@ -955,7 +955,7 @@ static int s5p_mfc_open(struct file *file) err_bad_node: dev->ctx[ctx->num] = NULL; err_no_ctx: - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); err_alloc: @@ -1010,7 +1010,7 @@ static int s5p_mfc_release(struct file *file) if (dev) dev->ctx[ctx->num] = NULL; s5p_mfc_dec_ctrls_delete(ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); /* vdev is gone if dev is null */ if (dev) v4l2_fh_exit(&ctx->fh); diff --git a/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c index 5e983799e298..38b2a2924443 100644 --- a/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c +++ b/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c @@ -634,7 +634,7 @@ static int bdisp_open(struct file *file) error_ctrls: bdisp_ctrls_delete(ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); error_fh: v4l2_fh_exit(&ctx->fh); bdisp_hw_free_nodes(ctx); @@ -659,7 +659,7 @@ static int bdisp_release(struct file *file) bdisp_ctrls_delete(ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); if (--bdisp->m2m.refcnt <= 0) diff --git a/drivers/media/platform/st/sti/delta/delta-v4l2.c b/drivers/media/platform/st/sti/delta/delta-v4l2.c index 3063a98ed25b..385b26d21408 100644 --- a/drivers/media/platform/st/sti/delta/delta-v4l2.c +++ b/drivers/media/platform/st/sti/delta/delta-v4l2.c @@ -1684,7 +1684,7 @@ static int delta_open(struct file *file) return 0; err_fh_del: - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); err: @@ -1712,7 +1712,7 @@ static int delta_release(struct file *file) v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); /* disable ST231 clocks */ diff --git a/drivers/media/platform/st/sti/hva/hva-v4l2.c b/drivers/media/platform/st/sti/hva/hva-v4l2.c index 2f9413fa7318..3581b73a99b8 100644 --- a/drivers/media/platform/st/sti/hva/hva-v4l2.c +++ b/drivers/media/platform/st/sti/hva/hva-v4l2.c @@ -1218,7 +1218,7 @@ static int hva_open(struct file *file) err_ctrls: v4l2_ctrl_handler_free(&ctx->ctrl_handler); err_fh: - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); out: @@ -1249,7 +1249,7 @@ static int hva_release(struct file *file) v4l2_ctrl_handler_free(&ctx->ctrl_handler); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); #ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS diff --git a/drivers/media/platform/st/stm32/dma2d/dma2d.c b/drivers/media/platform/st/stm32/dma2d/dma2d.c index b2bced06a1e6..bc0f81e78018 100644 --- a/drivers/media/platform/st/stm32/dma2d/dma2d.c +++ b/drivers/media/platform/st/stm32/dma2d/dma2d.c @@ -326,7 +326,7 @@ static int dma2d_release(struct file *file) v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); mutex_unlock(&dev->mutex); v4l2_ctrl_handler_free(&ctx->ctrl_handler); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); diff --git a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c index 7823eb97faf7..eb519afb30ca 100644 --- a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c +++ b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c @@ -759,7 +759,7 @@ static int deinterlace_release(struct file *file) mutex_lock(&dev->dev_mutex); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); diff --git a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c index 368a858b8c0f..89992feaab60 100644 --- a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c +++ b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c @@ -695,7 +695,7 @@ static int rotate_release(struct file *file) mutex_lock(&dev->dev_mutex); v4l2_ctrl_handler_free(&ctx->ctrl_handler); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); diff --git a/drivers/media/platform/ti/omap3isp/ispvideo.c b/drivers/media/platform/ti/omap3isp/ispvideo.c index d10a2b96c13c..2c0008444b7e 100644 --- a/drivers/media/platform/ti/omap3isp/ispvideo.c +++ b/drivers/media/platform/ti/omap3isp/ispvideo.c @@ -1336,7 +1336,7 @@ static int isp_video_open(struct file *file) done: if (ret < 0) { - v4l2_fh_del(&handle->vfh); + v4l2_fh_del(&handle->vfh, file); v4l2_fh_exit(&handle->vfh); kfree(handle); } @@ -1360,10 +1360,9 @@ static int isp_video_release(struct file *file) v4l2_pipeline_pm_put(&video->video.entity); /* Release the file handle. */ - v4l2_fh_del(vfh); + v4l2_fh_del(vfh, file); v4l2_fh_exit(vfh); kfree(handle); - file->private_data = NULL; omap3isp_put(video->isp); diff --git a/drivers/media/platform/ti/vpe/vpe.c b/drivers/media/platform/ti/vpe/vpe.c index a47c5d31c475..6029d4e8e0bd 100644 --- a/drivers/media/platform/ti/vpe/vpe.c +++ b/drivers/media/platform/ti/vpe/vpe.c @@ -2421,7 +2421,7 @@ static int vpe_release(struct file *file) vpdma_free_desc_buf(&ctx->sc_coeff_v); vpdma_free_desc_buf(&ctx->sc_coeff_h); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); v4l2_ctrl_handler_free(&ctx->hdl); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c index aadc3d8fb3d1..4cc9d00fd293 100644 --- a/drivers/media/platform/verisilicon/hantro_drv.c +++ b/drivers/media/platform/verisilicon/hantro_drv.c @@ -677,7 +677,7 @@ static int hantro_open(struct file *filp) return 0; err_fh_free: - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, filp); v4l2_fh_exit(&ctx->fh); err_ctx_free: kfree(ctx); @@ -693,7 +693,7 @@ static int hantro_release(struct file *filp) * to this file. */ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, filp); v4l2_fh_exit(&ctx->fh); v4l2_ctrl_handler_free(&ctx->ctrl_handler); kfree(ctx); diff --git a/drivers/media/test-drivers/vicodec/vicodec-core.c b/drivers/media/test-drivers/vicodec/vicodec-core.c index f20d9d9643f5..c340fd226040 100644 --- a/drivers/media/test-drivers/vicodec/vicodec-core.c +++ b/drivers/media/test-drivers/vicodec/vicodec-core.c @@ -1946,7 +1946,7 @@ static int vicodec_release(struct file *file) mutex_lock(vfd->lock); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); mutex_unlock(vfd->lock); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); v4l2_ctrl_handler_free(&ctx->hdl); kvfree(ctx->state.compressed_frame); diff --git a/drivers/media/test-drivers/vim2m.c b/drivers/media/test-drivers/vim2m.c index 24574025f58f..d0e760118c82 100644 --- a/drivers/media/test-drivers/vim2m.c +++ b/drivers/media/test-drivers/vim2m.c @@ -1450,7 +1450,7 @@ static int vim2m_release(struct file *file) dprintk(dev, 1, "Releasing instance %p\n", ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); v4l2_ctrl_handler_free(&ctx->hdl); mutex_lock(&dev->dev_mutex); diff --git a/drivers/media/test-drivers/visl/visl-core.c b/drivers/media/test-drivers/visl/visl-core.c index 0f43ec23f40b..26c6c6835f79 100644 --- a/drivers/media/test-drivers/visl/visl-core.c +++ b/drivers/media/test-drivers/visl/visl-core.c @@ -389,7 +389,7 @@ static int visl_release(struct file *file) dprintk(dev, "Releasing instance %p\n", ctx); tpg_free(&ctx->tpg); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); v4l2_ctrl_handler_free(&ctx->hdl); mutex_lock(&dev->dev_mutex); diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index 04c77af0c51e..f9535a484738 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -900,9 +900,8 @@ static int pvr2_v4l2_release(struct file *file) fhp->rhp = NULL; } - v4l2_fh_del(&fhp->fh); + v4l2_fh_del(&fhp->fh, file); v4l2_fh_exit(&fhp->fh); - file->private_data = NULL; pvr2_channel_done(&fhp->channel); pvr2_trace(PVR2_TRACE_STRUCT, diff --git a/drivers/media/v4l2-core/v4l2-fh.c b/drivers/media/v4l2-core/v4l2-fh.c index b59b1084d8cd..df3ba9d4674b 100644 --- a/drivers/media/v4l2-core/v4l2-fh.c +++ b/drivers/media/v4l2-core/v4l2-fh.c @@ -67,7 +67,7 @@ int v4l2_fh_open(struct file *filp) } EXPORT_SYMBOL_GPL(v4l2_fh_open); -void v4l2_fh_del(struct v4l2_fh *fh) +void v4l2_fh_del(struct v4l2_fh *fh, struct file *filp) { unsigned long flags; @@ -75,6 +75,8 @@ void v4l2_fh_del(struct v4l2_fh *fh) list_del_init(&fh->list); spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); v4l2_prio_close(fh->vdev->prio, fh->prio); + + filp->private_data = NULL; } EXPORT_SYMBOL_GPL(v4l2_fh_del); @@ -94,10 +96,9 @@ int v4l2_fh_release(struct file *filp) struct v4l2_fh *fh = file_to_v4l2_fh(filp); if (fh) { - v4l2_fh_del(fh); + v4l2_fh_del(fh, filp); v4l2_fh_exit(fh); kfree(fh); - filp->private_data = NULL; } return 0; } diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index bf35ac436249..41e4aca77b7f 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -109,7 +109,7 @@ static int subdev_open(struct file *file) err: module_put(subdev_fh->owner); - v4l2_fh_del(&subdev_fh->vfh); + v4l2_fh_del(&subdev_fh->vfh, file); v4l2_fh_exit(&subdev_fh->vfh); subdev_fh_free(subdev_fh); kfree(subdev_fh); @@ -127,11 +127,10 @@ static int subdev_close(struct file *file) if (sd->internal_ops && sd->internal_ops->close) sd->internal_ops->close(sd, subdev_fh); module_put(subdev_fh->owner); - v4l2_fh_del(vfh); + v4l2_fh_del(vfh, file); v4l2_fh_exit(vfh); subdev_fh_free(subdev_fh); kfree(subdev_fh); - file->private_data = NULL; return 0; } diff --git a/drivers/staging/media/imx/imx-media-csc-scaler.c b/drivers/staging/media/imx/imx-media-csc-scaler.c index 7fedb33dda34..dc7f9a77cbe6 100644 --- a/drivers/staging/media/imx/imx-media-csc-scaler.c +++ b/drivers/staging/media/imx/imx-media-csc-scaler.c @@ -792,7 +792,7 @@ static int ipu_csc_scaler_open(struct file *file) err_ctrls: v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); err_ctx: - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); return ret; @@ -807,7 +807,7 @@ static int ipu_csc_scaler_release(struct file *file) v4l2_ctrl_handler_free(&ctx->ctrl_hdlr); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c index b92666ff50a1..49e497a32973 100644 --- a/drivers/staging/media/meson/vdec/vdec.c +++ b/drivers/staging/media/meson/vdec/vdec.c @@ -926,7 +926,7 @@ static int vdec_close(struct file *file) v4l2_m2m_ctx_release(sess->m2m_ctx); v4l2_m2m_release(sess->m2m_dev); - v4l2_fh_del(&sess->fh); + v4l2_fh_del(&sess->fh, file); v4l2_fh_exit(&sess->fh); mutex_destroy(&sess->lock); diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index ebefd646dbdb..bff42ea1871f 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -404,7 +404,7 @@ static int cedrus_release(struct file *file) mutex_lock(&dev->dev_mutex); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); v4l2_ctrl_handler_free(&ctx->hdl); diff --git a/drivers/staging/most/video/video.c b/drivers/staging/most/video/video.c index 24a68e3e5419..32f71d9a9cf7 100644 --- a/drivers/staging/most/video/video.c +++ b/drivers/staging/most/video/video.c @@ -107,7 +107,7 @@ static int comp_vdev_open(struct file *filp) return 0; err_rm: - v4l2_fh_del(&fh->fh); + v4l2_fh_del(&fh->fh, filp); v4l2_fh_exit(&fh->fh); err_dec: @@ -143,7 +143,7 @@ static int comp_vdev_close(struct file *filp) most_stop_channel(mdev->iface, mdev->ch_idx, &comp); mdev->mute = false; - v4l2_fh_del(&fh->fh); + v4l2_fh_del(&fh->fh, filp); v4l2_fh_exit(&fh->fh); atomic_dec(&mdev->access_ref); diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c index 680f25d17dc2..fd4b998ccd16 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -692,8 +692,7 @@ uvc_v4l2_release(struct file *file) uvc_v4l2_disable(uvc); mutex_unlock(&video->mutex); - file->private_data = NULL; - v4l2_fh_del(&handle->vfh); + v4l2_fh_del(&handle->vfh, file); v4l2_fh_exit(&handle->vfh); kfree(handle); diff --git a/include/media/v4l2-fh.h b/include/media/v4l2-fh.h index d8fcf49f10e0..5e4c76163512 100644 --- a/include/media/v4l2-fh.h +++ b/include/media/v4l2-fh.h @@ -114,12 +114,15 @@ int v4l2_fh_open(struct file *filp); * v4l2_fh_del - Remove file handle from the list of file handles. * * @fh: pointer to &struct v4l2_fh + * @filp: pointer to &struct file associated with @fh + * + * The function resets filp->private_data to NULL. * * .. note:: * Must be called in v4l2_file_operations->release\(\) handler if the driver * uses &struct v4l2_fh. */ -void v4l2_fh_del(struct v4l2_fh *fh); +void v4l2_fh_del(struct v4l2_fh *fh, struct file *filp); /** * v4l2_fh_exit - Release resources related to a file handle. From 04eff11469b29f9d1e8ce9b8cc9c86817a2ae92c Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:30:10 +0300 Subject: [PATCH 00528/11391] media: ipu6: isys: Don't set V4L2_FL_USES_V4L2_FH manually The V4L2_FL_USES_V4L2_FH flag is set by v4l2_fh_init(). It is not meant to be set manually by drivers. Drop it from the ipu6-isys driver. Signed-off-by: Laurent Pinchart Reviewed-by: Bingbu Cao Reviewed-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/pci/intel/ipu6/ipu6-isys-video.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c index 24a2ef93474c..f3f3bc0615e5 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c +++ b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c @@ -1306,7 +1306,6 @@ int ipu6_isys_video_init(struct ipu6_isys_video *av) __ipu6_isys_vidioc_try_fmt_meta_cap(av, &format_meta); av->meta_fmt = format_meta.fmt.meta; - set_bit(V4L2_FL_USES_V4L2_FH, &av->vdev.flags); video_set_drvdata(&av->vdev, av); ret = video_register_device(&av->vdev, VFL_TYPE_VIDEO, -1); From 5c17eace98188614ab03b25784a39b9a9cda6e35 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:30:11 +0300 Subject: [PATCH 00529/11391] media: staging: ipu7: isys: Don't set V4L2_FL_USES_V4L2_FH manually The V4L2_FL_USES_V4L2_FH flag is set by v4l2_fh_init(). It is not meant to be set manually by drivers. Drop it from the ipu7-isys driver. Signed-off-by: Laurent Pinchart Reviewed-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/staging/media/ipu7/ipu7-isys-video.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/staging/media/ipu7/ipu7-isys-video.c b/drivers/staging/media/ipu7/ipu7-isys-video.c index 8756da3a8fb0..6b31c766bc58 100644 --- a/drivers/staging/media/ipu7/ipu7-isys-video.c +++ b/drivers/staging/media/ipu7/ipu7-isys-video.c @@ -1082,7 +1082,6 @@ int ipu7_isys_video_init(struct ipu7_isys_video *av) __ipu_isys_vidioc_try_fmt_vid_cap(av, &format); av->pix_fmt = format.fmt.pix; - set_bit(V4L2_FL_USES_V4L2_FH, &av->vdev.flags); video_set_drvdata(&av->vdev, av); ret = video_register_device(&av->vdev, VFL_TYPE_VIDEO, -1); From 5410bad3326f3557a7d996b19fa4adc2c70b3c0e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:30:12 +0300 Subject: [PATCH 00530/11391] media: v4l2-ctrls: Move v4l2_fh retrieval after V4L2_FL_USES_V4L2_FH check The v4l2_ctrl_log_status() function retrieves the v4l2_fh from the file with file_to_v4l2_fh() before checking the V4L2_FL_USES_V4L2_FH to see if the device makes use of v4l2_fh. While this doesn't cause any practical issue given the current implementation of file_to_v4l2_fh(), it is cleaner to retrieve the v4l2_fh after checking the flag. This could prevent future issues if the implementation of file_to_v4l2_fh() changes. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/v4l2-core/v4l2-ctrls-api.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-ctrls-api.c b/drivers/media/v4l2-core/v4l2-ctrls-api.c index d46b2c8f3d23..b0bba8eec143 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-api.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-api.c @@ -1253,11 +1253,14 @@ EXPORT_SYMBOL(v4l2_querymenu); int v4l2_ctrl_log_status(struct file *file, void *fh) { struct video_device *vfd = video_devdata(file); - struct v4l2_fh *vfh = file_to_v4l2_fh(file); - if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) && vfd->v4l2_dev) + if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) && vfd->v4l2_dev) { + struct v4l2_fh *vfh = file_to_v4l2_fh(file); + v4l2_ctrl_handler_log_status(vfh->ctrl_handler, vfd->v4l2_dev->name); + } + return 0; } EXPORT_SYMBOL(v4l2_ctrl_log_status); From b3d945ba42dd640255492a523baeb6b6946a99bf Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:30:13 +0300 Subject: [PATCH 00531/11391] media: v4l2-dev: Make open and release file operations mandatory All V4L2 drivers implement the open and release file operations. As all new drivers will need to use v4l2_fh, this situation won't change. Make those two file operation mandatory at registration time. This allows simplifying v4l2_open() and v4l2_release(). Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/v4l2-core/v4l2-dev.c | 32 +++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index c369235113d9..1a4184b94838 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -411,7 +411,7 @@ static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm) static int v4l2_open(struct inode *inode, struct file *filp) { struct video_device *vdev; - int ret = 0; + int ret; /* Check if the video device is available */ mutex_lock(&videodev_lock); @@ -424,12 +424,11 @@ static int v4l2_open(struct inode *inode, struct file *filp) /* and increase the device refcount */ video_get(vdev); mutex_unlock(&videodev_lock); - if (vdev->fops->open) { - if (video_is_registered(vdev)) - ret = vdev->fops->open(filp); - else - ret = -ENODEV; - } + + if (video_is_registered(vdev)) + ret = vdev->fops->open(filp); + else + ret = -ENODEV; if (vdev->dev_debug & V4L2_DEV_DEBUG_FOP) dprintk("%s: open (%d)\n", @@ -444,7 +443,7 @@ static int v4l2_open(struct inode *inode, struct file *filp) static int v4l2_release(struct inode *inode, struct file *filp) { struct video_device *vdev = video_devdata(filp); - int ret = 0; + int ret; /* * We need to serialize the release() with queueing new requests. @@ -452,14 +451,12 @@ static int v4l2_release(struct inode *inode, struct file *filp) * operation, and that should not be mixed with queueing a new * request at the same time. */ - if (vdev->fops->release) { - if (v4l2_device_supports_requests(vdev->v4l2_dev)) { - mutex_lock(&vdev->v4l2_dev->mdev->req_queue_mutex); - ret = vdev->fops->release(filp); - mutex_unlock(&vdev->v4l2_dev->mdev->req_queue_mutex); - } else { - ret = vdev->fops->release(filp); - } + if (v4l2_device_supports_requests(vdev->v4l2_dev)) { + mutex_lock(&vdev->v4l2_dev->mdev->req_queue_mutex); + ret = vdev->fops->release(filp); + mutex_unlock(&vdev->v4l2_dev->mdev->req_queue_mutex); + } else { + ret = vdev->fops->release(filp); } if (vdev->dev_debug & V4L2_DEV_DEBUG_FOP) @@ -922,6 +919,9 @@ int __video_register_device(struct video_device *vdev, /* the device_caps field MUST be set for all but subdevs */ if (WARN_ON(type != VFL_TYPE_SUBDEV && !vdev->device_caps)) return -EINVAL; + /* the open and release file operations are mandatory */ + if (WARN_ON(!vdev->fops || !vdev->fops->open || !vdev->fops->release)) + return -EINVAL; /* v4l2_fh support */ spin_lock_init(&vdev->fh_lock); From bb4d6be205dae94aa2d3c3a1ad814dad90d4fd62 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:30:14 +0300 Subject: [PATCH 00532/11391] media: Drop V4L2_FL_USES_V4L2_FH checks Now that all drivers use v4l2_fh, we can drop the V4L2_FL_USES_V4L2_FH checks through the V4L2 core. To ensure that all new drivers use v4l2_fh, keep setting the V4L2_FL_USES_V4L2_FH flag in v4l2_fh_init(), and verify it is set after the .open() file operation returns. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- Documentation/driver-api/media/v4l2-fh.rst | 15 +------- .../zh_CN/video4linux/v4l2-framework.txt | 5 --- .../media/common/videobuf2/videobuf2-v4l2.c | 12 ++---- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 7 +--- drivers/media/v4l2-core/v4l2-ctrls-api.c | 2 +- drivers/media/v4l2-core/v4l2-dev.c | 21 ++++++++--- drivers/media/v4l2-core/v4l2-ioctl.c | 37 ++++++------------- drivers/media/v4l2-core/v4l2-mem2mem.c | 12 ++---- include/media/v4l2-dev.h | 2 +- include/media/v4l2-fh.h | 2 +- 10 files changed, 43 insertions(+), 72 deletions(-) diff --git a/Documentation/driver-api/media/v4l2-fh.rst b/Documentation/driver-api/media/v4l2-fh.rst index afcad22ead7c..a934caa483a4 100644 --- a/Documentation/driver-api/media/v4l2-fh.rst +++ b/Documentation/driver-api/media/v4l2-fh.rst @@ -3,13 +3,8 @@ V4L2 File handles ----------------- -struct v4l2_fh provides a way to easily keep file handle specific -data that is used by the V4L2 framework. - -.. attention:: - New drivers must use struct v4l2_fh - since it is also used to implement priority handling - (:ref:`VIDIOC_G_PRIORITY`). +struct v4l2_fh provides a way to easily keep file handle specific data that is +used by the V4L2 framework. Its usage is mandatory in all drivers. struct v4l2_fh is allocated in the driver's ``open()`` file operation handler. It is typically embedded in a larger driver-specific structure. The @@ -134,12 +129,6 @@ associated device node: - Same, but it calls v4l2_fh_is_singular with filp->private_data. -.. note:: - The V4L2 framework knows whether a driver uses :c:type:`v4l2_fh` as its - ``file->private_data`` pointer by testing the ``V4L2_FL_USES_V4L2_FH`` - bit in :c:type:`video_device`->flags. This bit is set whenever - :c:func:`v4l2_fh_init` is called. - V4L2 fh functions and data structures ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/Documentation/translations/zh_CN/video4linux/v4l2-framework.txt b/Documentation/translations/zh_CN/video4linux/v4l2-framework.txt index 1653c6e2cb46..f0be21a60a0f 100644 --- a/Documentation/translations/zh_CN/video4linux/v4l2-framework.txt +++ b/Documentation/translations/zh_CN/video4linux/v4l2-framework.txt @@ -775,11 +775,6 @@ v4l2_fh 结构体提供一个保存用于 V4L2 框架的文件句柄特定数据 如果 video_device 标志,新驱动 必须使用 v4l2_fh 结构体,因为它也用于实现优先级处理(VIDIOC_G/S_PRIORITY)。 -v4l2_fh 的用户(位于 V4l2 框架中,并非驱动)可通过测试 -video_device->flags 中的 V4L2_FL_USES_V4L2_FH 位得知驱动是否使用 -v4l2_fh 作为他的 file->private_data 指针。这个位会在调用 v4l2_fh_init() -时被设置。 - v4l2_fh 结构体作为驱动自身文件句柄结构体的一部分被分配,且驱动在 其打开函数中将 file->private_data 指向它。 diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index f29307e59be5..d911021c1bb0 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -973,18 +973,14 @@ EXPORT_SYMBOL_GPL(vb2_queue_change_type); __poll_t vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait) { - struct video_device *vfd = video_devdata(file); + struct v4l2_fh *fh = file_to_v4l2_fh(file); __poll_t res; res = vb2_core_poll(q, file, wait); - if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) { - struct v4l2_fh *fh = file_to_v4l2_fh(file); - - poll_wait(file, &fh->wait, wait); - if (v4l2_event_pending(fh)) - res |= EPOLLPRI; - } + poll_wait(file, &fh->wait, wait); + if (v4l2_event_pending(fh)) + res |= EPOLLPRI; return res; } diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 8a5559225ff2..e5642e639811 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -672,15 +672,12 @@ struct v4l2_ext_control32 { static inline bool ctrl_is_pointer(struct file *file, u32 id) { struct video_device *vdev = video_devdata(file); - struct v4l2_fh *fh = NULL; + struct v4l2_fh *fh = file_to_v4l2_fh(file); struct v4l2_ctrl_handler *hdl = NULL; struct v4l2_query_ext_ctrl qec = { id }; const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops; - if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags)) - fh = file_to_v4l2_fh(file); - - if (fh && fh->ctrl_handler) + if (fh->ctrl_handler) hdl = fh->ctrl_handler; else if (vdev->ctrl_handler) hdl = vdev->ctrl_handler; diff --git a/drivers/media/v4l2-core/v4l2-ctrls-api.c b/drivers/media/v4l2-core/v4l2-ctrls-api.c index b0bba8eec143..afb4e5581b90 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-api.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-api.c @@ -1254,7 +1254,7 @@ int v4l2_ctrl_log_status(struct file *file, void *fh) { struct video_device *vfd = video_devdata(file); - if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) && vfd->v4l2_dev) { + if (vfd->v4l2_dev) { struct v4l2_fh *vfh = file_to_v4l2_fh(file); v4l2_ctrl_handler_log_status(vfh->ctrl_handler, diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 1a4184b94838..10a126e50c1c 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -425,14 +425,26 @@ static int v4l2_open(struct inode *inode, struct file *filp) video_get(vdev); mutex_unlock(&videodev_lock); - if (video_is_registered(vdev)) - ret = vdev->fops->open(filp); - else + if (!video_is_registered(vdev)) { ret = -ENODEV; + goto done; + } + ret = vdev->fops->open(filp); + if (ret) + goto done; + + /* All drivers must use v4l2_fh. */ + if (WARN_ON(!test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags))) { + vdev->fops->release(filp); + ret = -ENODEV; + } + +done: if (vdev->dev_debug & V4L2_DEV_DEBUG_FOP) dprintk("%s: open (%d)\n", video_device_node_name(vdev), ret); + /* decrease the refcount in case of an error */ if (ret) video_put(vdev); @@ -1114,8 +1126,7 @@ void video_unregister_device(struct video_device *vdev) */ clear_bit(V4L2_FL_REGISTERED, &vdev->flags); mutex_unlock(&videodev_lock); - if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags)) - v4l2_event_wake_all(vdev); + v4l2_event_wake_all(vdev); device_unregister(&vdev->dev); } EXPORT_SYMBOL(video_unregister_device); diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 8c81852c3046..6c684884873e 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1195,8 +1195,6 @@ static int v4l_s_priority(const struct v4l2_ioctl_ops *ops, u32 *p = arg; vfd = video_devdata(file); - if (!test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) - return -ENOTTY; vfh = file_to_v4l2_fh(file); return v4l2_prio_change(vfd->prio, &vfh->prio, *p); } @@ -2297,8 +2295,7 @@ static int v4l_queryctrl(const struct v4l2_ioctl_ops *ops, struct video_device *vfd = video_devdata(file); struct v4l2_query_ext_ctrl qec = {}; struct v4l2_queryctrl *p = arg; - struct v4l2_fh *vfh = - test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL; + struct v4l2_fh *vfh = fh; int ret; if (vfh && vfh->ctrl_handler) @@ -2322,8 +2319,7 @@ static int v4l_query_ext_ctrl(const struct v4l2_ioctl_ops *ops, { struct video_device *vfd = video_devdata(file); struct v4l2_query_ext_ctrl *p = arg; - struct v4l2_fh *vfh = - test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL; + struct v4l2_fh *vfh = fh; if (vfh && vfh->ctrl_handler) return v4l2_query_ext_ctrl(vfh->ctrl_handler, p); @@ -2339,8 +2335,7 @@ static int v4l_querymenu(const struct v4l2_ioctl_ops *ops, { struct video_device *vfd = video_devdata(file); struct v4l2_querymenu *p = arg; - struct v4l2_fh *vfh = - test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL; + struct v4l2_fh *vfh = fh; if (vfh && vfh->ctrl_handler) return v4l2_querymenu(vfh->ctrl_handler, p); @@ -2356,8 +2351,7 @@ static int v4l_g_ctrl(const struct v4l2_ioctl_ops *ops, { struct video_device *vfd = video_devdata(file); struct v4l2_control *p = arg; - struct v4l2_fh *vfh = - test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL; + struct v4l2_fh *vfh = fh; struct v4l2_ext_controls ctrls; struct v4l2_ext_control ctrl; @@ -2388,8 +2382,7 @@ static int v4l_s_ctrl(const struct v4l2_ioctl_ops *ops, { struct video_device *vfd = video_devdata(file); struct v4l2_control *p = arg; - struct v4l2_fh *vfh = - test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL; + struct v4l2_fh *vfh = fh; struct v4l2_ext_controls ctrls; struct v4l2_ext_control ctrl; int ret; @@ -2418,8 +2411,7 @@ static int v4l_g_ext_ctrls(const struct v4l2_ioctl_ops *ops, { struct video_device *vfd = video_devdata(file); struct v4l2_ext_controls *p = arg; - struct v4l2_fh *vfh = - test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL; + struct v4l2_fh *vfh = fh; p->error_idx = p->count; if (vfh && vfh->ctrl_handler) @@ -2439,8 +2431,7 @@ static int v4l_s_ext_ctrls(const struct v4l2_ioctl_ops *ops, { struct video_device *vfd = video_devdata(file); struct v4l2_ext_controls *p = arg; - struct v4l2_fh *vfh = - test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL; + struct v4l2_fh *vfh = fh; p->error_idx = p->count; if (vfh && vfh->ctrl_handler) @@ -2460,8 +2451,7 @@ static int v4l_try_ext_ctrls(const struct v4l2_ioctl_ops *ops, { struct video_device *vfd = video_devdata(file); struct v4l2_ext_controls *p = arg; - struct v4l2_fh *vfh = - test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL; + struct v4l2_fh *vfh = fh; p->error_idx = p->count; if (vfh && vfh->ctrl_handler) @@ -3073,7 +3063,7 @@ static long __video_do_ioctl(struct file *file, struct v4l2_ioctl_info default_info; const struct v4l2_ioctl_info *info; void *fh = file->private_data; - struct v4l2_fh *vfh = NULL; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); int dev_debug = vfd->dev_debug; long ret = -ENOTTY; @@ -3083,9 +3073,6 @@ static long __video_do_ioctl(struct file *file, return ret; } - if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) - vfh = file_to_v4l2_fh(file); - /* * We need to serialize streamon/off with queueing new requests. * These ioctls may trigger the cancellation of a streaming @@ -3117,10 +3104,10 @@ static long __video_do_ioctl(struct file *file, info = &v4l2_ioctls[_IOC_NR(cmd)]; if (!is_valid_ioctl(vfd, cmd) && - !((info->flags & INFO_FL_CTRL) && vfh && vfh->ctrl_handler)) + !((info->flags & INFO_FL_CTRL) && vfh->ctrl_handler)) goto done; - if (vfh && (info->flags & INFO_FL_PRIO)) { + if (info->flags & INFO_FL_PRIO) { ret = v4l2_prio_check(vfd->prio, vfh->prio); if (ret) goto done; @@ -3139,7 +3126,7 @@ static long __video_do_ioctl(struct file *file, ret = -ENOTTY; } else { ret = ops->vidioc_default(file, fh, - vfh ? v4l2_prio_check(vfd->prio, vfh->prio) >= 0 : 0, + v4l2_prio_check(vfd->prio, vfh->prio) >= 0, cmd, arg); } diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index e67e67f76f72..7678b8dbedbd 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -951,7 +951,7 @@ static __poll_t v4l2_m2m_poll_for_data(struct file *file, __poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, struct poll_table_struct *wait) { - struct video_device *vfd = video_devdata(file); + struct v4l2_fh *fh = file_to_v4l2_fh(file); struct vb2_queue *src_q = v4l2_m2m_get_src_vq(m2m_ctx); struct vb2_queue *dst_q = v4l2_m2m_get_dst_vq(m2m_ctx); __poll_t req_events = poll_requested_events(wait); @@ -970,13 +970,9 @@ __poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, if (req_events & (EPOLLOUT | EPOLLWRNORM | EPOLLIN | EPOLLRDNORM)) rc = v4l2_m2m_poll_for_data(file, m2m_ctx, wait); - if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) { - struct v4l2_fh *fh = file_to_v4l2_fh(file); - - poll_wait(file, &fh->wait, wait); - if (v4l2_event_pending(fh)) - rc |= EPOLLPRI; - } + poll_wait(file, &fh->wait, wait); + if (v4l2_event_pending(fh)) + rc |= EPOLLPRI; return rc; } diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index a69801274800..a213c3398dcf 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h @@ -74,7 +74,7 @@ struct dentry; * @V4L2_FL_USES_V4L2_FH: * indicates that file->private_data points to &struct v4l2_fh. * This flag is set by the core when v4l2_fh_init() is called. - * All new drivers should use it. + * All drivers must use it. * @V4L2_FL_QUIRK_INVERTED_CROP: * some old M2M drivers use g/s_crop/cropcap incorrectly: crop and * compose are swapped. If this flag is set, then the selection diff --git a/include/media/v4l2-fh.h b/include/media/v4l2-fh.h index 5e4c76163512..aad4b3689d7e 100644 --- a/include/media/v4l2-fh.h +++ b/include/media/v4l2-fh.h @@ -3,7 +3,7 @@ * v4l2-fh.h * * V4L2 file handle. Store per file handle data for the V4L2 - * framework. Using file handles is optional for the drivers. + * framework. Using file handles is mandatory for the drivers. * * Copyright (C) 2009--2010 Nokia Corporation. * From dc322d13cf417552b59e313e809a6da40b8b36ef Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:15 +0300 Subject: [PATCH 00533/11391] media: zoran: Remove zoran_fh structure The zoran_fh structure is a wrapper around v4l2_fh. Its usage has been mostly removed by commit 83f89a8bcbc3 ("media: zoran: convert to vb2"), but the structure stayed by mistake. It is now used in a single location, assigned from a void pointer and then recast to a void pointer, without being every accessed. Drop it. Fixes: 83f89a8bcbc3 ("media: zoran: convert to vb2") Signed-off-by: Jacopo Mondi Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/pci/zoran/zoran.h | 6 ------ drivers/media/pci/zoran/zoran_driver.c | 3 +-- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/media/pci/zoran/zoran.h b/drivers/media/pci/zoran/zoran.h index 1cd990468d3d..d05e222b3921 100644 --- a/drivers/media/pci/zoran/zoran.h +++ b/drivers/media/pci/zoran/zoran.h @@ -154,12 +154,6 @@ struct zoran_jpg_settings { struct zoran; -/* zoran_fh contains per-open() settings */ -struct zoran_fh { - struct v4l2_fh fh; - struct zoran *zr; -}; - struct card_info { enum card_type type; char name[32]; diff --git a/drivers/media/pci/zoran/zoran_driver.c b/drivers/media/pci/zoran/zoran_driver.c index f42f596d3e62..ec7fc1da4cc0 100644 --- a/drivers/media/pci/zoran/zoran_driver.c +++ b/drivers/media/pci/zoran/zoran_driver.c @@ -511,12 +511,11 @@ static int zoran_s_fmt_vid_cap(struct file *file, void *__fh, struct v4l2_format *fmt) { struct zoran *zr = video_drvdata(file); - struct zoran_fh *fh = __fh; int i; int res = 0; if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) - return zoran_s_fmt_vid_out(file, fh, fmt); + return zoran_s_fmt_vid_out(file, __fh, fmt); for (i = 0; i < NUM_FORMATS; i++) if (fmt->fmt.pix.pixelformat == zoran_formats[i].fourcc) From 6b79b21e7d2cfc5e31ce00869526f31ae0f93959 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:16 +0300 Subject: [PATCH 00534/11391] media: zoran: Rename __fh to fh Unless there is a good reason to do so, naming variable with double underscore is generally not a good idea. Rename the (mostly unused) __fh argument to ioctl handlers to fh. Signed-off-by: Jacopo Mondi Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/pci/zoran/zoran_driver.c | 36 +++++++++++++------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/media/pci/zoran/zoran_driver.c b/drivers/media/pci/zoran/zoran_driver.c index ec7fc1da4cc0..5b4d5dd06edb 100644 --- a/drivers/media/pci/zoran/zoran_driver.c +++ b/drivers/media/pci/zoran/zoran_driver.c @@ -245,7 +245,7 @@ static int zoran_set_input(struct zoran *zr, int input) * ioctl routine */ -static int zoran_querycap(struct file *file, void *__fh, struct v4l2_capability *cap) +static int zoran_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { struct zoran *zr = video_drvdata(file); @@ -278,7 +278,7 @@ static int zoran_enum_fmt(struct zoran *zr, struct v4l2_fmtdesc *fmt, int flag) return -EINVAL; } -static int zoran_enum_fmt_vid_cap(struct file *file, void *__fh, +static int zoran_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) { struct zoran *zr = video_drvdata(file); @@ -286,7 +286,7 @@ static int zoran_enum_fmt_vid_cap(struct file *file, void *__fh, return zoran_enum_fmt(zr, f, ZORAN_FORMAT_CAPTURE); } -static int zoran_g_fmt_vid_out(struct file *file, void *__fh, +static int zoran_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) { struct zoran *zr = video_drvdata(file); @@ -308,13 +308,13 @@ static int zoran_g_fmt_vid_out(struct file *file, void *__fh, return 0; } -static int zoran_g_fmt_vid_cap(struct file *file, void *__fh, +static int zoran_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) { struct zoran *zr = video_drvdata(file); if (zr->map_mode != ZORAN_MAP_MODE_RAW) - return zoran_g_fmt_vid_out(file, __fh, fmt); + return zoran_g_fmt_vid_out(file, fh, fmt); fmt->fmt.pix.width = zr->v4l_settings.width; fmt->fmt.pix.height = zr->v4l_settings.height; fmt->fmt.pix.sizeimage = zr->buffer_size; @@ -328,7 +328,7 @@ static int zoran_g_fmt_vid_cap(struct file *file, void *__fh, return 0; } -static int zoran_try_fmt_vid_out(struct file *file, void *__fh, +static int zoran_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) { struct zoran *zr = video_drvdata(file); @@ -391,7 +391,7 @@ static int zoran_try_fmt_vid_out(struct file *file, void *__fh, return res; } -static int zoran_try_fmt_vid_cap(struct file *file, void *__fh, +static int zoran_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) { struct zoran *zr = video_drvdata(file); @@ -399,7 +399,7 @@ static int zoran_try_fmt_vid_cap(struct file *file, void *__fh, int i; if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) - return zoran_try_fmt_vid_out(file, __fh, fmt); + return zoran_try_fmt_vid_out(file, fh, fmt); for (i = 0; i < NUM_FORMATS; i++) if (zoran_formats[i].fourcc == fmt->fmt.pix.pixelformat) @@ -427,7 +427,7 @@ static int zoran_try_fmt_vid_cap(struct file *file, void *__fh, return 0; } -static int zoran_s_fmt_vid_out(struct file *file, void *__fh, +static int zoran_s_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) { struct zoran *zr = video_drvdata(file); @@ -507,7 +507,7 @@ static int zoran_s_fmt_vid_out(struct file *file, void *__fh, return res; } -static int zoran_s_fmt_vid_cap(struct file *file, void *__fh, +static int zoran_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) { struct zoran *zr = video_drvdata(file); @@ -515,7 +515,7 @@ static int zoran_s_fmt_vid_cap(struct file *file, void *__fh, int res = 0; if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) - return zoran_s_fmt_vid_out(file, __fh, fmt); + return zoran_s_fmt_vid_out(file, fh, fmt); for (i = 0; i < NUM_FORMATS; i++) if (fmt->fmt.pix.pixelformat == zoran_formats[i].fourcc) @@ -555,7 +555,7 @@ static int zoran_s_fmt_vid_cap(struct file *file, void *__fh, return res; } -static int zoran_g_std(struct file *file, void *__fh, v4l2_std_id *std) +static int zoran_g_std(struct file *file, void *fh, v4l2_std_id *std) { struct zoran *zr = video_drvdata(file); @@ -563,7 +563,7 @@ static int zoran_g_std(struct file *file, void *__fh, v4l2_std_id *std) return 0; } -static int zoran_s_std(struct file *file, void *__fh, v4l2_std_id std) +static int zoran_s_std(struct file *file, void *fh, v4l2_std_id std) { struct zoran *zr = video_drvdata(file); int res = 0; @@ -578,7 +578,7 @@ static int zoran_s_std(struct file *file, void *__fh, v4l2_std_id std) return res; } -static int zoran_enum_input(struct file *file, void *__fh, +static int zoran_enum_input(struct file *file, void *fh, struct v4l2_input *inp) { struct zoran *zr = video_drvdata(file); @@ -595,7 +595,7 @@ static int zoran_enum_input(struct file *file, void *__fh, return 0; } -static int zoran_g_input(struct file *file, void *__fh, unsigned int *input) +static int zoran_g_input(struct file *file, void *fh, unsigned int *input) { struct zoran *zr = video_drvdata(file); @@ -604,7 +604,7 @@ static int zoran_g_input(struct file *file, void *__fh, unsigned int *input) return 0; } -static int zoran_s_input(struct file *file, void *__fh, unsigned int input) +static int zoran_s_input(struct file *file, void *fh, unsigned int input) { struct zoran *zr = video_drvdata(file); int res; @@ -617,7 +617,7 @@ static int zoran_s_input(struct file *file, void *__fh, unsigned int input) } /* cropping (sub-frame capture) */ -static int zoran_g_selection(struct file *file, void *__fh, struct v4l2_selection *sel) +static int zoran_g_selection(struct file *file, void *fh, struct v4l2_selection *sel) { struct zoran *zr = video_drvdata(file); @@ -652,7 +652,7 @@ static int zoran_g_selection(struct file *file, void *__fh, struct v4l2_selectio return 0; } -static int zoran_s_selection(struct file *file, void *__fh, struct v4l2_selection *sel) +static int zoran_s_selection(struct file *file, void *fh, struct v4l2_selection *sel) { struct zoran *zr = video_drvdata(file); struct zoran_jpg_settings settings; From ae76d82230844d8d7cbbcf3e3a9dd7228a7cb994 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:17 +0300 Subject: [PATCH 00535/11391] media: v4l2-ioctl: Access v4l2_fh from private_data Now that it is guaranteed that file->private_data is set to point to the 'struct v4l2_fh' initialised by v4l2_fh_add() the v4l2-ioctl layer can be modified to retrieve the v4l2_fh pointer from the file *. As the __video_do_ioctl() function, that calls all the handlers modified by this patch goes as: static long __video_do_ioctl(struct file *file, unsigned int cmd, void *arg) { void *fh = file->private_data; ... ret = info->func(ops, file, fh, arg); } This patch introduces no functional changes and makes it possible to remove in future the 'fh' argument to all ioctl handlers. Signed-off-by: Jacopo Mondi Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/v4l2-core/v4l2-ioctl.c | 33 ++++++++++++++++------------ 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 6c684884873e..378a2a149fec 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -2295,7 +2295,7 @@ static int v4l_queryctrl(const struct v4l2_ioctl_ops *ops, struct video_device *vfd = video_devdata(file); struct v4l2_query_ext_ctrl qec = {}; struct v4l2_queryctrl *p = arg; - struct v4l2_fh *vfh = fh; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); int ret; if (vfh && vfh->ctrl_handler) @@ -2319,7 +2319,7 @@ static int v4l_query_ext_ctrl(const struct v4l2_ioctl_ops *ops, { struct video_device *vfd = video_devdata(file); struct v4l2_query_ext_ctrl *p = arg; - struct v4l2_fh *vfh = fh; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); if (vfh && vfh->ctrl_handler) return v4l2_query_ext_ctrl(vfh->ctrl_handler, p); @@ -2335,7 +2335,7 @@ static int v4l_querymenu(const struct v4l2_ioctl_ops *ops, { struct video_device *vfd = video_devdata(file); struct v4l2_querymenu *p = arg; - struct v4l2_fh *vfh = fh; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); if (vfh && vfh->ctrl_handler) return v4l2_querymenu(vfh->ctrl_handler, p); @@ -2351,7 +2351,7 @@ static int v4l_g_ctrl(const struct v4l2_ioctl_ops *ops, { struct video_device *vfd = video_devdata(file); struct v4l2_control *p = arg; - struct v4l2_fh *vfh = fh; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct v4l2_ext_controls ctrls; struct v4l2_ext_control ctrl; @@ -2382,7 +2382,7 @@ static int v4l_s_ctrl(const struct v4l2_ioctl_ops *ops, { struct video_device *vfd = video_devdata(file); struct v4l2_control *p = arg; - struct v4l2_fh *vfh = fh; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct v4l2_ext_controls ctrls; struct v4l2_ext_control ctrl; int ret; @@ -2411,7 +2411,7 @@ static int v4l_g_ext_ctrls(const struct v4l2_ioctl_ops *ops, { struct video_device *vfd = video_devdata(file); struct v4l2_ext_controls *p = arg; - struct v4l2_fh *vfh = fh; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); p->error_idx = p->count; if (vfh && vfh->ctrl_handler) @@ -2431,7 +2431,7 @@ static int v4l_s_ext_ctrls(const struct v4l2_ioctl_ops *ops, { struct video_device *vfd = video_devdata(file); struct v4l2_ext_controls *p = arg; - struct v4l2_fh *vfh = fh; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); p->error_idx = p->count; if (vfh && vfh->ctrl_handler) @@ -2451,7 +2451,7 @@ static int v4l_try_ext_ctrls(const struct v4l2_ioctl_ops *ops, { struct video_device *vfd = video_devdata(file); struct v4l2_ext_controls *p = arg; - struct v4l2_fh *vfh = fh; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); p->error_idx = p->count; if (vfh && vfh->ctrl_handler) @@ -2746,19 +2746,25 @@ static int v4l_dbg_g_chip_info(const struct v4l2_ioctl_ops *ops, static int v4l_dqevent(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { - return v4l2_event_dequeue(fh, arg, file->f_flags & O_NONBLOCK); + struct v4l2_fh *vfh = file_to_v4l2_fh(file); + + return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK); } static int v4l_subscribe_event(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { - return ops->vidioc_subscribe_event(fh, arg); + struct v4l2_fh *vfh = file_to_v4l2_fh(file); + + return ops->vidioc_subscribe_event(vfh, arg); } static int v4l_unsubscribe_event(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { - return ops->vidioc_unsubscribe_event(fh, arg); + struct v4l2_fh *vfh = file_to_v4l2_fh(file); + + return ops->vidioc_unsubscribe_event(vfh, arg); } static int v4l_g_sliced_vbi_cap(const struct v4l2_ioctl_ops *ops, @@ -3062,7 +3068,6 @@ static long __video_do_ioctl(struct file *file, bool write_only = false; struct v4l2_ioctl_info default_info; const struct v4l2_ioctl_info *info; - void *fh = file->private_data; struct v4l2_fh *vfh = file_to_v4l2_fh(file); int dev_debug = vfd->dev_debug; long ret = -ENOTTY; @@ -3121,11 +3126,11 @@ static long __video_do_ioctl(struct file *file, write_only = _IOC_DIR(cmd) == _IOC_WRITE; if (info != &default_info) { - ret = info->func(ops, file, fh, arg); + ret = info->func(ops, file, vfh, arg); } else if (!ops->vidioc_default) { ret = -ENOTTY; } else { - ret = ops->vidioc_default(file, fh, + ret = ops->vidioc_default(file, vfh, v4l2_prio_check(vfd->prio, vfh->prio) >= 0, cmd, arg); } From 334f228752c2f8d3d4c74bc360527197819ddcc5 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:18 +0300 Subject: [PATCH 00536/11391] media: allegro: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. While at it remove the only left user of fh_to_channel() and remove the macro completely. Signed-off-by: Jacopo Mondi Reviewed-by: Michael Tretter Co-developed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- .../media/platform/allegro-dvt/allegro-core.c | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/allegro-core.c index 5e3b1f5d7206..510c3c9661d9 100644 --- a/drivers/media/platform/allegro-dvt/allegro-core.c +++ b/drivers/media/platform/allegro-dvt/allegro-core.c @@ -197,8 +197,6 @@ static const struct regmap_config allegro_sram_config = { .cache_type = REGCACHE_NONE, }; -#define fh_to_channel(__fh) container_of(__fh, struct allegro_channel, fh) - struct allegro_channel { struct allegro_dev *dev; struct v4l2_fh fh; @@ -3284,7 +3282,7 @@ static int allegro_enum_fmt_vid(struct file *file, void *fh, static int allegro_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) { - struct allegro_channel *channel = fh_to_channel(fh); + struct allegro_channel *channel = file_to_channel(file); f->fmt.pix.field = V4L2_FIELD_NONE; f->fmt.pix.width = channel->width; @@ -3326,7 +3324,7 @@ static int allegro_try_fmt_vid_cap(struct file *file, void *fh, static int allegro_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) { - struct allegro_channel *channel = fh_to_channel(fh); + struct allegro_channel *channel = file_to_channel(file); struct vb2_queue *vq; int err; @@ -3350,7 +3348,7 @@ static int allegro_s_fmt_vid_cap(struct file *file, void *fh, static int allegro_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *f) { - struct allegro_channel *channel = fh_to_channel(fh); + struct allegro_channel *channel = file_to_channel(file); f->fmt.pix.field = V4L2_FIELD_NONE; @@ -3397,7 +3395,7 @@ static int allegro_try_fmt_vid_out(struct file *file, void *fh, static int allegro_s_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *f) { - struct allegro_channel *channel = fh_to_channel(fh); + struct allegro_channel *channel = file_to_channel(file); int err; err = allegro_try_fmt_vid_out(file, fh, f); @@ -3438,7 +3436,7 @@ static int allegro_channel_cmd_start(struct allegro_channel *channel) static int allegro_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *cmd) { - struct allegro_channel *channel = fh_to_channel(fh); + struct allegro_channel *channel = file_to_channel(file); int err; err = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, cmd); @@ -3487,8 +3485,7 @@ static int allegro_enum_framesizes(struct file *file, void *fh, static int allegro_ioctl_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { - struct v4l2_fh *fh = file_to_v4l2_fh(file); - struct allegro_channel *channel = fh_to_channel(fh); + struct allegro_channel *channel = file_to_channel(file); int err; if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { @@ -3497,13 +3494,13 @@ static int allegro_ioctl_streamon(struct file *file, void *priv, return err; } - return v4l2_m2m_streamon(file, fh->m2m_ctx, type); + return v4l2_m2m_streamon(file, channel->fh.m2m_ctx, type); } static int allegro_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { - struct allegro_channel *channel = fh_to_channel(fh); + struct allegro_channel *channel = file_to_channel(file); struct v4l2_fract *timeperframe; if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) @@ -3520,7 +3517,7 @@ static int allegro_g_parm(struct file *file, void *fh, static int allegro_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { - struct allegro_channel *channel = fh_to_channel(fh); + struct allegro_channel *channel = file_to_channel(file); struct v4l2_fract *timeperframe; int div; From e732b1221dbdf8b54ab5c85f06012962001f2c48 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:19 +0300 Subject: [PATCH 00537/11391] media: meson-ge2d: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. Signed-off-by: Jacopo Mondi Signed-off-by: Hans Verkuil --- drivers/media/platform/amlogic/meson-ge2d/ge2d.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/amlogic/meson-ge2d/ge2d.c b/drivers/media/platform/amlogic/meson-ge2d/ge2d.c index b1b0b6535fb1..5744853a4003 100644 --- a/drivers/media/platform/amlogic/meson-ge2d/ge2d.c +++ b/drivers/media/platform/amlogic/meson-ge2d/ge2d.c @@ -457,7 +457,7 @@ static int vidioc_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f static int vidioc_g_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct ge2d_ctx *ctx = priv; + struct ge2d_ctx *ctx = file_to_ge2d_ctx(file); struct ge2d_frame *f; bool use_frame = false; @@ -507,7 +507,7 @@ static int vidioc_g_selection(struct file *file, void *priv, static int vidioc_s_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct ge2d_ctx *ctx = priv; + struct ge2d_ctx *ctx = file_to_ge2d_ctx(file); struct meson_ge2d *ge2d = ctx->ge2d; struct ge2d_frame *f; int ret = 0; @@ -574,8 +574,8 @@ static void vidioc_setup_cap_fmt(struct ge2d_ctx *ctx, struct v4l2_pix_format *f static int vidioc_try_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { + struct ge2d_ctx *ctx = file_to_ge2d_ctx(file); const struct ge2d_fmt *fmt = find_fmt(f); - struct ge2d_ctx *ctx = priv; struct v4l2_pix_format fmt_cap; vidioc_setup_cap_fmt(ctx, &fmt_cap); @@ -595,7 +595,7 @@ static int vidioc_try_fmt_cap(struct file *file, void *priv, struct v4l2_format static int vidioc_s_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct ge2d_ctx *ctx = priv; + struct ge2d_ctx *ctx = file_to_ge2d_ctx(file); struct meson_ge2d *ge2d = ctx->ge2d; struct vb2_queue *vq; struct ge2d_frame *frm; @@ -631,7 +631,7 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv, struct v4l2_format *f static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct ge2d_ctx *ctx = priv; + struct ge2d_ctx *ctx = file_to_ge2d_ctx(file); struct vb2_queue *vq; struct ge2d_frame *frm; @@ -670,7 +670,7 @@ static int vidioc_try_fmt_out(struct file *file, void *priv, struct v4l2_format static int vidioc_s_fmt_out(struct file *file, void *priv, struct v4l2_format *f) { - struct ge2d_ctx *ctx = priv; + struct ge2d_ctx *ctx = file_to_ge2d_ctx(file); struct meson_ge2d *ge2d = ctx->ge2d; struct vb2_queue *vq; struct ge2d_frame *frm, *frm_cap; From a7f90007c2495c29909be4ae05e006b6a24844bb Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:20 +0300 Subject: [PATCH 00538/11391] media: coda: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. Signed-off-by: Jacopo Mondi Signed-off-by: Hans Verkuil --- .../platform/chips-media/coda/coda-common.c | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/media/platform/chips-media/coda/coda-common.c b/drivers/media/platform/chips-media/coda/coda-common.c index 583759eed610..9a57b042d9fd 100644 --- a/drivers/media/platform/chips-media/coda/coda-common.c +++ b/drivers/media/platform/chips-media/coda/coda-common.c @@ -427,7 +427,7 @@ static struct vdoa_data *coda_get_vdoa_data(void) static int coda_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct coda_ctx *ctx = fh_to_ctx(priv); + struct coda_ctx *ctx = file_to_ctx(file); strscpy(cap->driver, CODA_NAME, sizeof(cap->driver)); strscpy(cap->card, coda_product_name(ctx->dev->devtype->product), @@ -447,7 +447,7 @@ static int coda_enum_fmt(struct file *file, void *priv, { struct video_device *vdev = video_devdata(file); const struct coda_video_device *cvd = to_coda_video_device(vdev); - struct coda_ctx *ctx = fh_to_ctx(priv); + struct coda_ctx *ctx = file_to_ctx(file); const u32 *formats; if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) @@ -497,7 +497,7 @@ static int coda_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct coda_q_data *q_data; - struct coda_ctx *ctx = fh_to_ctx(priv); + struct coda_ctx *ctx = file_to_ctx(file); q_data = get_q_data(ctx, f->type); if (!q_data) @@ -658,7 +658,7 @@ static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec, static int coda_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct coda_ctx *ctx = fh_to_ctx(priv); + struct coda_ctx *ctx = file_to_ctx(file); const struct coda_q_data *q_data_src; const struct coda_codec *codec; struct vb2_queue *src_vq; @@ -764,7 +764,7 @@ static void coda_set_default_colorspace(struct v4l2_pix_format *fmt) static int coda_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { - struct coda_ctx *ctx = fh_to_ctx(priv); + struct coda_ctx *ctx = file_to_ctx(file); struct coda_dev *dev = ctx->dev; const struct coda_q_data *q_data_dst; const struct coda_codec *codec; @@ -858,7 +858,7 @@ static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f, static int coda_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct coda_ctx *ctx = fh_to_ctx(priv); + struct coda_ctx *ctx = file_to_ctx(file); struct coda_q_data *q_data_src; const struct coda_codec *codec; struct v4l2_rect r; @@ -910,7 +910,7 @@ static int coda_s_fmt_vid_cap(struct file *file, void *priv, static int coda_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { - struct coda_ctx *ctx = fh_to_ctx(priv); + struct coda_ctx *ctx = file_to_ctx(file); const struct coda_codec *codec; struct v4l2_format f_cap; struct vb2_queue *dst_vq; @@ -966,7 +966,7 @@ static int coda_s_fmt_vid_out(struct file *file, void *priv, static int coda_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *rb) { - struct coda_ctx *ctx = fh_to_ctx(priv); + struct coda_ctx *ctx = file_to_ctx(file); int ret; ret = v4l2_m2m_reqbufs(file, ctx->fh.m2m_ctx, rb); @@ -986,7 +986,7 @@ static int coda_reqbufs(struct file *file, void *priv, static int coda_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct coda_ctx *ctx = fh_to_ctx(priv); + struct coda_ctx *ctx = file_to_ctx(file); if (ctx->inst_type == CODA_INST_DECODER && buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) @@ -997,7 +997,7 @@ static int coda_qbuf(struct file *file, void *priv, static int coda_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct coda_ctx *ctx = fh_to_ctx(priv); + struct coda_ctx *ctx = file_to_ctx(file); int ret; ret = v4l2_m2m_dqbuf(file, ctx->fh.m2m_ctx, buf); @@ -1025,7 +1025,7 @@ void coda_m2m_buf_done(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf, static int coda_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct coda_ctx *ctx = fh_to_ctx(fh); + struct coda_ctx *ctx = file_to_ctx(file); struct coda_q_data *q_data; struct v4l2_rect r, *rsel; @@ -1071,7 +1071,7 @@ static int coda_g_selection(struct file *file, void *fh, static int coda_s_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct coda_ctx *ctx = fh_to_ctx(fh); + struct coda_ctx *ctx = file_to_ctx(file); struct coda_q_data *q_data; switch (s->target) { @@ -1126,7 +1126,7 @@ static void coda_wake_up_capture_queue(struct coda_ctx *ctx) static int coda_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *ec) { - struct coda_ctx *ctx = fh_to_ctx(fh); + struct coda_ctx *ctx = file_to_ctx(file); struct vb2_v4l2_buffer *buf; int ret; @@ -1207,7 +1207,7 @@ static bool coda_mark_last_dst_buf(struct coda_ctx *ctx) static int coda_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dc) { - struct coda_ctx *ctx = fh_to_ctx(fh); + struct coda_ctx *ctx = file_to_ctx(file); struct coda_dev *dev = ctx->dev; struct vb2_v4l2_buffer *buf; struct vb2_queue *dst_vq; @@ -1286,7 +1286,7 @@ static int coda_decoder_cmd(struct file *file, void *fh, static int coda_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize) { - struct coda_ctx *ctx = fh_to_ctx(fh); + struct coda_ctx *ctx = file_to_ctx(file); struct coda_q_data *q_data_dst; const struct coda_codec *codec; @@ -1319,7 +1319,7 @@ static int coda_enum_framesizes(struct file *file, void *fh, static int coda_enum_frameintervals(struct file *file, void *fh, struct v4l2_frmivalenum *f) { - struct coda_ctx *ctx = fh_to_ctx(fh); + struct coda_ctx *ctx = file_to_ctx(file); struct coda_q_data *q_data; const struct coda_codec *codec; @@ -1358,7 +1358,7 @@ static int coda_enum_frameintervals(struct file *file, void *fh, static int coda_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { - struct coda_ctx *ctx = fh_to_ctx(fh); + struct coda_ctx *ctx = file_to_ctx(file); struct v4l2_fract *tpf; if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) @@ -1441,7 +1441,7 @@ static uint32_t coda_timeperframe_to_frate(struct v4l2_fract *timeperframe) static int coda_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { - struct coda_ctx *ctx = fh_to_ctx(fh); + struct coda_ctx *ctx = file_to_ctx(file); struct v4l2_fract *tpf; if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) From d0169457bc76e1220531356c574732a1124ee9e3 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:21 +0300 Subject: [PATCH 00539/11391] media: wave5: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. Signed-off-by: Jacopo Mondi Signed-off-by: Hans Verkuil --- .../platform/chips-media/wave5/wave5-helper.c | 2 +- .../chips-media/wave5/wave5-vpu-dec.c | 18 +++++++------- .../chips-media/wave5/wave5-vpu-enc.c | 24 +++++++++---------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/media/platform/chips-media/wave5/wave5-helper.c b/drivers/media/platform/chips-media/wave5/wave5-helper.c index 0bce62f0c039..f03ad9c0de22 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-helper.c +++ b/drivers/media/platform/chips-media/wave5/wave5-helper.c @@ -142,7 +142,7 @@ int wave5_vpu_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscr int wave5_vpu_g_fmt_out(struct file *file, void *fh, struct v4l2_format *f) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); int i; f->fmt.pix_mp.width = inst->src_fmt.width; diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c index 88eb933a5144..72af0faa3ef2 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c @@ -506,7 +506,7 @@ static int wave5_vpu_dec_enum_fmt_cap(struct file *file, void *fh, struct v4l2_f static int wave5_vpu_dec_try_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); struct dec_info *p_dec_info = &inst->codec_info->dec_info; const struct v4l2_frmsize_stepwise *frmsize; const struct vpu_format *vpu_fmt; @@ -547,7 +547,7 @@ static int wave5_vpu_dec_try_fmt_cap(struct file *file, void *fh, struct v4l2_fo static int wave5_vpu_dec_s_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); int i, ret; dev_dbg(inst->dev->dev, @@ -606,7 +606,7 @@ static int wave5_vpu_dec_s_fmt_cap(struct file *file, void *fh, struct v4l2_form static int wave5_vpu_dec_g_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); int i; f->fmt.pix_mp.width = inst->dst_fmt.width; @@ -630,7 +630,7 @@ static int wave5_vpu_dec_g_fmt_cap(struct file *file, void *fh, struct v4l2_form static int wave5_vpu_dec_enum_fmt_out(struct file *file, void *fh, struct v4l2_fmtdesc *f) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); const struct vpu_format *vpu_fmt; dev_dbg(inst->dev->dev, "%s: index: %u\n", __func__, f->index); @@ -647,7 +647,7 @@ static int wave5_vpu_dec_enum_fmt_out(struct file *file, void *fh, struct v4l2_f static int wave5_vpu_dec_try_fmt_out(struct file *file, void *fh, struct v4l2_format *f) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); const struct v4l2_frmsize_stepwise *frmsize; const struct vpu_format *vpu_fmt; int width, height; @@ -678,7 +678,7 @@ static int wave5_vpu_dec_try_fmt_out(struct file *file, void *fh, struct v4l2_fo static int wave5_vpu_dec_s_fmt_out(struct file *file, void *fh, struct v4l2_format *f) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); const struct vpu_format *vpu_fmt; int i, ret; @@ -727,7 +727,7 @@ static int wave5_vpu_dec_s_fmt_out(struct file *file, void *fh, struct v4l2_form static int wave5_vpu_dec_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); dev_dbg(inst->dev->dev, "%s: type: %u | target: %u\n", __func__, s->type, s->target); @@ -761,7 +761,7 @@ static int wave5_vpu_dec_g_selection(struct file *file, void *fh, struct v4l2_se static int wave5_vpu_dec_s_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -872,7 +872,7 @@ static int wave5_vpu_dec_start(struct vpu_instance *inst) static int wave5_vpu_dec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dc) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; int ret; diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c index 322c1498758a..279f23e1304a 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c @@ -360,7 +360,7 @@ static int wave5_vpu_enc_enum_framesizes(struct file *f, void *fh, struct v4l2_f static int wave5_vpu_enc_enum_fmt_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); const struct vpu_format *vpu_fmt; dev_dbg(inst->dev->dev, "%s: index: %u\n", __func__, f->index); @@ -377,7 +377,7 @@ static int wave5_vpu_enc_enum_fmt_cap(struct file *file, void *fh, struct v4l2_f static int wave5_vpu_enc_try_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); const struct v4l2_frmsize_stepwise *frmsize; const struct vpu_format *vpu_fmt; int width, height; @@ -411,7 +411,7 @@ static int wave5_vpu_enc_try_fmt_cap(struct file *file, void *fh, struct v4l2_fo static int wave5_vpu_enc_s_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); int i, ret; dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n", @@ -445,7 +445,7 @@ static int wave5_vpu_enc_s_fmt_cap(struct file *file, void *fh, struct v4l2_form static int wave5_vpu_enc_g_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); int i; f->fmt.pix_mp.width = inst->dst_fmt.width; @@ -469,7 +469,7 @@ static int wave5_vpu_enc_g_fmt_cap(struct file *file, void *fh, struct v4l2_form static int wave5_vpu_enc_enum_fmt_out(struct file *file, void *fh, struct v4l2_fmtdesc *f) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); const struct vpu_format *vpu_fmt; dev_dbg(inst->dev->dev, "%s: index: %u\n", __func__, f->index); @@ -486,7 +486,7 @@ static int wave5_vpu_enc_enum_fmt_out(struct file *file, void *fh, struct v4l2_f static int wave5_vpu_enc_try_fmt_out(struct file *file, void *fh, struct v4l2_format *f) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); const struct v4l2_frmsize_stepwise *frmsize; const struct vpu_format *vpu_fmt; int width, height; @@ -515,7 +515,7 @@ static int wave5_vpu_enc_try_fmt_out(struct file *file, void *fh, struct v4l2_fo static int wave5_vpu_enc_s_fmt_out(struct file *file, void *fh, struct v4l2_format *f) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); const struct vpu_format *vpu_fmt; const struct v4l2_format_info *info; int i, ret; @@ -576,7 +576,7 @@ static int wave5_vpu_enc_s_fmt_out(struct file *file, void *fh, struct v4l2_form static int wave5_vpu_enc_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); dev_dbg(inst->dev->dev, "%s: type: %u | target: %u\n", __func__, s->type, s->target); @@ -605,7 +605,7 @@ static int wave5_vpu_enc_g_selection(struct file *file, void *fh, struct v4l2_se static int wave5_vpu_enc_s_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) return -EINVAL; @@ -628,7 +628,7 @@ static int wave5_vpu_enc_s_selection(struct file *file, void *fh, struct v4l2_se static int wave5_vpu_enc_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *ec) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; int ret; @@ -661,7 +661,7 @@ static int wave5_vpu_enc_encoder_cmd(struct file *file, void *fh, struct v4l2_en static int wave5_vpu_enc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, a->type); @@ -681,7 +681,7 @@ static int wave5_vpu_enc_g_parm(struct file *file, void *fh, struct v4l2_streamp static int wave5_vpu_enc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, a->type); From 94f55f5eead078a499e401759a36b7e2c12f4a48 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:22 +0300 Subject: [PATCH 00540/11391] media: m2m-deinterlace: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. Signed-off-by: Jacopo Mondi Signed-off-by: Hans Verkuil --- drivers/media/platform/m2m-deinterlace.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c index 51c2f206cb1f..e07e57d4206b 100644 --- a/drivers/media/platform/m2m-deinterlace.c +++ b/drivers/media/platform/m2m-deinterlace.c @@ -517,13 +517,13 @@ static int vidioc_g_fmt(struct deinterlace_ctx *ctx, struct v4l2_format *f) static int vidioc_g_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { - return vidioc_g_fmt(priv, f); + return vidioc_g_fmt(file_to_ctx(file), f); } static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - return vidioc_g_fmt(priv, f); + return vidioc_g_fmt(file_to_ctx(file), f); } static int vidioc_try_fmt(struct v4l2_format *f, struct deinterlace_fmt *fmt) @@ -544,8 +544,8 @@ static int vidioc_try_fmt(struct v4l2_format *f, struct deinterlace_fmt *fmt) static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { + struct deinterlace_ctx *ctx = file_to_ctx(file); struct deinterlace_fmt *fmt; - struct deinterlace_ctx *ctx = priv; fmt = find_format(f); if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) @@ -638,20 +638,20 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, ret = vidioc_try_fmt_vid_cap(file, priv, f); if (ret) return ret; - return vidioc_s_fmt(priv, f); + return vidioc_s_fmt(file_to_ctx(file), f); } static int vidioc_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { - struct deinterlace_ctx *ctx = priv; + struct deinterlace_ctx *ctx = file_to_ctx(file); int ret; ret = vidioc_try_fmt_vid_out(file, priv, f); if (ret) return ret; - ret = vidioc_s_fmt(priv, f); + ret = vidioc_s_fmt(ctx, f); if (!ret) ctx->colorspace = f->fmt.pix.colorspace; @@ -661,8 +661,8 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv, static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { + struct deinterlace_ctx *ctx = file_to_ctx(file); struct deinterlace_q_data *s_q_data, *d_q_data; - struct deinterlace_ctx *ctx = priv; s_q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_OUTPUT); d_q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_CAPTURE); From 966579c979a9f9702e52a63eaf42a0612ef6feb4 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:23 +0300 Subject: [PATCH 00541/11391] media: mtk: jpeg: Access v4l2_fh from file->private_data The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. Signed-off-by: Jacopo Mondi Co-developed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- .../platform/mediatek/jpeg/mtk_jpeg_core.c | 29 ++++++++----------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c index de15d6f0b490..6268d651bdcf 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c @@ -119,14 +119,9 @@ static inline struct mtk_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl) return container_of(ctrl->handler, struct mtk_jpeg_ctx, ctrl_hdl); } -static inline struct mtk_jpeg_ctx *mtk_jpeg_fh_to_ctx(struct v4l2_fh *fh) -{ - return container_of(fh, struct mtk_jpeg_ctx, fh); -} - static inline struct mtk_jpeg_ctx *mtk_jpeg_file_to_ctx(struct file *filp) { - return mtk_jpeg_fh_to_ctx(file_to_v4l2_fh(filp)); + return container_of(file_to_v4l2_fh(filp), struct mtk_jpeg_ctx, fh); } static inline struct mtk_jpeg_src_buf *mtk_jpeg_vb2_to_srcbuf( @@ -217,7 +212,7 @@ static int mtk_jpeg_enum_fmt(struct mtk_jpeg_fmt *mtk_jpeg_formats, int n, static int mtk_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); + struct mtk_jpeg_ctx *ctx = mtk_jpeg_file_to_ctx(file); struct mtk_jpeg_dev *jpeg = ctx->jpeg; return mtk_jpeg_enum_fmt(jpeg->variant->formats, @@ -228,7 +223,7 @@ static int mtk_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, static int mtk_jpeg_enum_fmt_vid_out(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); + struct mtk_jpeg_ctx *ctx = mtk_jpeg_file_to_ctx(file); struct mtk_jpeg_dev *jpeg = ctx->jpeg; return mtk_jpeg_enum_fmt(jpeg->variant->formats, @@ -310,7 +305,7 @@ static int mtk_jpeg_g_fmt_vid_mplane(struct file *file, void *priv, struct vb2_queue *vq; struct mtk_jpeg_q_data *q_data = NULL; struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); + struct mtk_jpeg_ctx *ctx = mtk_jpeg_file_to_ctx(file); struct mtk_jpeg_dev *jpeg = ctx->jpeg; int i; @@ -356,7 +351,7 @@ static int mtk_jpeg_g_fmt_vid_mplane(struct file *file, void *priv, static int mtk_jpeg_try_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f) { - struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); + struct mtk_jpeg_ctx *ctx = mtk_jpeg_file_to_ctx(file); struct mtk_jpeg_dev *jpeg = ctx->jpeg; struct mtk_jpeg_fmt *fmt; @@ -385,7 +380,7 @@ static int mtk_jpeg_try_fmt_vid_cap_mplane(struct file *file, void *priv, static int mtk_jpeg_try_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f) { - struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); + struct mtk_jpeg_ctx *ctx = mtk_jpeg_file_to_ctx(file); struct mtk_jpeg_dev *jpeg = ctx->jpeg; struct mtk_jpeg_fmt *fmt; @@ -475,7 +470,7 @@ static int mtk_jpeg_s_fmt_vid_out_mplane(struct file *file, void *priv, if (ret) return ret; - return mtk_jpeg_s_fmt_mplane(mtk_jpeg_fh_to_ctx(priv), f, + return mtk_jpeg_s_fmt_mplane(mtk_jpeg_file_to_ctx(file), f, MTK_JPEG_FMT_FLAG_OUTPUT); } @@ -488,7 +483,7 @@ static int mtk_jpeg_s_fmt_vid_cap_mplane(struct file *file, void *priv, if (ret) return ret; - return mtk_jpeg_s_fmt_mplane(mtk_jpeg_fh_to_ctx(priv), f, + return mtk_jpeg_s_fmt_mplane(mtk_jpeg_file_to_ctx(file), f, MTK_JPEG_FMT_FLAG_CAPTURE); } @@ -517,7 +512,7 @@ static int mtk_jpeg_subscribe_event(struct v4l2_fh *fh, static int mtk_jpeg_enc_g_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); + struct mtk_jpeg_ctx *ctx = mtk_jpeg_file_to_ctx(file); if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) return -EINVAL; @@ -542,7 +537,7 @@ static int mtk_jpeg_enc_g_selection(struct file *file, void *priv, static int mtk_jpeg_dec_g_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); + struct mtk_jpeg_ctx *ctx = mtk_jpeg_file_to_ctx(file); if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -571,7 +566,7 @@ static int mtk_jpeg_dec_g_selection(struct file *file, void *priv, static int mtk_jpeg_enc_s_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); + struct mtk_jpeg_ctx *ctx = mtk_jpeg_file_to_ctx(file); if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) return -EINVAL; @@ -594,7 +589,7 @@ static int mtk_jpeg_enc_s_selection(struct file *file, void *priv, static int mtk_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { struct v4l2_fh *fh = file_to_v4l2_fh(file); - struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); + struct mtk_jpeg_ctx *ctx = mtk_jpeg_file_to_ctx(file); struct vb2_queue *vq; struct vb2_buffer *vb; struct mtk_jpeg_src_buf *jpeg_src_buf; From 59879e77deed1b31c698e60e96767099c73077e0 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:24 +0300 Subject: [PATCH 00542/11391] media: mtk_mdp_m2m: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. Signed-off-by: Jacopo Mondi Co-developed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- .../media/platform/mediatek/mdp/mtk_mdp_m2m.c | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c b/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c index 7e89a8443707..03c07948dfdd 100644 --- a/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c +++ b/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c @@ -348,14 +348,9 @@ static int mtk_mdp_try_crop(struct mtk_mdp_ctx *ctx, u32 type, return 0; } -static inline struct mtk_mdp_ctx *fh_to_ctx(struct v4l2_fh *fh) -{ - return container_of(fh, struct mtk_mdp_ctx, fh); -} - static inline struct mtk_mdp_ctx *file_to_ctx(struct file *filp) { - return fh_to_ctx(file_to_v4l2_fh(filp)); + return container_of(file_to_v4l2_fh(filp), struct mtk_mdp_ctx, fh); } static inline struct mtk_mdp_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl) @@ -594,7 +589,7 @@ static const struct vb2_ops mtk_mdp_m2m_qops = { static int mtk_mdp_m2m_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { - struct mtk_mdp_ctx *ctx = fh_to_ctx(fh); + struct mtk_mdp_ctx *ctx = file_to_ctx(file); struct mtk_mdp_dev *mdp = ctx->mdp_dev; strscpy(cap->driver, MTK_MDP_MODULE_NAME, sizeof(cap->driver)); @@ -632,7 +627,7 @@ static int mtk_mdp_m2m_enum_fmt_vid_out(struct file *file, void *priv, static int mtk_mdp_m2m_g_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { - struct mtk_mdp_ctx *ctx = fh_to_ctx(fh); + struct mtk_mdp_ctx *ctx = file_to_ctx(file); struct mtk_mdp_frame *frame; struct v4l2_pix_format_mplane *pix_mp; int i; @@ -671,7 +666,7 @@ static int mtk_mdp_m2m_g_fmt_mplane(struct file *file, void *fh, static int mtk_mdp_m2m_try_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { - struct mtk_mdp_ctx *ctx = fh_to_ctx(fh); + struct mtk_mdp_ctx *ctx = file_to_ctx(file); if (!mtk_mdp_try_fmt_mplane(ctx, f)) return -EINVAL; @@ -681,7 +676,7 @@ static int mtk_mdp_m2m_try_fmt_mplane(struct file *file, void *fh, static int mtk_mdp_m2m_s_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { - struct mtk_mdp_ctx *ctx = fh_to_ctx(fh); + struct mtk_mdp_ctx *ctx = file_to_ctx(file); struct vb2_queue *vq; struct mtk_mdp_frame *frame; struct v4l2_pix_format_mplane *pix_mp; @@ -727,7 +722,7 @@ static int mtk_mdp_m2m_s_fmt_mplane(struct file *file, void *fh, static int mtk_mdp_m2m_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *reqbufs) { - struct mtk_mdp_ctx *ctx = fh_to_ctx(fh); + struct mtk_mdp_ctx *ctx = file_to_ctx(file); return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); } @@ -735,7 +730,7 @@ static int mtk_mdp_m2m_reqbufs(struct file *file, void *fh, static int mtk_mdp_m2m_streamon(struct file *file, void *fh, enum v4l2_buf_type type) { - struct mtk_mdp_ctx *ctx = fh_to_ctx(fh); + struct mtk_mdp_ctx *ctx = file_to_ctx(file); int ret; if (!mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_VPU_INIT)) { @@ -773,8 +768,8 @@ static inline bool mtk_mdp_is_target_crop(u32 target) static int mtk_mdp_m2m_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { + struct mtk_mdp_ctx *ctx = file_to_ctx(file); struct mtk_mdp_frame *frame; - struct mtk_mdp_ctx *ctx = fh_to_ctx(fh); bool valid = false; if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { @@ -840,8 +835,8 @@ static int mtk_mdp_check_scaler_ratio(struct mtk_mdp_variant *var, int src_w, static int mtk_mdp_m2m_s_selection(struct file *file, void *fh, struct v4l2_selection *s) { + struct mtk_mdp_ctx *ctx = file_to_ctx(file); struct mtk_mdp_frame *frame; - struct mtk_mdp_ctx *ctx = fh_to_ctx(fh); struct v4l2_rect new_r; struct mtk_mdp_variant *variant = ctx->mdp_dev->variant; int ret; From 698c41290e8dafc5a9089f0bec147a7dcd0c6849 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:25 +0300 Subject: [PATCH 00543/11391] media: mtk: mdp3: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. Signed-off-by: Jacopo Mondi Co-developed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- .../platform/mediatek/mdp3/mtk-mdp3-m2m.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c index e68ae19d71a9..9ef956b565a7 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c @@ -10,14 +10,9 @@ #include #include "mtk-mdp3-m2m.h" -static inline struct mdp_m2m_ctx *fh_to_ctx(struct v4l2_fh *fh) -{ - return container_of(fh, struct mdp_m2m_ctx, fh); -} - static inline struct mdp_m2m_ctx *file_to_ctx(struct file *filp) { - return fh_to_ctx(file_to_v4l2_fh(filp)); + return container_of(file_to_v4l2_fh(filp), struct mdp_m2m_ctx, fh); } static inline struct mdp_m2m_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl) @@ -290,7 +285,7 @@ static int mdp_m2m_querycap(struct file *file, void *fh, static int mdp_m2m_enum_fmt_mplane(struct file *file, void *fh, struct v4l2_fmtdesc *f) { - struct mdp_m2m_ctx *ctx = fh_to_ctx(fh); + struct mdp_m2m_ctx *ctx = file_to_ctx(file); return mdp_enum_fmt_mplane(ctx->mdp_dev, f); } @@ -298,7 +293,7 @@ static int mdp_m2m_enum_fmt_mplane(struct file *file, void *fh, static int mdp_m2m_g_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { - struct mdp_m2m_ctx *ctx = fh_to_ctx(fh); + struct mdp_m2m_ctx *ctx = file_to_ctx(file); struct mdp_frame *frame; struct v4l2_pix_format_mplane *pix_mp; @@ -316,7 +311,7 @@ static int mdp_m2m_g_fmt_mplane(struct file *file, void *fh, static int mdp_m2m_s_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { - struct mdp_m2m_ctx *ctx = fh_to_ctx(fh); + struct mdp_m2m_ctx *ctx = file_to_ctx(file); struct mdp_frame *frame = ctx_get_frame(ctx, f->type); struct mdp_frame *capture; const struct mdp_format *fmt; @@ -359,7 +354,7 @@ static int mdp_m2m_s_fmt_mplane(struct file *file, void *fh, static int mdp_m2m_try_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { - struct mdp_m2m_ctx *ctx = fh_to_ctx(fh); + struct mdp_m2m_ctx *ctx = file_to_ctx(file); if (!mdp_try_fmt_mplane(ctx->mdp_dev, f, &ctx->curr_param, ctx->id)) return -EINVAL; @@ -370,7 +365,7 @@ static int mdp_m2m_try_fmt_mplane(struct file *file, void *fh, static int mdp_m2m_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct mdp_m2m_ctx *ctx = fh_to_ctx(fh); + struct mdp_m2m_ctx *ctx = file_to_ctx(file); struct mdp_frame *frame; bool valid = false; @@ -422,7 +417,7 @@ static int mdp_m2m_g_selection(struct file *file, void *fh, static int mdp_m2m_s_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct mdp_m2m_ctx *ctx = fh_to_ctx(fh); + struct mdp_m2m_ctx *ctx = file_to_ctx(file); struct mdp_frame *frame = ctx_get_frame(ctx, s->type); struct mdp_frame *capture; struct v4l2_rect r; From 50363fc1feb87f48163bfa1cd431b46db917d0ad Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:26 +0300 Subject: [PATCH 00544/11391] media: mtk: vcodec: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. While at modify mtk_vcodec_enc_get_chip_name() to accept a ctx instead of a raw void *. Signed-off-by: Jacopo Mondi Co-developed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- .../mediatek/vcodec/decoder/mtk_vcodec_dec.c | 36 +++++++++--------- .../mediatek/vcodec/encoder/mtk_vcodec_enc.c | 37 +++++++++---------- .../vcodec/encoder/mtk_vcodec_enc_drv.h | 7 +--- 3 files changed, 37 insertions(+), 43 deletions(-) diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.c index 98838217b97d..d691bd533103 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.c @@ -87,7 +87,7 @@ static int stateful_try_decoder_cmd(struct file *file, void *priv, struct v4l2_d static int stateful_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) { - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); struct vb2_queue *src_vq, *dst_vq; int ret; @@ -132,7 +132,7 @@ static int stateless_try_decoder_cmd(struct file *file, void *priv, struct v4l2_ static int stateless_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) { - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); int ret; ret = v4l2_m2m_ioctl_stateless_try_decoder_cmd(file, priv, cmd); @@ -158,7 +158,7 @@ static int stateless_decoder_cmd(struct file *file, void *priv, struct v4l2_deco static int vidioc_try_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) { - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); if (ctx->dev->vdec_pdata->uses_stateless_api) return stateless_try_decoder_cmd(file, priv, cmd); @@ -168,7 +168,7 @@ static int vidioc_try_decoder_cmd(struct file *file, void *priv, struct v4l2_dec static int vidioc_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) { - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); if (ctx->dev->vdec_pdata->uses_stateless_api) return stateless_decoder_cmd(file, priv, cmd); @@ -233,7 +233,7 @@ void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_dec_ctx *ctx) static int vidioc_vdec_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); if (ctx->state == MTK_STATE_ABORT) { mtk_v4l2_vdec_err(ctx, "[%d] Call on QBUF after unrecoverable error", ctx->id); @@ -246,7 +246,7 @@ static int vidioc_vdec_qbuf(struct file *file, void *priv, static int vidioc_vdec_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); if (ctx->state == MTK_STATE_ABORT) { mtk_v4l2_vdec_err(ctx, "[%d] Call on DQBUF after unrecoverable error", ctx->id); @@ -259,7 +259,7 @@ static int vidioc_vdec_dqbuf(struct file *file, void *priv, static int vidioc_vdec_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); struct device *dev = &ctx->dev->plat_dev->dev; strscpy(cap->driver, dev->driver->name, sizeof(cap->driver)); @@ -354,7 +354,7 @@ static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f) { const struct mtk_video_fmt *fmt; - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata; fmt = mtk_vdec_find_format(f, dec_pdata); @@ -372,7 +372,7 @@ static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, { struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; const struct mtk_video_fmt *fmt; - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata; fmt = mtk_vdec_find_format(f, dec_pdata); @@ -393,7 +393,7 @@ static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, static int vidioc_vdec_g_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); struct mtk_q_data *q_data; if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) @@ -442,7 +442,7 @@ static int vidioc_vdec_g_selection(struct file *file, void *priv, static int vidioc_vdec_s_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -464,7 +464,7 @@ static int vidioc_vdec_s_selection(struct file *file, void *priv, static int vidioc_vdec_s_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); struct v4l2_pix_format_mplane *pix_mp; struct mtk_q_data *q_data; int ret = 0; @@ -594,7 +594,7 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize) { int i = 0; - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata; if (fsize->index != 0) @@ -623,10 +623,10 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, return -EINVAL; } -static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, void *priv, +static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f, bool output_queue) { - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata; const struct mtk_video_fmt *fmt; int i, j = 0; @@ -660,19 +660,19 @@ static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, void *priv, static int vidioc_vdec_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - return vidioc_enum_fmt(f, priv, false); + return vidioc_enum_fmt(file, f, false); } static int vidioc_vdec_enum_fmt_vid_out(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - return vidioc_enum_fmt(f, priv, true); + return vidioc_enum_fmt(file, f, true); } static int vidioc_vdec_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; struct vb2_queue *vq; struct mtk_q_data *q_data; diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c index a01dc25a7699..d815e962ab89 100644 --- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c +++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c @@ -159,7 +159,7 @@ static int vidioc_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize) { const struct mtk_video_fmt *fmt; - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(fh); + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); if (fsize->index != 0) return -EINVAL; @@ -183,7 +183,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { const struct mtk_vcodec_enc_pdata *pdata = - fh_to_enc_ctx(priv)->dev->venc_pdata; + file_to_enc_ctx(file)->dev->venc_pdata; return vidioc_enum_fmt(f, pdata->capture_formats, pdata->num_capture_formats); @@ -193,15 +193,14 @@ static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, struct v4l2_fmtdesc *f) { const struct mtk_vcodec_enc_pdata *pdata = - fh_to_enc_ctx(priv)->dev->venc_pdata; + file_to_enc_ctx(file)->dev->venc_pdata; return vidioc_enum_fmt(f, pdata->output_formats, pdata->num_output_formats); } -static int mtk_vcodec_enc_get_chip_name(void *priv) +static int mtk_vcodec_enc_get_chip_name(struct mtk_vcodec_enc_ctx *ctx) { - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(priv); struct device *dev = &ctx->dev->plat_dev->dev; if (of_device_is_compatible(dev->of_node, "mediatek,mt8173-vcodec-enc")) @@ -221,9 +220,9 @@ static int mtk_vcodec_enc_get_chip_name(void *priv) static int vidioc_venc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(priv); + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); struct device *dev = &ctx->dev->plat_dev->dev; - int platform_name = mtk_vcodec_enc_get_chip_name(priv); + int platform_name = mtk_vcodec_enc_get_chip_name(ctx); strscpy(cap->driver, dev->driver->name, sizeof(cap->driver)); snprintf(cap->card, sizeof(cap->card), "MT%d video encoder", platform_name); @@ -234,7 +233,7 @@ static int vidioc_venc_querycap(struct file *file, void *priv, static int vidioc_venc_s_parm(struct file *file, void *priv, struct v4l2_streamparm *a) { - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(priv); + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); struct v4l2_fract *timeperframe = &a->parm.output.timeperframe; if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) @@ -257,7 +256,7 @@ static int vidioc_venc_s_parm(struct file *file, void *priv, static int vidioc_venc_g_parm(struct file *file, void *priv, struct v4l2_streamparm *a) { - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(priv); + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) return -EINVAL; @@ -414,7 +413,7 @@ static void mtk_venc_set_param(struct mtk_vcodec_enc_ctx *ctx, static int vidioc_venc_s_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(priv); + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); const struct mtk_vcodec_enc_pdata *pdata = ctx->dev->venc_pdata; struct vb2_queue *vq; struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, f->type); @@ -469,7 +468,7 @@ static int vidioc_venc_s_fmt_cap(struct file *file, void *priv, static int vidioc_venc_s_fmt_out(struct file *file, void *priv, struct v4l2_format *f) { - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(priv); + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); const struct mtk_vcodec_enc_pdata *pdata = ctx->dev->venc_pdata; struct vb2_queue *vq; struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, f->type); @@ -524,7 +523,7 @@ static int vidioc_venc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(priv); + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); struct vb2_queue *vq; struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, f->type); int i; @@ -557,7 +556,7 @@ static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f) { const struct mtk_video_fmt *fmt; - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(priv); + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); const struct mtk_vcodec_enc_pdata *pdata = ctx->dev->venc_pdata; fmt = mtk_venc_find_format(f->fmt.pix.pixelformat, pdata); @@ -579,7 +578,7 @@ static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f) { const struct mtk_video_fmt *fmt; - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(priv); + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); const struct mtk_vcodec_enc_pdata *pdata = ctx->dev->venc_pdata; fmt = mtk_venc_find_format(f->fmt.pix.pixelformat, pdata); @@ -600,7 +599,7 @@ static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, static int vidioc_venc_g_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(priv); + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, s->type); if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) @@ -630,7 +629,7 @@ static int vidioc_venc_g_selection(struct file *file, void *priv, static int vidioc_venc_s_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(priv); + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, s->type); if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) @@ -655,7 +654,7 @@ static int vidioc_venc_s_selection(struct file *file, void *priv, static int vidioc_venc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(priv); + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); if (ctx->state == MTK_STATE_ABORT) { mtk_v4l2_venc_err(ctx, "[%d] Call on QBUF after unrecoverable error", @@ -669,7 +668,7 @@ static int vidioc_venc_qbuf(struct file *file, void *priv, static int vidioc_venc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(priv); + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); int ret; if (ctx->state == MTK_STATE_ABORT) { @@ -707,7 +706,7 @@ static int vidioc_venc_dqbuf(struct file *file, void *priv, static int vidioc_encoder_cmd(struct file *file, void *priv, struct v4l2_encoder_cmd *cmd) { - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(priv); + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); struct vb2_queue *src_vq, *dst_vq; int ret; diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.h b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.h index a4fe2f453d8f..5b304a551236 100644 --- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.h +++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.h @@ -217,14 +217,9 @@ struct mtk_vcodec_enc_dev { struct mtk_vcodec_dbgfs dbgfs; }; -static inline struct mtk_vcodec_enc_ctx *fh_to_enc_ctx(struct v4l2_fh *fh) -{ - return container_of(fh, struct mtk_vcodec_enc_ctx, fh); -} - static inline struct mtk_vcodec_enc_ctx *file_to_enc_ctx(struct file *filp) { - return fh_to_enc_ctx(file_to_v4l2_fh(filp)); + return container_of(file_to_v4l2_fh(filp), struct mtk_vcodec_enc_ctx, fh); } static inline struct mtk_vcodec_enc_ctx *ctrl_to_enc_ctx(struct v4l2_ctrl *ctrl) From 25fe47cdc9098760b493a7aa3e032eb0f1c14f7a Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:27 +0300 Subject: [PATCH 00545/11391] media: tegra-vde: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. Signed-off-by: Jacopo Mondi Signed-off-by: Hans Verkuil --- .../media/platform/nvidia/tegra-vde/v4l2.c | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/media/platform/nvidia/tegra-vde/v4l2.c b/drivers/media/platform/nvidia/tegra-vde/v4l2.c index 0c50f4ff82e0..d94978ae2baf 100644 --- a/drivers/media/platform/nvidia/tegra-vde/v4l2.c +++ b/drivers/media/platform/nvidia/tegra-vde/v4l2.c @@ -46,9 +46,9 @@ static const struct v4l2_ctrl_config ctrl_cfgs[] = { }, }; -static inline struct tegra_ctx *fh_to_tegra_ctx(struct v4l2_fh *fh) +static inline struct tegra_ctx *file_to_tegra_ctx(struct file *file) { - return container_of(fh, struct tegra_ctx, fh); + return container_of(file_to_v4l2_fh(file), struct tegra_ctx, fh); } static void tegra_set_control_data(struct tegra_ctx *ctx, void *data, u32 id) @@ -506,7 +506,7 @@ static int tegra_querycap(struct file *file, void *priv, static int tegra_enum_decoded_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + struct tegra_ctx *ctx = file_to_tegra_ctx(file); if (WARN_ON(!ctx->coded_fmt_desc)) return -EINVAL; @@ -522,7 +522,7 @@ static int tegra_enum_decoded_fmt(struct file *file, void *priv, static int tegra_g_decoded_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + struct tegra_ctx *ctx = file_to_tegra_ctx(file); *f = ctx->decoded_fmt; return 0; @@ -531,8 +531,8 @@ static int tegra_g_decoded_fmt(struct file *file, void *priv, static int tegra_try_decoded_fmt(struct file *file, void *priv, struct v4l2_format *f) { + struct tegra_ctx *ctx = file_to_tegra_ctx(file); struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); const struct tegra_coded_fmt_desc *coded_desc; unsigned int i; @@ -571,7 +571,7 @@ static int tegra_try_decoded_fmt(struct file *file, void *priv, static int tegra_s_decoded_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + struct tegra_ctx *ctx = file_to_tegra_ctx(file); struct vb2_queue *vq; int err; @@ -593,7 +593,7 @@ static int tegra_s_decoded_fmt(struct file *file, void *priv, static int tegra_enum_coded_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + struct tegra_ctx *ctx = file_to_tegra_ctx(file); const struct tegra_vde_soc *soc = ctx->vde->soc; if (f->index >= soc->num_coded_fmts) @@ -607,7 +607,7 @@ static int tegra_enum_coded_fmt(struct file *file, void *priv, static int tegra_g_coded_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + struct tegra_ctx *ctx = file_to_tegra_ctx(file); *f = ctx->coded_fmt; return 0; @@ -631,7 +631,7 @@ static int tegra_try_coded_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + struct tegra_ctx *ctx = file_to_tegra_ctx(file); const struct tegra_vde_soc *soc = ctx->vde->soc; int size = pix_mp->plane_fmt[0].sizeimage; const struct tegra_coded_fmt_desc *desc; @@ -656,7 +656,7 @@ static int tegra_try_coded_fmt(struct file *file, void *priv, static int tegra_s_coded_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + struct tegra_ctx *ctx = file_to_tegra_ctx(file); struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; const struct tegra_coded_fmt_desc *desc; struct vb2_queue *peer_vq, *vq; @@ -718,7 +718,7 @@ static int tegra_s_coded_fmt(struct file *file, void *priv, static int tegra_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize) { - struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + struct tegra_ctx *ctx = file_to_tegra_ctx(file); const struct tegra_coded_fmt_desc *fmt; if (fsize->index) @@ -852,8 +852,8 @@ static int tegra_open(struct file *file) static int tegra_release(struct file *file) { + struct tegra_ctx *ctx = file_to_tegra_ctx(file); struct v4l2_fh *fh = file_to_v4l2_fh(file); - struct tegra_ctx *ctx = fh_to_tegra_ctx(fh); struct tegra_vde *vde = ctx->vde; v4l2_fh_del(fh, file); From 8be69363d852a355323a715fdfb558c6ea132cca Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:28 +0300 Subject: [PATCH 00546/11391] media: imx-jpeg: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. Signed-off-by: Jacopo Mondi Reviewed-by: Ming Qian Co-developed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Reviewed-by: Frank Li Signed-off-by: Hans Verkuil --- .../media/platform/nxp/imx-jpeg/mxc-jpeg.c | 35 ++++++++----------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c index a34e644b2cb1..df3ccdf767ba 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c @@ -644,14 +644,9 @@ static void print_mxc_buf(struct mxc_jpeg_dev *jpeg, struct vb2_buffer *buf, } } -static inline struct mxc_jpeg_ctx *mxc_jpeg_fh_to_ctx(struct v4l2_fh *fh) -{ - return container_of(fh, struct mxc_jpeg_ctx, fh); -} - static inline struct mxc_jpeg_ctx *mxc_jpeg_file_to_ctx(struct file *filp) { - return mxc_jpeg_fh_to_ctx(file_to_v4l2_fh(filp)); + return container_of(file_to_v4l2_fh(filp), struct mxc_jpeg_ctx, fh); } static int enum_fmt(const struct mxc_jpeg_fmt *mxc_formats, int n, @@ -1610,7 +1605,7 @@ static int mxc_jpeg_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) { struct v4l2_fh *fh = file_to_v4l2_fh(file); - struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh); + struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file); unsigned long flags; int ret; @@ -1643,7 +1638,7 @@ static int mxc_jpeg_encoder_cmd(struct file *file, void *priv, struct v4l2_encoder_cmd *cmd) { struct v4l2_fh *fh = file_to_v4l2_fh(file); - struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh); + struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file); unsigned long flags; int ret; @@ -2260,7 +2255,7 @@ static int mxc_jpeg_querycap(struct file *file, void *priv, static int mxc_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv); + struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file); struct mxc_jpeg_q_data *q_data = mxc_jpeg_get_q_data(ctx, f->type); if (ctx->mxc_jpeg->mode == MXC_JPEG_ENCODE) { @@ -2300,7 +2295,7 @@ static int mxc_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, static int mxc_jpeg_enum_fmt_vid_out(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv); + struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file); u32 type = ctx->mxc_jpeg->mode == MXC_JPEG_DECODE ? MXC_JPEG_FMT_TYPE_ENC : MXC_JPEG_FMT_TYPE_RAW; int ret; @@ -2441,7 +2436,7 @@ static int mxc_jpeg_try_fmt(struct v4l2_format *f, static int mxc_jpeg_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv); + struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file); struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg; struct device *dev = jpeg->dev; struct mxc_jpeg_q_data tmp_q; @@ -2460,7 +2455,7 @@ static int mxc_jpeg_try_fmt_vid_cap(struct file *file, void *priv, static int mxc_jpeg_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { - struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv); + struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file); struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg; struct device *dev = jpeg->dev; struct mxc_jpeg_q_data tmp_q; @@ -2512,20 +2507,20 @@ static int mxc_jpeg_s_fmt(struct mxc_jpeg_ctx *ctx, static int mxc_jpeg_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - return mxc_jpeg_s_fmt(mxc_jpeg_fh_to_ctx(priv), f); + return mxc_jpeg_s_fmt(mxc_jpeg_file_to_ctx(file), f); } static int mxc_jpeg_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { int ret; - struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv); + struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file); struct vb2_queue *dst_vq; struct mxc_jpeg_q_data *q_data_cap; enum v4l2_buf_type cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; struct v4l2_format fc; - ret = mxc_jpeg_s_fmt(mxc_jpeg_fh_to_ctx(priv), f); + ret = mxc_jpeg_s_fmt(ctx, f); if (ret) return ret; @@ -2554,7 +2549,7 @@ static int mxc_jpeg_s_fmt_vid_out(struct file *file, void *priv, static int mxc_jpeg_g_fmt_vid(struct file *file, void *priv, struct v4l2_format *f) { - struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv); + struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file); struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg; struct device *dev = jpeg->dev; struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; @@ -2592,7 +2587,7 @@ static int mxc_jpeg_g_fmt_vid(struct file *file, void *priv, static int mxc_jpeg_dec_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh); + struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file); struct mxc_jpeg_q_data *q_data_cap; if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) @@ -2621,7 +2616,7 @@ static int mxc_jpeg_dec_g_selection(struct file *file, void *fh, struct v4l2_sel static int mxc_jpeg_enc_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh); + struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file); struct mxc_jpeg_q_data *q_data_out; if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) @@ -2649,7 +2644,7 @@ static int mxc_jpeg_enc_g_selection(struct file *file, void *fh, struct v4l2_sel static int mxc_jpeg_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh); + struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file); if (ctx->mxc_jpeg->mode == MXC_JPEG_DECODE) return mxc_jpeg_dec_g_selection(file, fh, s); @@ -2659,7 +2654,7 @@ static int mxc_jpeg_g_selection(struct file *file, void *fh, struct v4l2_selecti static int mxc_jpeg_s_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh); + struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file); struct mxc_jpeg_q_data *q_data_out; if (ctx->mxc_jpeg->mode != MXC_JPEG_ENCODE) From f048bf7d755dc836c61ef38b905887b65dee79bd Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:29 +0300 Subject: [PATCH 00547/11391] media: imx-isi: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. Signed-off-by: Jacopo Mondi Co-developed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Reviewed-by: Frank Li Signed-off-by: Hans Verkuil --- .../media/platform/nxp/imx8-isi/imx8-isi-m2m.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c index 31298307c672..5501214cc6c0 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c @@ -74,14 +74,9 @@ to_isi_m2m_buffer(struct vb2_v4l2_buffer *buf) return container_of(buf, struct mxc_isi_m2m_buffer, buf.vb); } -static inline struct mxc_isi_m2m_ctx *to_isi_m2m_ctx(struct v4l2_fh *fh) -{ - return container_of(fh, struct mxc_isi_m2m_ctx, fh); -} - static inline struct mxc_isi_m2m_ctx *file_to_isi_m2m_ctx(struct file *filp) { - return to_isi_m2m_ctx(file_to_v4l2_fh(filp)); + return container_of(file_to_v4l2_fh(filp), struct mxc_isi_m2m_ctx, fh); } static inline struct mxc_isi_m2m_ctx_queue_data * @@ -432,7 +427,7 @@ static int mxc_isi_m2m_try_fmt_vid(struct file *file, void *fh, const enum mxc_isi_video_type type = f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ? MXC_ISI_VIDEO_M2M_OUT : MXC_ISI_VIDEO_M2M_CAP; - struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh); + struct mxc_isi_m2m_ctx *ctx = file_to_isi_m2m_ctx(file); __mxc_isi_m2m_try_fmt_vid(ctx, &f->fmt.pix_mp, type); @@ -442,7 +437,7 @@ static int mxc_isi_m2m_try_fmt_vid(struct file *file, void *fh, static int mxc_isi_m2m_g_fmt_vid(struct file *file, void *fh, struct v4l2_format *f) { - struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh); + struct mxc_isi_m2m_ctx *ctx = file_to_isi_m2m_ctx(file); const struct mxc_isi_m2m_ctx_queue_data *qdata = mxc_isi_m2m_ctx_qdata(ctx, f->type); @@ -457,7 +452,7 @@ static int mxc_isi_m2m_s_fmt_vid(struct file *file, void *fh, const enum mxc_isi_video_type type = f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ? MXC_ISI_VIDEO_M2M_OUT : MXC_ISI_VIDEO_M2M_CAP; - struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh); + struct mxc_isi_m2m_ctx *ctx = file_to_isi_m2m_ctx(file); struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; const struct mxc_isi_format_info *info; struct vb2_queue *vq; @@ -489,7 +484,7 @@ static int mxc_isi_m2m_s_fmt_vid(struct file *file, void *fh, static int mxc_isi_m2m_streamon(struct file *file, void *fh, enum v4l2_buf_type type) { - struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh); + struct mxc_isi_m2m_ctx *ctx = file_to_isi_m2m_ctx(file); struct mxc_isi_m2m_ctx_queue_data *q = mxc_isi_m2m_ctx_qdata(ctx, type); const struct v4l2_pix_format_mplane *out_pix = &ctx->queues.out.format; const struct v4l2_pix_format_mplane *cap_pix = &ctx->queues.cap.format; @@ -577,7 +572,7 @@ static int mxc_isi_m2m_streamon(struct file *file, void *fh, static int mxc_isi_m2m_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) { - struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh); + struct mxc_isi_m2m_ctx *ctx = file_to_isi_m2m_ctx(file); struct mxc_isi_m2m_ctx_queue_data *q = mxc_isi_m2m_ctx_qdata(ctx, type); struct mxc_isi_m2m *m2m = ctx->m2m; From cdc569967504fc1c9db7a1302e6d9ef4e4422553 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:30 +0300 Subject: [PATCH 00548/11391] media: nxp: mx2: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. Signed-off-by: Jacopo Mondi Signed-off-by: Hans Verkuil --- drivers/media/platform/nxp/mx2_emmaprp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/nxp/mx2_emmaprp.c b/drivers/media/platform/nxp/mx2_emmaprp.c index d23da93304bd..3aae8c0b690c 100644 --- a/drivers/media/platform/nxp/mx2_emmaprp.c +++ b/drivers/media/platform/nxp/mx2_emmaprp.c @@ -456,13 +456,13 @@ static int vidioc_g_fmt(struct emmaprp_ctx *ctx, struct v4l2_format *f) static int vidioc_g_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { - return vidioc_g_fmt(priv, f); + return vidioc_g_fmt(file_to_emmaprp_ctx(file), f); } static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - return vidioc_g_fmt(priv, f); + return vidioc_g_fmt(file_to_emmaprp_ctx(file), f); } static int vidioc_try_fmt(struct v4l2_format *f) @@ -502,8 +502,8 @@ static int vidioc_try_fmt(struct v4l2_format *f) static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { + struct emmaprp_ctx *ctx = file_to_emmaprp_ctx(file); struct emmaprp_fmt *fmt; - struct emmaprp_ctx *ctx = priv; fmt = find_format(f); if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) { @@ -519,8 +519,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, static int vidioc_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { + struct emmaprp_ctx *ctx = file_to_emmaprp_ctx(file); struct emmaprp_fmt *fmt; - struct emmaprp_ctx *ctx = priv; fmt = find_format(f); if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) { @@ -580,7 +580,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, if (ret) return ret; - return vidioc_s_fmt(priv, f); + return vidioc_s_fmt(file_to_emmaprp_ctx(file), f); } static int vidioc_s_fmt_vid_out(struct file *file, void *priv, @@ -592,7 +592,7 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv, if (ret) return ret; - return vidioc_s_fmt(priv, f); + return vidioc_s_fmt(file_to_emmaprp_ctx(file), f); } static const struct v4l2_ioctl_ops emmaprp_ioctl_ops = { From 8fbb206557ce7dd4f4881251d8c963421c5f064e Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:31 +0300 Subject: [PATCH 00549/11391] media: renesas: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. Signed-off-by: Jacopo Mondi Reviewed-by: Kieran Bingham Co-developed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/platform/renesas/rcar_fdp1.c | 13 ++++-------- drivers/media/platform/renesas/rcar_jpu.c | 23 +++++++++------------- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/drivers/media/platform/renesas/rcar_fdp1.c b/drivers/media/platform/renesas/rcar_fdp1.c index e2dba0e4f315..84c3901a2e5d 100644 --- a/drivers/media/platform/renesas/rcar_fdp1.c +++ b/drivers/media/platform/renesas/rcar_fdp1.c @@ -630,14 +630,9 @@ struct fdp1_ctx { struct fdp1_field_buffer *previous; }; -static inline struct fdp1_ctx *fh_to_ctx(struct v4l2_fh *fh) -{ - return container_of(fh, struct fdp1_ctx, fh); -} - static inline struct fdp1_ctx *file_to_ctx(struct file *filp) { - return fh_to_ctx(file_to_v4l2_fh(filp)); + return container_of(file_to_v4l2_fh(filp), struct fdp1_ctx, fh); } static struct fdp1_q_data *get_q_data(struct fdp1_ctx *ctx, @@ -1411,8 +1406,8 @@ static int fdp1_enum_fmt_vid_out(struct file *file, void *priv, static int fdp1_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { + struct fdp1_ctx *ctx = file_to_ctx(file); struct fdp1_q_data *q_data; - struct fdp1_ctx *ctx = fh_to_ctx(priv); if (!v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type)) return -EINVAL; @@ -1589,7 +1584,7 @@ static void fdp1_try_fmt_capture(struct fdp1_ctx *ctx, static int fdp1_try_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct fdp1_ctx *ctx = fh_to_ctx(priv); + struct fdp1_ctx *ctx = file_to_ctx(file); if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) fdp1_try_fmt_output(ctx, NULL, &f->fmt.pix_mp); @@ -1660,7 +1655,7 @@ static void fdp1_set_format(struct fdp1_ctx *ctx, static int fdp1_s_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct fdp1_ctx *ctx = fh_to_ctx(priv); + struct fdp1_ctx *ctx = file_to_ctx(file); struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; struct vb2_queue *vq = v4l2_m2m_get_vq(m2m_ctx, f->type); diff --git a/drivers/media/platform/renesas/rcar_jpu.c b/drivers/media/platform/renesas/rcar_jpu.c index 0b479dfa2917..9c70a74a2969 100644 --- a/drivers/media/platform/renesas/rcar_jpu.c +++ b/drivers/media/platform/renesas/rcar_jpu.c @@ -480,14 +480,9 @@ static struct jpu_ctx *ctrl_to_ctx(struct v4l2_ctrl *c) return container_of(c->handler, struct jpu_ctx, ctrl_handler); } -static struct jpu_ctx *fh_to_ctx(struct v4l2_fh *fh) -{ - return container_of(fh, struct jpu_ctx, fh); -} - static struct jpu_ctx *file_to_ctx(struct file *filp) { - return fh_to_ctx(file_to_v4l2_fh(filp)); + return container_of(file_to_v4l2_fh(filp), struct jpu_ctx, fh); } static void jpu_set_tbl(struct jpu *jpu, u32 reg, const unsigned int *tbl, @@ -661,7 +656,7 @@ static u8 jpu_parse_hdr(void *buffer, unsigned long size, unsigned int *width, static int jpu_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct jpu_ctx *ctx = fh_to_ctx(priv); + struct jpu_ctx *ctx = file_to_ctx(file); if (ctx->encoder) strscpy(cap->card, DRV_NAME " encoder", sizeof(cap->card)); @@ -719,7 +714,7 @@ static int jpu_enum_fmt(struct v4l2_fmtdesc *f, u32 type) static int jpu_enum_fmt_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct jpu_ctx *ctx = fh_to_ctx(priv); + struct jpu_ctx *ctx = file_to_ctx(file); return jpu_enum_fmt(f, ctx->encoder ? JPU_ENC_CAPTURE : JPU_DEC_CAPTURE); @@ -728,7 +723,7 @@ static int jpu_enum_fmt_cap(struct file *file, void *priv, static int jpu_enum_fmt_out(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct jpu_ctx *ctx = fh_to_ctx(priv); + struct jpu_ctx *ctx = file_to_ctx(file); return jpu_enum_fmt(f, ctx->encoder ? JPU_ENC_OUTPUT : JPU_DEC_OUTPUT); } @@ -828,7 +823,7 @@ static int __jpu_try_fmt(struct jpu_ctx *ctx, struct jpu_fmt **fmtinfo, static int jpu_try_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct jpu_ctx *ctx = fh_to_ctx(priv); + struct jpu_ctx *ctx = file_to_ctx(file); if (!v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type)) return -EINVAL; @@ -839,7 +834,7 @@ static int jpu_try_fmt(struct file *file, void *priv, struct v4l2_format *f) static int jpu_s_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct vb2_queue *vq; - struct jpu_ctx *ctx = fh_to_ctx(priv); + struct jpu_ctx *ctx = file_to_ctx(file); struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; struct jpu_fmt *fmtinfo; struct jpu_q_data *q_data; @@ -868,8 +863,8 @@ static int jpu_s_fmt(struct file *file, void *priv, struct v4l2_format *f) static int jpu_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { + struct jpu_ctx *ctx = file_to_ctx(file); struct jpu_q_data *q_data; - struct jpu_ctx *ctx = fh_to_ctx(priv); if (!v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type)) return -EINVAL; @@ -902,8 +897,8 @@ static const struct v4l2_ctrl_ops jpu_ctrl_ops = { static int jpu_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { - struct jpu_ctx *ctx = fh_to_ctx(priv); struct jpu_q_data *src_q_data, *dst_q_data, *orig, adj, *ref; + struct jpu_ctx *ctx = file_to_ctx(file); enum v4l2_buf_type adj_type; src_q_data = jpu_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); @@ -1284,8 +1279,8 @@ static int jpu_open(struct file *file) static int jpu_release(struct file *file) { - struct jpu *jpu = video_drvdata(file); struct jpu_ctx *ctx = file_to_ctx(file); + struct jpu *jpu = video_drvdata(file); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); v4l2_ctrl_handler_free(&ctx->ctrl_handler); From 3cf9bbb526534f8f1c96b3ca81bf162e0ffb633c Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:32 +0300 Subject: [PATCH 00550/11391] media: rockhip: rga: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. Signed-off-by: Jacopo Mondi Signed-off-by: Hans Verkuil --- drivers/media/platform/rockchip/rga/rga.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index 45c42c7ad846..7c657df623f2 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -462,7 +462,7 @@ static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f) static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp; - struct rga_ctx *ctx = prv; + struct rga_ctx *ctx = file_to_rga_ctx(file); struct vb2_queue *vq; struct rga_frame *frm; @@ -504,7 +504,7 @@ static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f) static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp; - struct rga_ctx *ctx = prv; + struct rga_ctx *ctx = file_to_rga_ctx(file); struct rockchip_rga *rga = ctx->rga; struct vb2_queue *vq; struct rga_frame *frm; @@ -561,7 +561,7 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) static int vidioc_g_selection(struct file *file, void *prv, struct v4l2_selection *s) { - struct rga_ctx *ctx = prv; + struct rga_ctx *ctx = file_to_rga_ctx(file); struct rga_frame *f; bool use_frame = false; @@ -609,7 +609,7 @@ static int vidioc_g_selection(struct file *file, void *prv, static int vidioc_s_selection(struct file *file, void *prv, struct v4l2_selection *s) { - struct rga_ctx *ctx = prv; + struct rga_ctx *ctx = file_to_rga_ctx(file); struct rockchip_rga *rga = ctx->rga; struct rga_frame *f; int ret = 0; From aa099b1129a834d508761a9af18c6bf5f78b057d Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:33 +0300 Subject: [PATCH 00551/11391] media: rockchip: rkvdec: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. Signed-off-by: Jacopo Mondi Reviewed-by: Detlev Casanova Co-developed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/platform/rockchip/rkvdec/rkvdec.c | 14 +++++++------- drivers/media/platform/rockchip/rkvdec/rkvdec.h | 7 +------ 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c index 481c2488f9ac..9fa80ab3c62b 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c @@ -354,7 +354,7 @@ static int rkvdec_try_capture_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(priv); + struct rkvdec_ctx *ctx = file_to_rkvdec_ctx(file); const struct rkvdec_coded_fmt_desc *coded_desc; /* @@ -387,7 +387,7 @@ static int rkvdec_try_output_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(priv); + struct rkvdec_ctx *ctx = file_to_rkvdec_ctx(file); const struct rkvdec_coded_fmt_desc *desc; desc = rkvdec_find_coded_fmt_desc(pix_mp->pixelformat); @@ -418,7 +418,7 @@ static int rkvdec_try_output_fmt(struct file *file, void *priv, static int rkvdec_s_capture_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(priv); + struct rkvdec_ctx *ctx = file_to_rkvdec_ctx(file); struct vb2_queue *vq; int ret; @@ -439,7 +439,7 @@ static int rkvdec_s_capture_fmt(struct file *file, void *priv, static int rkvdec_s_output_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(priv); + struct rkvdec_ctx *ctx = file_to_rkvdec_ctx(file); struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; const struct rkvdec_coded_fmt_desc *desc; struct v4l2_format *cap_fmt; @@ -504,7 +504,7 @@ static int rkvdec_s_output_fmt(struct file *file, void *priv, static int rkvdec_g_output_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(priv); + struct rkvdec_ctx *ctx = file_to_rkvdec_ctx(file); *f = ctx->coded_fmt; return 0; @@ -513,7 +513,7 @@ static int rkvdec_g_output_fmt(struct file *file, void *priv, static int rkvdec_g_capture_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(priv); + struct rkvdec_ctx *ctx = file_to_rkvdec_ctx(file); *f = ctx->decoded_fmt; return 0; @@ -532,7 +532,7 @@ static int rkvdec_enum_output_fmt(struct file *file, void *priv, static int rkvdec_enum_capture_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(priv); + struct rkvdec_ctx *ctx = file_to_rkvdec_ctx(file); u32 fourcc; fourcc = rkvdec_enum_decoded_fmt(ctx, f->index, ctx->image_fmt); diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h index 3a6322d42b26..481aaa4bffe9 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h @@ -124,14 +124,9 @@ struct rkvdec_ctx { void *priv; }; -static inline struct rkvdec_ctx *fh_to_rkvdec_ctx(struct v4l2_fh *fh) -{ - return container_of(fh, struct rkvdec_ctx, fh); -} - static inline struct rkvdec_ctx *file_to_rkvdec_ctx(struct file *filp) { - return fh_to_rkvdec_ctx(file_to_v4l2_fh(filp)); + return container_of(file_to_v4l2_fh(filp), struct rkvdec_ctx, fh); } struct rkvdec_aux_buf { From 9d612344a2fc4d59a8c0b8c72bbfb774ae181e2b Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:34 +0300 Subject: [PATCH 00552/11391] media: exynos-gsc: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. Signed-off-by: Jacopo Mondi Co-developed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- .../platform/samsung/exynos-gsc/gsc-core.h | 4 +--- .../platform/samsung/exynos-gsc/gsc-m2m.c | 24 +++++++++---------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/drivers/media/platform/samsung/exynos-gsc/gsc-core.h b/drivers/media/platform/samsung/exynos-gsc/gsc-core.h index 56856e9f9baf..265221abf4dc 100644 --- a/drivers/media/platform/samsung/exynos-gsc/gsc-core.h +++ b/drivers/media/platform/samsung/exynos-gsc/gsc-core.h @@ -85,8 +85,6 @@ enum gsc_yuv_fmt { GSC_CRCB, }; -#define fh_to_ctx(__fh) container_of(__fh, struct gsc_ctx, fh) - #define is_rgb(x) (!!((x) & 0x1)) #define is_yuv420(x) (!!((x) & 0x2)) #define is_yuv422(x) (!!((x) & 0x4)) @@ -384,7 +382,7 @@ struct gsc_ctx { static inline struct gsc_ctx *file_to_ctx(struct file *filp) { - return fh_to_ctx(file_to_v4l2_fh(filp)); + return container_of(file_to_v4l2_fh(filp), struct gsc_ctx, fh); } void gsc_set_prefbuf(struct gsc_dev *gsc, struct gsc_frame *frm); diff --git a/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c b/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c index 2999fb2610f0..722e2531e23f 100644 --- a/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c @@ -297,7 +297,7 @@ static int gsc_m2m_enum_fmt(struct file *file, void *priv, static int gsc_m2m_g_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { - struct gsc_ctx *ctx = fh_to_ctx(fh); + struct gsc_ctx *ctx = file_to_ctx(file); return gsc_g_fmt_mplane(ctx, f); } @@ -305,7 +305,7 @@ static int gsc_m2m_g_fmt_mplane(struct file *file, void *fh, static int gsc_m2m_try_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { - struct gsc_ctx *ctx = fh_to_ctx(fh); + struct gsc_ctx *ctx = file_to_ctx(file); return gsc_try_fmt_mplane(ctx, f); } @@ -313,7 +313,7 @@ static int gsc_m2m_try_fmt_mplane(struct file *file, void *fh, static int gsc_m2m_s_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { - struct gsc_ctx *ctx = fh_to_ctx(fh); + struct gsc_ctx *ctx = file_to_ctx(file); struct vb2_queue *vq; struct gsc_frame *frame; struct v4l2_pix_format_mplane *pix; @@ -359,7 +359,7 @@ static int gsc_m2m_s_fmt_mplane(struct file *file, void *fh, static int gsc_m2m_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *reqbufs) { - struct gsc_ctx *ctx = fh_to_ctx(fh); + struct gsc_ctx *ctx = file_to_ctx(file); struct gsc_dev *gsc = ctx->gsc_dev; u32 max_cnt; @@ -374,35 +374,35 @@ static int gsc_m2m_reqbufs(struct file *file, void *fh, static int gsc_m2m_expbuf(struct file *file, void *fh, struct v4l2_exportbuffer *eb) { - struct gsc_ctx *ctx = fh_to_ctx(fh); + struct gsc_ctx *ctx = file_to_ctx(file); return v4l2_m2m_expbuf(file, ctx->m2m_ctx, eb); } static int gsc_m2m_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf) { - struct gsc_ctx *ctx = fh_to_ctx(fh); + struct gsc_ctx *ctx = file_to_ctx(file); return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); } static int gsc_m2m_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) { - struct gsc_ctx *ctx = fh_to_ctx(fh); + struct gsc_ctx *ctx = file_to_ctx(file); return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); } static int gsc_m2m_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) { - struct gsc_ctx *ctx = fh_to_ctx(fh); + struct gsc_ctx *ctx = file_to_ctx(file); return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); } static int gsc_m2m_streamon(struct file *file, void *fh, enum v4l2_buf_type type) { - struct gsc_ctx *ctx = fh_to_ctx(fh); + struct gsc_ctx *ctx = file_to_ctx(file); /* The source and target color format need to be set */ if (V4L2_TYPE_IS_OUTPUT(type)) { @@ -418,7 +418,7 @@ static int gsc_m2m_streamon(struct file *file, void *fh, static int gsc_m2m_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) { - struct gsc_ctx *ctx = fh_to_ctx(fh); + struct gsc_ctx *ctx = file_to_ctx(file); return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); } @@ -440,8 +440,8 @@ static int is_rectangle_enclosed(struct v4l2_rect *a, struct v4l2_rect *b) static int gsc_m2m_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { + struct gsc_ctx *ctx = file_to_ctx(file); struct gsc_frame *frame; - struct gsc_ctx *ctx = fh_to_ctx(fh); if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)) @@ -478,7 +478,7 @@ static int gsc_m2m_s_selection(struct file *file, void *fh, struct v4l2_selection *s) { struct gsc_frame *frame; - struct gsc_ctx *ctx = fh_to_ctx(fh); + struct gsc_ctx *ctx = file_to_ctx(file); struct gsc_variant *variant = ctx->gsc_dev->variant; struct v4l2_selection sel = *s; int ret; From 3aafbde78bc67ae1321645a91f092da60dea205a Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:35 +0300 Subject: [PATCH 00553/11391] media: exynos4-is: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. Signed-off-by: Jacopo Mondi Co-developed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/platform/samsung/exynos4-is/fimc-core.h | 4 +--- drivers/media/platform/samsung/exynos4-is/fimc-m2m.c | 10 +++++----- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-core.h b/drivers/media/platform/samsung/exynos4-is/fimc-core.h index 2b6c72d9442c..c23cbdee7afc 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-core.h +++ b/drivers/media/platform/samsung/exynos4-is/fimc-core.h @@ -496,11 +496,9 @@ struct fimc_ctx { struct fimc_ctrls ctrls; }; -#define fh_to_ctx(__fh) container_of(__fh, struct fimc_ctx, fh) - static inline struct fimc_ctx *file_to_ctx(struct file *filp) { - return fh_to_ctx(file_to_v4l2_fh(filp)); + return container_of(file_to_v4l2_fh(filp), struct fimc_ctx, fh); } static inline void set_frame_bounds(struct fimc_frame *f, u32 width, u32 height) diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c b/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c index 609fd84f89d4..562c57f186c6 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c @@ -249,7 +249,7 @@ static int fimc_m2m_enum_fmt(struct file *file, void *priv, static int fimc_m2m_g_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { - struct fimc_ctx *ctx = fh_to_ctx(fh); + struct fimc_ctx *ctx = file_to_ctx(file); const struct fimc_frame *frame = ctx_get_frame(ctx, f->type); if (IS_ERR(frame)) @@ -308,7 +308,7 @@ static int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f) static int fimc_m2m_try_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { - struct fimc_ctx *ctx = fh_to_ctx(fh); + struct fimc_ctx *ctx = file_to_ctx(file); return fimc_try_fmt_mplane(ctx, f); } @@ -337,7 +337,7 @@ static void __set_frame_format(struct fimc_frame *frame, static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { - struct fimc_ctx *ctx = fh_to_ctx(fh); + struct fimc_ctx *ctx = file_to_ctx(file); struct fimc_dev *fimc = ctx->fimc_dev; const struct fimc_fmt *fmt; struct vb2_queue *vq; @@ -376,7 +376,7 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh, static int fimc_m2m_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct fimc_ctx *ctx = fh_to_ctx(fh); + struct fimc_ctx *ctx = file_to_ctx(file); const struct fimc_frame *frame; frame = ctx_get_frame(ctx, s->type); @@ -484,7 +484,7 @@ static int fimc_m2m_try_selection(struct fimc_ctx *ctx, static int fimc_m2m_s_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct fimc_ctx *ctx = fh_to_ctx(fh); + struct fimc_ctx *ctx = file_to_ctx(file); struct fimc_dev *fimc = ctx->fimc_dev; struct fimc_frame *f; int ret; From 223171b22e866ede054c9949b0a83ab2e5ae8951 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:36 +0300 Subject: [PATCH 00554/11391] media: s3c-camif: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh from the file * in all ioctl handlers. The v4l2_fh pointer is used to keep track of which user owns the streaming queue. Signed-off-by: Jacopo Mondi Signed-off-by: Hans Verkuil --- .../samsung/s3c-camif/camif-capture.c | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/samsung/s3c-camif/camif-capture.c b/drivers/media/platform/samsung/s3c-camif/camif-capture.c index cae15a4ce5fd..ed1a1d693293 100644 --- a/drivers/media/platform/samsung/s3c-camif/camif-capture.c +++ b/drivers/media/platform/samsung/s3c-camif/camif-capture.c @@ -791,7 +791,7 @@ static int s3c_camif_vidioc_s_fmt(struct file *file, void *priv, out_frame->rect.top = 0; if (vp->owner == NULL) - vp->owner = priv; + vp->owner = file_to_v4l2_fh(file); pr_debug("%ux%u. payload: %u. fmt: 0x%08x. %d %d. sizeimage: %d. bpl: %d\n", out_frame->f_width, out_frame->f_height, vp->payload, @@ -841,7 +841,7 @@ static int s3c_camif_streamon(struct file *file, void *priv, if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - if (vp->owner && vp->owner != priv) + if (vp->owner && vp->owner != file_to_v4l2_fh(file)) return -EBUSY; if (s3c_vp_active(vp)) @@ -872,7 +872,7 @@ static int s3c_camif_streamoff(struct file *file, void *priv, if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - if (vp->owner && vp->owner != priv) + if (vp->owner && vp->owner != file_to_v4l2_fh(file)) return -EBUSY; ret = vb2_streamoff(&vp->vb_queue, type); @@ -888,9 +888,9 @@ static int s3c_camif_reqbufs(struct file *file, void *priv, int ret; pr_debug("[vp%d] rb count: %d, owner: %p, priv: %p\n", - vp->id, rb->count, vp->owner, priv); + vp->id, rb->count, vp->owner, file_to_v4l2_fh(file)); - if (vp->owner && vp->owner != priv) + if (vp->owner && vp->owner != file_to_v4l2_fh(file)) return -EBUSY; if (rb->count) @@ -910,7 +910,7 @@ static int s3c_camif_reqbufs(struct file *file, void *priv, vp->reqbufs_count = rb->count; if (vp->owner == NULL && rb->count > 0) - vp->owner = priv; + vp->owner = file_to_v4l2_fh(file); return ret; } @@ -929,7 +929,7 @@ static int s3c_camif_qbuf(struct file *file, void *priv, pr_debug("[vp%d]\n", vp->id); - if (vp->owner && vp->owner != priv) + if (vp->owner && vp->owner != file_to_v4l2_fh(file)) return -EBUSY; return vb2_qbuf(&vp->vb_queue, vp->vdev.v4l2_dev->mdev, buf); @@ -942,7 +942,7 @@ static int s3c_camif_dqbuf(struct file *file, void *priv, pr_debug("[vp%d] sequence: %d\n", vp->id, vp->frame_sequence); - if (vp->owner && vp->owner != priv) + if (vp->owner && vp->owner != file_to_v4l2_fh(file)) return -EBUSY; return vb2_dqbuf(&vp->vb_queue, buf, file->f_flags & O_NONBLOCK); @@ -954,14 +954,14 @@ static int s3c_camif_create_bufs(struct file *file, void *priv, struct camif_vp *vp = video_drvdata(file); int ret; - if (vp->owner && vp->owner != priv) + if (vp->owner && vp->owner != file_to_v4l2_fh(file)) return -EBUSY; create->count = max_t(u32, 1, create->count); ret = vb2_create_bufs(&vp->vb_queue, create); if (!ret && vp->owner == NULL) - vp->owner = priv; + vp->owner = file_to_v4l2_fh(file); return ret; } From d21431099b75ec70a33e3d7be3f0fa17d30da05e Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:37 +0300 Subject: [PATCH 00555/11391] media: s5p-g2d: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. Signed-off-by: Jacopo Mondi Signed-off-by: Hans Verkuil --- drivers/media/platform/samsung/s5p-g2d/g2d.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/samsung/s5p-g2d/g2d.c b/drivers/media/platform/samsung/s5p-g2d/g2d.c index 922262f61e7b..55f5130156b7 100644 --- a/drivers/media/platform/samsung/s5p-g2d/g2d.c +++ b/drivers/media/platform/samsung/s5p-g2d/g2d.c @@ -307,7 +307,7 @@ static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f) static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) { - struct g2d_ctx *ctx = prv; + struct g2d_ctx *ctx = file2ctx(file); struct vb2_queue *vq; struct g2d_frame *frm; @@ -359,7 +359,7 @@ static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f) static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) { - struct g2d_ctx *ctx = prv; + struct g2d_ctx *ctx = file2ctx(file); struct g2d_dev *dev = ctx->dev; struct vb2_queue *vq; struct g2d_frame *frm; @@ -400,7 +400,7 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) static int vidioc_g_selection(struct file *file, void *prv, struct v4l2_selection *s) { - struct g2d_ctx *ctx = prv; + struct g2d_ctx *ctx = file2ctx(file); struct g2d_frame *f; f = get_frame(ctx, s->type); @@ -450,7 +450,7 @@ static int vidioc_g_selection(struct file *file, void *prv, static int vidioc_try_selection(struct file *file, void *prv, const struct v4l2_selection *s) { - struct g2d_ctx *ctx = prv; + struct g2d_ctx *ctx = file2ctx(file); struct g2d_dev *dev = ctx->dev; struct g2d_frame *f; @@ -478,7 +478,7 @@ static int vidioc_try_selection(struct file *file, void *prv, static int vidioc_s_selection(struct file *file, void *prv, struct v4l2_selection *s) { - struct g2d_ctx *ctx = prv; + struct g2d_ctx *ctx = file2ctx(file); struct g2d_frame *f; int ret; From 52e6cd6aaa6bcac2647188518801d525e267edef Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:38 +0300 Subject: [PATCH 00556/11391] media: s5p-jpeg: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. Signed-off-by: Jacopo Mondi Reviewed-by: Andrzej Pietrasiewicz Co-developed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- .../platform/samsung/s5p-jpeg/jpeg-core.c | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c index 65f256db4c76..81792f7f8b16 100644 --- a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c @@ -580,14 +580,9 @@ static inline struct s5p_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *c) return container_of(c->handler, struct s5p_jpeg_ctx, ctrl_handler); } -static inline struct s5p_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh) -{ - return container_of(fh, struct s5p_jpeg_ctx, fh); -} - static inline struct s5p_jpeg_ctx *file_to_ctx(struct file *filp) { - return fh_to_ctx(file_to_v4l2_fh(filp)); + return container_of(file_to_v4l2_fh(filp), struct s5p_jpeg_ctx, fh); } static int s5p_jpeg_to_user_subsampling(struct s5p_jpeg_ctx *ctx) @@ -1015,8 +1010,8 @@ static int s5p_jpeg_open(struct file *file) static int s5p_jpeg_release(struct file *file) { - struct s5p_jpeg *jpeg = video_drvdata(file); struct s5p_jpeg_ctx *ctx = file_to_ctx(file); + struct s5p_jpeg *jpeg = video_drvdata(file); mutex_lock(&jpeg->lock); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); @@ -1253,7 +1248,7 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result, static int s5p_jpeg_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); + struct s5p_jpeg_ctx *ctx = file_to_ctx(file); if (ctx->mode == S5P_JPEG_ENCODE) { strscpy(cap->driver, S5P_JPEG_M2M_NAME, @@ -1301,7 +1296,7 @@ static int enum_fmt(struct s5p_jpeg_ctx *ctx, static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); + struct s5p_jpeg_ctx *ctx = file_to_ctx(file); if (ctx->mode == S5P_JPEG_ENCODE) return enum_fmt(ctx, sjpeg_formats, SJPEG_NUM_FORMATS, f, @@ -1314,7 +1309,7 @@ static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); + struct s5p_jpeg_ctx *ctx = file_to_ctx(file); if (ctx->mode == S5P_JPEG_ENCODE) return enum_fmt(ctx, sjpeg_formats, SJPEG_NUM_FORMATS, f, @@ -1340,7 +1335,7 @@ static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f) struct vb2_queue *vq; struct s5p_jpeg_q_data *q_data = NULL; struct v4l2_pix_format *pix = &f->fmt.pix; - struct s5p_jpeg_ctx *ct = fh_to_ctx(priv); + struct s5p_jpeg_ctx *ct = file_to_ctx(file); vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type); if (!vq) @@ -1480,7 +1475,7 @@ static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt, static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); + struct s5p_jpeg_ctx *ctx = file_to_ctx(file); struct v4l2_pix_format *pix = &f->fmt.pix; struct s5p_jpeg_fmt *fmt; int ret; @@ -1539,7 +1534,7 @@ static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv, static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { - struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); + struct s5p_jpeg_ctx *ctx = file_to_ctx(file); struct s5p_jpeg_fmt *fmt; fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat, @@ -1686,7 +1681,7 @@ static int s5p_jpeg_s_fmt_vid_cap(struct file *file, void *priv, if (ret) return ret; - return s5p_jpeg_s_fmt(fh_to_ctx(priv), f); + return s5p_jpeg_s_fmt(file_to_ctx(file), f); } static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv, @@ -1698,7 +1693,7 @@ static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv, if (ret) return ret; - return s5p_jpeg_s_fmt(fh_to_ctx(priv), f); + return s5p_jpeg_s_fmt(file_to_ctx(file), f); } static int s5p_jpeg_subscribe_event(struct v4l2_fh *fh, @@ -1795,7 +1790,7 @@ static int exynos3250_jpeg_try_crop(struct s5p_jpeg_ctx *ctx, static int s5p_jpeg_g_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); + struct s5p_jpeg_ctx *ctx = file_to_ctx(file); if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) From 4df43d4997ac34e371b2c08e8c506507da1652b2 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:30:39 +0300 Subject: [PATCH 00557/11391] media: s5p-mfc: Store s5p_mfc_ctx in vb2_queue.drv_priv The driver stores a pointer to a v4l2_fh in the vb2_queue.drv_priv, which it then has to cast to a s5p_mfc_ctx pointer in all vb2 queue operations. Store the pointer to the s5p_mfc_ctx instead to avoid the cast. While at it, use the vb2_get_drv_priv() helper to access the field. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c | 4 ++-- drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c | 10 +++++----- drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c | 12 ++++++------ 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c index a5e756049620..4948d734eb02 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c @@ -876,7 +876,7 @@ static int s5p_mfc_open(struct file *file) /* Init videobuf2 queue for CAPTURE */ q = &ctx->vq_dst; q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - q->drv_priv = &ctx->fh; + q->drv_priv = ctx; q->lock = &dev->mfc_mutex; if (vdev == dev->vfd_dec) { q->io_modes = VB2_MMAP; @@ -903,7 +903,7 @@ static int s5p_mfc_open(struct file *file) /* Init videobuf2 queue for OUTPUT */ q = &ctx->vq_src; q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - q->drv_priv = &ctx->fh; + q->drv_priv = ctx; q->lock = &dev->mfc_mutex; if (vdev == dev->vfd_dec) { q->io_modes = VB2_MMAP; diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c index 3efbc3367906..aefa6da5c609 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c @@ -937,7 +937,7 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, unsigned int *plane_count, unsigned int psize[], struct device *alloc_devs[]) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); + struct s5p_mfc_ctx *ctx = vb2_get_drv_priv(vq); struct s5p_mfc_dev *dev = ctx->dev; const struct v4l2_format_info *format; @@ -1006,7 +1006,7 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct vb2_queue *vq = vb->vb2_queue; - struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); + struct s5p_mfc_ctx *ctx = vb2_get_drv_priv(vq); unsigned int i; if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { @@ -1068,7 +1068,7 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb) static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); + struct s5p_mfc_ctx *ctx = vb2_get_drv_priv(q); struct s5p_mfc_dev *dev = ctx->dev; v4l2_ctrl_handler_setup(&ctx->ctrl_handler); @@ -1085,7 +1085,7 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count) static void s5p_mfc_stop_streaming(struct vb2_queue *q) { unsigned long flags; - struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); + struct s5p_mfc_ctx *ctx = vb2_get_drv_priv(q); struct s5p_mfc_dev *dev = ctx->dev; int aborted = 0; @@ -1130,7 +1130,7 @@ static void s5p_mfc_stop_streaming(struct vb2_queue *q) static void s5p_mfc_buf_queue(struct vb2_buffer *vb) { struct vb2_queue *vq = vb->vb2_queue; - struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); + struct s5p_mfc_ctx *ctx = vb2_get_drv_priv(vq); struct s5p_mfc_dev *dev = ctx->dev; unsigned long flags; struct s5p_mfc_buf *mfc_buf; diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c index 6c603dcd5664..9b77dbd856e7 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c @@ -2418,7 +2418,7 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, unsigned int *buf_count, unsigned int *plane_count, unsigned int psize[], struct device *alloc_devs[]) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); + struct s5p_mfc_ctx *ctx = vb2_get_drv_priv(vq); struct s5p_mfc_dev *dev = ctx->dev; if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { @@ -2477,7 +2477,7 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct vb2_queue *vq = vb->vb2_queue; - struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); + struct s5p_mfc_ctx *ctx = vb2_get_drv_priv(vq); unsigned int i; int ret; @@ -2516,7 +2516,7 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb) static int s5p_mfc_buf_prepare(struct vb2_buffer *vb) { struct vb2_queue *vq = vb->vb2_queue; - struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); + struct s5p_mfc_ctx *ctx = vb2_get_drv_priv(vq); int ret; if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { @@ -2557,7 +2557,7 @@ static int s5p_mfc_buf_prepare(struct vb2_buffer *vb) static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); + struct s5p_mfc_ctx *ctx = vb2_get_drv_priv(q); struct s5p_mfc_dev *dev = ctx->dev; if (IS_MFCV6_PLUS(dev) && @@ -2588,7 +2588,7 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count) static void s5p_mfc_stop_streaming(struct vb2_queue *q) { unsigned long flags; - struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); + struct s5p_mfc_ctx *ctx = vb2_get_drv_priv(q); struct s5p_mfc_dev *dev = ctx->dev; if ((ctx->state == MFCINST_FINISHING || @@ -2617,7 +2617,7 @@ static void s5p_mfc_stop_streaming(struct vb2_queue *q) static void s5p_mfc_buf_queue(struct vb2_buffer *vb) { struct vb2_queue *vq = vb->vb2_queue; - struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); + struct s5p_mfc_ctx *ctx = vb2_get_drv_priv(vq); struct s5p_mfc_dev *dev = ctx->dev; unsigned long flags; struct s5p_mfc_buf *mfc_buf; From fede1dac719e080f922b52ef36fbb124dc1a2386 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:40 +0300 Subject: [PATCH 00558/11391] media: s5p-mfc: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. Signed-off-by: Jacopo Mondi Signed-off-by: Hans Verkuil --- .../platform/samsung/s5p-mfc/s5p_mfc_common.h | 4 +--- .../platform/samsung/s5p-mfc/s5p_mfc_dec.c | 22 ++++++++--------- .../platform/samsung/s5p-mfc/s5p_mfc_enc.c | 24 +++++++++---------- 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h index a29228b4207f..58dc1768082c 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h @@ -767,11 +767,9 @@ struct mfc_control { #define s5p_mfc_hw_call(f, op, args...) \ ((f && f->op) ? f->op(args) : (typeof(f->op(args)))(-ENODEV)) -#define fh_to_ctx(__fh) container_of(__fh, struct s5p_mfc_ctx, fh) - static inline struct s5p_mfc_ctx *file_to_ctx(struct file *filp) { - return fh_to_ctx(file_to_v4l2_fh(filp)); + return container_of(file_to_v4l2_fh(filp), struct s5p_mfc_ctx, fh); } #define ctrl_to_ctx(__ctrl) \ diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c index aefa6da5c609..606e1a7121b5 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c @@ -345,7 +345,7 @@ static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, /* Get format */ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); struct v4l2_pix_format_mplane *pix_mp; mfc_debug_enter(); @@ -442,7 +442,7 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct s5p_mfc_dev *dev = video_drvdata(file); - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); int ret = 0; struct v4l2_pix_format_mplane *pix_mp; const struct s5p_mfc_buf_size *buf_size = dev->variant->buf_size; @@ -598,7 +598,7 @@ static int vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *reqbufs) { struct s5p_mfc_dev *dev = video_drvdata(file); - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); if (reqbufs->memory != V4L2_MEMORY_MMAP) { mfc_debug(2, "Only V4L2_MEMORY_MMAP is supported\n"); @@ -619,7 +619,7 @@ static int vidioc_reqbufs(struct file *file, void *priv, static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); int ret; int i; @@ -647,7 +647,7 @@ static int vidioc_querybuf(struct file *file, void *priv, /* Queue a buffer */ static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); if (ctx->state == MFCINST_ERROR) { mfc_err("Call on QBUF after unrecoverable error\n"); @@ -666,7 +666,7 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) const struct v4l2_event ev = { .type = V4L2_EVENT_EOS }; - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); int ret; if (ctx->state == MFCINST_ERROR) { @@ -695,7 +695,7 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) static int vidioc_expbuf(struct file *file, void *priv, struct v4l2_exportbuffer *eb) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); if (eb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) return vb2_expbuf(&ctx->vq_src, eb); @@ -708,7 +708,7 @@ static int vidioc_expbuf(struct file *file, void *priv, static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); int ret = -EINVAL; mfc_debug_enter(); @@ -724,7 +724,7 @@ static int vidioc_streamon(struct file *file, void *priv, static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type type) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) return vb2_streamoff(&ctx->vq_src, type); @@ -801,7 +801,7 @@ static const struct v4l2_ctrl_ops s5p_mfc_dec_ctrl_ops = { static int vidioc_g_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); struct s5p_mfc_dev *dev = ctx->dev; u32 left, right, top, bottom; u32 width, height; @@ -856,7 +856,7 @@ static int vidioc_g_selection(struct file *file, void *priv, static int vidioc_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_buf *buf; unsigned long flags; diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c index 9b77dbd856e7..694b68788a95 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c @@ -1389,8 +1389,8 @@ static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; + struct s5p_mfc_ctx *ctx = file_to_ctx(file); mfc_debug(2, "f->type = %d ctx->state = %d\n", f->type, ctx->state); if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { @@ -1472,8 +1472,8 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) { + struct s5p_mfc_ctx *ctx = file_to_ctx(file); struct s5p_mfc_dev *dev = video_drvdata(file); - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; int ret = 0; @@ -1531,7 +1531,7 @@ static int vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *reqbufs) { struct s5p_mfc_dev *dev = video_drvdata(file); - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); int ret = 0; /* if memory is not mmp or userptr or dmabuf return error */ @@ -1601,7 +1601,7 @@ static int vidioc_reqbufs(struct file *file, void *priv, static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); int ret = 0; /* if memory is not mmp or userptr or dmabuf return error */ @@ -1636,7 +1636,7 @@ static int vidioc_querybuf(struct file *file, void *priv, /* Queue a buffer */ static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); if (ctx->state == MFCINST_ERROR) { mfc_err("Call on QBUF after unrecoverable error\n"); @@ -1657,10 +1657,10 @@ static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) /* Dequeue a buffer */ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { + struct s5p_mfc_ctx *ctx = file_to_ctx(file); const struct v4l2_event ev = { .type = V4L2_EVENT_EOS }; - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); int ret; if (ctx->state == MFCINST_ERROR) { @@ -1685,7 +1685,7 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) static int vidioc_expbuf(struct file *file, void *priv, struct v4l2_exportbuffer *eb) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); if (eb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) return vb2_expbuf(&ctx->vq_src, eb); @@ -1698,7 +1698,7 @@ static int vidioc_expbuf(struct file *file, void *priv, static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) return vb2_streamon(&ctx->vq_src, type); @@ -1711,7 +1711,7 @@ static int vidioc_streamon(struct file *file, void *priv, static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type type) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) return vb2_streamoff(&ctx->vq_src, type); @@ -2284,7 +2284,7 @@ static const struct v4l2_ctrl_ops s5p_mfc_enc_ctrl_ops = { static int vidioc_s_parm(struct file *file, void *priv, struct v4l2_streamparm *a) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { ctx->enc_params.rc_framerate_num = @@ -2301,7 +2301,7 @@ static int vidioc_s_parm(struct file *file, void *priv, static int vidioc_g_parm(struct file *file, void *priv, struct v4l2_streamparm *a) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { a->parm.output.timeperframe.denominator = @@ -2318,7 +2318,7 @@ static int vidioc_g_parm(struct file *file, void *priv, static int vidioc_encoder_cmd(struct file *file, void *priv, struct v4l2_encoder_cmd *cmd) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_buf *buf; unsigned long flags; From c3db0cdea470798c958915a2571de10e145334cc Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:41 +0300 Subject: [PATCH 00559/11391] media: bdisp: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. Signed-off-by: Jacopo Mondi Co-developed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- .../media/platform/st/sti/bdisp/bdisp-v4l2.c | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c index 38b2a2924443..56169b70652d 100644 --- a/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c +++ b/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c @@ -33,11 +33,9 @@ #define BDISP_MIN_H 1 #define BDISP_MAX_H 8191 -#define fh_to_ctx(__fh) container_of(__fh, struct bdisp_ctx, fh) - static inline struct bdisp_ctx *file_to_ctx(struct file *filp) { - return fh_to_ctx(file_to_v4l2_fh(filp)); + return container_of(file_to_v4l2_fh(filp), struct bdisp_ctx, fh); } enum bdisp_dev_flags { @@ -686,7 +684,7 @@ static const struct v4l2_file_operations bdisp_fops = { static int bdisp_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { - struct bdisp_ctx *ctx = fh_to_ctx(fh); + struct bdisp_ctx *ctx = file_to_ctx(file); struct bdisp_dev *bdisp = ctx->bdisp_dev; strscpy(cap->driver, bdisp->pdev->name, sizeof(cap->driver)); @@ -698,7 +696,7 @@ static int bdisp_querycap(struct file *file, void *fh, static int bdisp_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) { - struct bdisp_ctx *ctx = fh_to_ctx(fh); + struct bdisp_ctx *ctx = file_to_ctx(file); const struct bdisp_fmt *fmt; if (f->index >= ARRAY_SIZE(bdisp_formats)) @@ -718,7 +716,7 @@ static int bdisp_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) static int bdisp_g_fmt(struct file *file, void *fh, struct v4l2_format *f) { - struct bdisp_ctx *ctx = fh_to_ctx(fh); + struct bdisp_ctx *ctx = file_to_ctx(file); struct v4l2_pix_format *pix; struct bdisp_frame *frame = ctx_get_frame(ctx, f->type); @@ -742,7 +740,7 @@ static int bdisp_g_fmt(struct file *file, void *fh, struct v4l2_format *f) static int bdisp_try_fmt(struct file *file, void *fh, struct v4l2_format *f) { - struct bdisp_ctx *ctx = fh_to_ctx(fh); + struct bdisp_ctx *ctx = file_to_ctx(file); struct v4l2_pix_format *pix = &f->fmt.pix; const struct bdisp_fmt *format; u32 in_w, in_h; @@ -792,7 +790,7 @@ static int bdisp_try_fmt(struct file *file, void *fh, struct v4l2_format *f) static int bdisp_s_fmt(struct file *file, void *fh, struct v4l2_format *f) { - struct bdisp_ctx *ctx = fh_to_ctx(fh); + struct bdisp_ctx *ctx = file_to_ctx(file); struct vb2_queue *vq; struct bdisp_frame *frame; struct v4l2_pix_format *pix; @@ -845,8 +843,8 @@ static int bdisp_s_fmt(struct file *file, void *fh, struct v4l2_format *f) static int bdisp_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { + struct bdisp_ctx *ctx = file_to_ctx(file); struct bdisp_frame *frame; - struct bdisp_ctx *ctx = fh_to_ctx(fh); frame = ctx_get_frame(ctx, s->type); if (IS_ERR(frame)) { @@ -923,8 +921,8 @@ static int is_rect_enclosed(struct v4l2_rect *a, struct v4l2_rect *b) static int bdisp_s_selection(struct file *file, void *fh, struct v4l2_selection *s) { + struct bdisp_ctx *ctx = file_to_ctx(file); struct bdisp_frame *frame; - struct bdisp_ctx *ctx = fh_to_ctx(fh); struct v4l2_rect *in, out; bool valid = false; @@ -1001,7 +999,7 @@ static int bdisp_s_selection(struct file *file, void *fh, static int bdisp_streamon(struct file *file, void *fh, enum v4l2_buf_type type) { - struct bdisp_ctx *ctx = fh_to_ctx(fh); + struct bdisp_ctx *ctx = file_to_ctx(file); if ((type == V4L2_BUF_TYPE_VIDEO_OUTPUT) && !bdisp_ctx_state_is_set(BDISP_SRC_FMT, ctx)) { From 1b2135910747f573027b5c220f0ede98484fcf6a Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:42 +0300 Subject: [PATCH 00560/11391] media: st: delta: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. Signed-off-by: Jacopo Mondi Co-developed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/platform/st/sti/delta/delta-v4l2.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/st/sti/delta/delta-v4l2.c b/drivers/media/platform/st/sti/delta/delta-v4l2.c index 385b26d21408..6c1a53c771f7 100644 --- a/drivers/media/platform/st/sti/delta/delta-v4l2.c +++ b/drivers/media/platform/st/sti/delta/delta-v4l2.c @@ -24,11 +24,9 @@ #define DELTA_PREFIX "[---:----]" -#define to_ctx(__fh) container_of(__fh, struct delta_ctx, fh) - static inline struct delta_ctx *file_to_ctx(struct file *filp) { - return to_ctx(file_to_v4l2_fh(filp)); + return container_of(file_to_v4l2_fh(filp), struct delta_ctx, fh); } #define to_au(__vbuf) container_of(__vbuf, struct delta_au, vbuf) @@ -727,7 +725,7 @@ static int delta_s_fmt_frame(struct file *file, void *fh, struct v4l2_format *f) static int delta_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct delta_ctx *ctx = to_ctx(fh); + struct delta_ctx *ctx = file_to_ctx(file); struct delta_frameinfo *frameinfo = &ctx->frameinfo; struct v4l2_rect crop; @@ -809,7 +807,7 @@ static int delta_try_decoder_cmd(struct file *file, void *fh, return 0; } -static int delta_decoder_stop_cmd(struct delta_ctx *ctx, void *fh) +static int delta_decoder_stop_cmd(struct delta_ctx *ctx) { const struct delta_dec *dec = ctx->dec; struct delta_dev *delta = ctx->dev; @@ -872,14 +870,14 @@ static int delta_decoder_stop_cmd(struct delta_ctx *ctx, void *fh) static int delta_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd) { - struct delta_ctx *ctx = to_ctx(fh); + struct delta_ctx *ctx = file_to_ctx(file); int ret = 0; ret = delta_try_decoder_cmd(file, fh, cmd); if (ret) return ret; - return delta_decoder_stop_cmd(ctx, fh); + return delta_decoder_stop_cmd(ctx); } static int delta_subscribe_event(struct v4l2_fh *fh, From ecdcfa456e6f6048666c7dd56a0c9b95e50312a5 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:43 +0300 Subject: [PATCH 00561/11391] media: stm32: dma2d: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. Signed-off-by: Jacopo Mondi Signed-off-by: Hans Verkuil --- drivers/media/platform/st/stm32/dma2d/dma2d.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/st/stm32/dma2d/dma2d.c b/drivers/media/platform/st/stm32/dma2d/dma2d.c index bc0f81e78018..a22f587a5f83 100644 --- a/drivers/media/platform/st/stm32/dma2d/dma2d.c +++ b/drivers/media/platform/st/stm32/dma2d/dma2d.c @@ -354,7 +354,7 @@ static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f) static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) { - struct dma2d_ctx *ctx = prv; + struct dma2d_ctx *ctx = file2ctx(file); struct vb2_queue *vq; struct dma2d_frame *frm; @@ -379,7 +379,7 @@ static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f) { - struct dma2d_ctx *ctx = prv; + struct dma2d_ctx *ctx = file2ctx(file); struct dma2d_fmt *fmt; enum v4l2_field *field; u32 fourcc = f->fmt.pix.pixelformat; @@ -422,7 +422,7 @@ static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f) static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) { - struct dma2d_ctx *ctx = prv; + struct dma2d_ctx *ctx = file2ctx(file); struct vb2_queue *vq; struct dma2d_frame *frm; struct dma2d_fmt *fmt; From 7f7c478871170785a5789959402a3e3435273899 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:30:44 +0300 Subject: [PATCH 00562/11391] media: hantro: Access v4l2_fh from file->private_data To prepare for the introduction of video_device_state as second argument of the v4l2_ioctl_ops handler, access the v4l2_fh from file->private_data instead of using void *priv. The file->private_data is initialized to point to the v4l2_fh by the usage of v4l2_fh_init() in the v4l2_file_operations.open() handler. Signed-off-by: Laurent Pinchart Reviewed-by: Paul Kocialkowski Acked-by: Nicolas Dufresne Signed-off-by: Hans Verkuil --- drivers/media/platform/verisilicon/hantro.h | 7 +----- .../media/platform/verisilicon/hantro_v4l2.c | 22 +++++++++---------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/drivers/media/platform/verisilicon/hantro.h b/drivers/media/platform/verisilicon/hantro.h index 5b85c8a44706..e0fdc4535b2d 100644 --- a/drivers/media/platform/verisilicon/hantro.h +++ b/drivers/media/platform/verisilicon/hantro.h @@ -382,14 +382,9 @@ extern int hantro_debug; pr_err("%s:%d: " fmt, __func__, __LINE__, ##args) /* Structure access helpers. */ -static __always_inline struct hantro_ctx *fh_to_ctx(struct v4l2_fh *fh) -{ - return container_of(fh, struct hantro_ctx, fh); -} - static __always_inline struct hantro_ctx *file_to_ctx(struct file *filp) { - return fh_to_ctx(file_to_v4l2_fh(filp)); + return container_of(file_to_v4l2_fh(filp), struct hantro_ctx, fh); } /* Register accessors. */ diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c index 7c3515cf7d64..6bcd892e7bb4 100644 --- a/drivers/media/platform/verisilicon/hantro_v4l2.c +++ b/drivers/media/platform/verisilicon/hantro_v4l2.c @@ -185,7 +185,7 @@ static int vidioc_querycap(struct file *file, void *priv, static int vidioc_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize) { - struct hantro_ctx *ctx = fh_to_ctx(priv); + struct hantro_ctx *ctx = file_to_ctx(file); const struct hantro_fmt *fmt; fmt = hantro_find_format(ctx, fsize->pixel_format); @@ -217,7 +217,7 @@ static int vidioc_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f, bool capture) { - struct hantro_ctx *ctx = fh_to_ctx(priv); + struct hantro_ctx *ctx = file_to_ctx(file); const struct hantro_fmt *fmt, *formats; unsigned int num_fmts, i, j = 0; bool skip_mode_none, enum_all_formats; @@ -297,7 +297,7 @@ static int vidioc_g_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - struct hantro_ctx *ctx = fh_to_ctx(priv); + struct hantro_ctx *ctx = file_to_ctx(file); vpu_debug(4, "f->type = %d\n", f->type); @@ -310,7 +310,7 @@ static int vidioc_g_fmt_cap_mplane(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - struct hantro_ctx *ctx = fh_to_ctx(priv); + struct hantro_ctx *ctx = file_to_ctx(file); vpu_debug(4, "f->type = %d\n", f->type); @@ -398,13 +398,13 @@ static int hantro_try_fmt(const struct hantro_ctx *ctx, static int vidioc_try_fmt_cap_mplane(struct file *file, void *priv, struct v4l2_format *f) { - return hantro_try_fmt(fh_to_ctx(priv), &f->fmt.pix_mp, f->type); + return hantro_try_fmt(file_to_ctx(file), &f->fmt.pix_mp, f->type); } static int vidioc_try_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f) { - return hantro_try_fmt(fh_to_ctx(priv), &f->fmt.pix_mp, f->type); + return hantro_try_fmt(file_to_ctx(file), &f->fmt.pix_mp, f->type); } static void @@ -648,19 +648,19 @@ static int hantro_set_fmt_cap(struct hantro_ctx *ctx, static int vidioc_s_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f) { - return hantro_set_fmt_out(fh_to_ctx(priv), &f->fmt.pix_mp, HANTRO_AUTO_POSTPROC); + return hantro_set_fmt_out(file_to_ctx(file), &f->fmt.pix_mp, HANTRO_AUTO_POSTPROC); } static int vidioc_s_fmt_cap_mplane(struct file *file, void *priv, struct v4l2_format *f) { - return hantro_set_fmt_cap(fh_to_ctx(priv), &f->fmt.pix_mp); + return hantro_set_fmt_cap(file_to_ctx(file), &f->fmt.pix_mp); } static int vidioc_g_selection(struct file *file, void *priv, struct v4l2_selection *sel) { - struct hantro_ctx *ctx = fh_to_ctx(priv); + struct hantro_ctx *ctx = file_to_ctx(file); /* Crop only supported on source. */ if (!ctx->is_encoder || @@ -691,7 +691,7 @@ static int vidioc_g_selection(struct file *file, void *priv, static int vidioc_s_selection(struct file *file, void *priv, struct v4l2_selection *sel) { - struct hantro_ctx *ctx = fh_to_ctx(priv); + struct hantro_ctx *ctx = file_to_ctx(file); struct v4l2_rect *rect = &sel->r; struct vb2_queue *vq; @@ -738,7 +738,7 @@ static const struct v4l2_event hantro_eos_event = { static int vidioc_encoder_cmd(struct file *file, void *priv, struct v4l2_encoder_cmd *ec) { - struct hantro_ctx *ctx = fh_to_ctx(priv); + struct hantro_ctx *ctx = file_to_ctx(file); int ret; ret = v4l2_m2m_ioctl_try_encoder_cmd(file, priv, ec); From 61699f3a2e6f3064a5816374145e3b0cbba4c552 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:45 +0300 Subject: [PATCH 00563/11391] media: omap3isp: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. While at it remove the only left user of to_isp_video_fh() and remove the macro completely. Signed-off-by: Jacopo Mondi Co-developed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/platform/ti/omap3isp/ispvideo.c | 22 +++++++++---------- drivers/media/platform/ti/omap3isp/ispvideo.h | 4 +--- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/drivers/media/platform/ti/omap3isp/ispvideo.c b/drivers/media/platform/ti/omap3isp/ispvideo.c index 2c0008444b7e..0e7f0bf2b346 100644 --- a/drivers/media/platform/ti/omap3isp/ispvideo.c +++ b/drivers/media/platform/ti/omap3isp/ispvideo.c @@ -657,7 +657,7 @@ isp_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap) static int isp_video_get_format(struct file *file, void *fh, struct v4l2_format *format) { - struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video_fh *vfh = file_to_isp_video_fh(file); struct isp_video *video = video_drvdata(file); if (format->type != video->type) @@ -673,7 +673,7 @@ isp_video_get_format(struct file *file, void *fh, struct v4l2_format *format) static int isp_video_set_format(struct file *file, void *fh, struct v4l2_format *format) { - struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video_fh *vfh = file_to_isp_video_fh(file); struct isp_video *video = video_drvdata(file); struct v4l2_mbus_framefmt fmt; @@ -858,7 +858,7 @@ isp_video_set_selection(struct file *file, void *fh, struct v4l2_selection *sel) static int isp_video_get_param(struct file *file, void *fh, struct v4l2_streamparm *a) { - struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video_fh *vfh = file_to_isp_video_fh(file); struct isp_video *video = video_drvdata(file); if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || @@ -876,7 +876,7 @@ isp_video_get_param(struct file *file, void *fh, struct v4l2_streamparm *a) static int isp_video_set_param(struct file *file, void *fh, struct v4l2_streamparm *a) { - struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video_fh *vfh = file_to_isp_video_fh(file); struct isp_video *video = video_drvdata(file); if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || @@ -894,7 +894,7 @@ isp_video_set_param(struct file *file, void *fh, struct v4l2_streamparm *a) static int isp_video_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb) { - struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video_fh *vfh = file_to_isp_video_fh(file); struct isp_video *video = video_drvdata(file); int ret; @@ -908,7 +908,7 @@ isp_video_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb) static int isp_video_querybuf(struct file *file, void *fh, struct v4l2_buffer *b) { - struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video_fh *vfh = file_to_isp_video_fh(file); struct isp_video *video = video_drvdata(file); int ret; @@ -922,7 +922,7 @@ isp_video_querybuf(struct file *file, void *fh, struct v4l2_buffer *b) static int isp_video_qbuf(struct file *file, void *fh, struct v4l2_buffer *b) { - struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video_fh *vfh = file_to_isp_video_fh(file); struct isp_video *video = video_drvdata(file); int ret; @@ -936,7 +936,7 @@ isp_video_qbuf(struct file *file, void *fh, struct v4l2_buffer *b) static int isp_video_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b) { - struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video_fh *vfh = file_to_isp_video_fh(file); struct isp_video *video = video_drvdata(file); int ret; @@ -1074,7 +1074,7 @@ static int isp_video_check_external_subdevs(struct isp_video *video, static int isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) { - struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video_fh *vfh = file_to_isp_video_fh(file); struct isp_video *video = video_drvdata(file); enum isp_pipeline_state state; struct isp_pipeline *pipe; @@ -1180,7 +1180,7 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) static int isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) { - struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video_fh *vfh = file_to_isp_video_fh(file); struct isp_video *video = video_drvdata(file); struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity); enum isp_pipeline_state state; @@ -1348,7 +1348,7 @@ static int isp_video_release(struct file *file) { struct isp_video *video = video_drvdata(file); struct v4l2_fh *vfh = file_to_v4l2_fh(file); - struct isp_video_fh *handle = to_isp_video_fh(vfh); + struct isp_video_fh *handle = file_to_isp_video_fh(file); /* Disable streaming and free the buffers queue resources. */ isp_video_streamoff(file, vfh, video->type); diff --git a/drivers/media/platform/ti/omap3isp/ispvideo.h b/drivers/media/platform/ti/omap3isp/ispvideo.h index 4364b4b14fb4..537da59cff62 100644 --- a/drivers/media/platform/ti/omap3isp/ispvideo.h +++ b/drivers/media/platform/ti/omap3isp/ispvideo.h @@ -194,11 +194,9 @@ struct isp_video_fh { struct v4l2_fract timeperframe; }; -#define to_isp_video_fh(fh) container_of(fh, struct isp_video_fh, vfh) - static inline struct isp_video_fh *file_to_isp_video_fh(struct file *filp) { - return to_isp_video_fh(file_to_v4l2_fh(filp)); + return container_of(file_to_v4l2_fh(filp), struct isp_video_fh, vfh); } #define isp_video_queue_to_isp_video_fh(q) \ From 7b9eb53e8591b67f816fc4ccc57321a9e0c97004 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:46 +0300 Subject: [PATCH 00564/11391] media: cx18: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. Signed-off-by: Jacopo Mondi Signed-off-by: Hans Verkuil --- drivers/media/pci/cx18/cx18-ioctl.c | 64 ++++++++++++++--------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c index 9a1512b1ccaa..bf16d36448f8 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.c +++ b/drivers/media/pci/cx18/cx18-ioctl.c @@ -52,7 +52,7 @@ static const struct v4l2_fmtdesc cx18_formats_mpeg[] = { static int cx18_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct cx18_open_id *id = fh2id(fh); + struct cx18_open_id *id = file2id(file); struct cx18 *cx = id->cx; struct cx18_stream *s = &cx->streams[id->type]; struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; @@ -76,7 +76,7 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh, static int cx18_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct cx18_open_id *id = fh2id(fh); + struct cx18_open_id *id = file2id(file); struct cx18 *cx = id->cx; struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; int w = pixfmt->width; @@ -121,7 +121,7 @@ static int cx18_try_fmt_vid_cap(struct file *file, void *fh, static int cx18_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct cx18_open_id *id = fh2id(fh); + struct cx18_open_id *id = file2id(file); struct cx18 *cx = id->cx; struct v4l2_subdev_format format = { .which = V4L2_SUBDEV_FORMAT_ACTIVE, @@ -261,7 +261,7 @@ u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt) static int cx18_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi; vbifmt->sampling_rate = 27000000; @@ -280,7 +280,7 @@ static int cx18_g_fmt_vbi_cap(struct file *file, void *fh, static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; /* sane, V4L2 spec compliant, defaults */ @@ -311,7 +311,7 @@ static int cx18_try_fmt_vbi_cap(struct file *file, void *fh, static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; @@ -330,7 +330,7 @@ static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh, static int cx18_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct cx18_open_id *id = fh2id(fh); + struct cx18_open_id *id = file2id(file); struct cx18 *cx = id->cx; int ret; @@ -360,7 +360,7 @@ static int cx18_s_fmt_vbi_cap(struct file *file, void *fh, static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct cx18_open_id *id = fh2id(fh); + struct cx18_open_id *id = file2id(file); struct cx18 *cx = id->cx; int ret; struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; @@ -392,7 +392,7 @@ static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh, static int cx18_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; if (reg->reg & 0x3) return -EINVAL; @@ -406,7 +406,7 @@ static int cx18_g_register(struct file *file, void *fh, static int cx18_s_register(struct file *file, void *fh, const struct v4l2_dbg_register *reg) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; if (reg->reg & 0x3) return -EINVAL; @@ -420,7 +420,7 @@ static int cx18_s_register(struct file *file, void *fh, static int cx18_querycap(struct file *file, void *fh, struct v4l2_capability *vcap) { - struct cx18_open_id *id = fh2id(fh); + struct cx18_open_id *id = file2id(file); struct cx18 *cx = id->cx; strscpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver)); @@ -431,14 +431,14 @@ static int cx18_querycap(struct file *file, void *fh, static int cx18_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; return cx18_get_audio_input(cx, vin->index, vin); } static int cx18_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; vin->index = cx->audio_input; return cx18_get_audio_input(cx, vin->index, vin); @@ -446,7 +446,7 @@ static int cx18_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) static int cx18_s_audio(struct file *file, void *fh, const struct v4l2_audio *vout) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; if (vout->index >= cx->nof_audio_inputs) return -EINVAL; @@ -457,7 +457,7 @@ static int cx18_s_audio(struct file *file, void *fh, const struct v4l2_audio *vo static int cx18_enum_input(struct file *file, void *fh, struct v4l2_input *vin) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; /* set it to defaults from our table */ return cx18_get_input(cx, vin->index, vin); @@ -466,7 +466,7 @@ static int cx18_enum_input(struct file *file, void *fh, struct v4l2_input *vin) static int cx18_g_pixelaspect(struct file *file, void *fh, int type, struct v4l2_fract *f) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -479,7 +479,7 @@ static int cx18_g_pixelaspect(struct file *file, void *fh, static int cx18_g_selection(struct file *file, void *fh, struct v4l2_selection *sel) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -499,7 +499,7 @@ static int cx18_g_selection(struct file *file, void *fh, static int cx18_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) { - struct cx18_open_id *id = fh2id(fh); + struct cx18_open_id *id = file2id(file); if (id->type == CX18_ENC_STREAM_TYPE_YUV) { if (fmt->index >= ARRAY_SIZE(cx18_formats_yuv)) @@ -515,7 +515,7 @@ static int cx18_enum_fmt_vid_cap(struct file *file, void *fh, static int cx18_g_input(struct file *file, void *fh, unsigned int *i) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; *i = cx->active_input; return 0; @@ -523,7 +523,7 @@ static int cx18_g_input(struct file *file, void *fh, unsigned int *i) int cx18_s_input(struct file *file, void *fh, unsigned int inp) { - struct cx18_open_id *id = fh2id(fh); + struct cx18_open_id *id = file2id(file); struct cx18 *cx = id->cx; v4l2_std_id std = V4L2_STD_ALL; const struct cx18_card_video_input *card_input = @@ -561,7 +561,7 @@ int cx18_s_input(struct file *file, void *fh, unsigned int inp) static int cx18_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; if (vf->tuner != 0) return -EINVAL; @@ -572,7 +572,7 @@ static int cx18_g_frequency(struct file *file, void *fh, int cx18_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf) { - struct cx18_open_id *id = fh2id(fh); + struct cx18_open_id *id = file2id(file); struct cx18 *cx = id->cx; if (vf->tuner != 0) @@ -587,7 +587,7 @@ int cx18_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *v static int cx18_g_std(struct file *file, void *fh, v4l2_std_id *std) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; *std = cx->std; return 0; @@ -595,7 +595,7 @@ static int cx18_g_std(struct file *file, void *fh, v4l2_std_id *std) int cx18_s_std(struct file *file, void *fh, v4l2_std_id std) { - struct cx18_open_id *id = fh2id(fh); + struct cx18_open_id *id = file2id(file); struct cx18 *cx = id->cx; if ((std & V4L2_STD_ALL) == 0) @@ -644,7 +644,7 @@ int cx18_s_std(struct file *file, void *fh, v4l2_std_id std) static int cx18_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) { - struct cx18_open_id *id = fh2id(fh); + struct cx18_open_id *id = file2id(file); struct cx18 *cx = id->cx; if (vt->index != 0) @@ -656,7 +656,7 @@ static int cx18_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; if (vt->index != 0) return -EINVAL; @@ -673,7 +673,7 @@ static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) static int cx18_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525; int f, l; @@ -794,7 +794,7 @@ static int cx18_process_idx_data(struct cx18_stream *s, struct cx18_mdl *mdl, static int cx18_g_enc_index(struct file *file, void *fh, struct v4l2_enc_idx *idx) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; s32 tmp; struct cx18_mdl *mdl; @@ -841,7 +841,7 @@ static int cx18_g_enc_index(struct file *file, void *fh, static int cx18_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc) { - struct cx18_open_id *id = fh2id(fh); + struct cx18_open_id *id = file2id(file); struct cx18 *cx = id->cx; u32 h; @@ -900,7 +900,7 @@ static int cx18_encoder_cmd(struct file *file, void *fh, static int cx18_try_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; switch (enc->cmd) { case V4L2_ENC_CMD_START: @@ -932,7 +932,7 @@ static int cx18_try_encoder_cmd(struct file *file, void *fh, static int cx18_log_status(struct file *file, void *fh) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; struct v4l2_input vidin; struct v4l2_audio audin; int i; @@ -976,7 +976,7 @@ static int cx18_log_status(struct file *file, void *fh) static long cx18_default(struct file *file, void *fh, bool valid_prio, unsigned int cmd, void *arg) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; switch (cmd) { case VIDIOC_INT_RESET: { From 9ba9d11544f994095d60e68339a1bf203ec4a474 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:47 +0300 Subject: [PATCH 00565/11391] media: ivtv: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. While at it remove the only left user of fh2id() and remove the macro completely. Signed-off-by: Jacopo Mondi Co-developed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/pci/ivtv/ivtv-driver.h | 7 +- drivers/media/pci/ivtv/ivtv-fileops.c | 2 +- drivers/media/pci/ivtv/ivtv-ioctl.c | 124 +++++++++++++------------- 3 files changed, 64 insertions(+), 69 deletions(-) diff --git a/drivers/media/pci/ivtv/ivtv-driver.h b/drivers/media/pci/ivtv/ivtv-driver.h index 3d84004d4e90..69c37f450c21 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.h +++ b/drivers/media/pci/ivtv/ivtv-driver.h @@ -384,14 +384,9 @@ struct ivtv_open_id { struct ivtv *itv; }; -static inline struct ivtv_open_id *fh2id(struct v4l2_fh *fh) -{ - return container_of(fh, struct ivtv_open_id, fh); -} - static inline struct ivtv_open_id *file2id(struct file *filp) { - return fh2id(file_to_v4l2_fh(filp)); + return container_of(file_to_v4l2_fh(filp), struct ivtv_open_id, fh); } struct yuv_frame_info diff --git a/drivers/media/pci/ivtv/ivtv-fileops.c b/drivers/media/pci/ivtv/ivtv-fileops.c index 0040a5e7f654..814fe7989cdc 100644 --- a/drivers/media/pci/ivtv/ivtv-fileops.c +++ b/drivers/media/pci/ivtv/ivtv-fileops.c @@ -878,7 +878,7 @@ static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts) int ivtv_v4l2_close(struct file *filp) { struct v4l2_fh *fh = file_to_v4l2_fh(filp); - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(filp); struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index d888435b71fb..8077a71d4850 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -308,7 +308,7 @@ static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id, static int ivtv_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; vbifmt->reserved[0] = 0; @@ -330,7 +330,7 @@ static int ivtv_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_fo static int ivtv_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; @@ -353,7 +353,7 @@ static int ivtv_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f static int ivtv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi; vbifmt->sampling_rate = 27000000; @@ -372,7 +372,7 @@ static int ivtv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f static int ivtv_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; vbifmt->reserved[0] = 0; @@ -394,7 +394,7 @@ static int ivtv_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_fo static int ivtv_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; @@ -434,8 +434,8 @@ static int ivtv_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *f static int ivtv_g_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv *itv = fh2id(fh)->itv; - struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; + struct ivtv *itv = file2id(file)->itv; + struct ivtv_stream *s = &itv->streams[file2id(file)->type]; struct v4l2_window *winfmt = &fmt->fmt.win; if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) @@ -461,7 +461,7 @@ static int ivtv_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_ static int ivtv_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; int w = fmt->fmt.pix.width; int h = fmt->fmt.pix.height; @@ -490,7 +490,7 @@ static int ivtv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format static int ivtv_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; if (id->type == IVTV_DEC_STREAM_TYPE_VBI) @@ -510,7 +510,7 @@ static int ivtv_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_ static int ivtv_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); s32 w = fmt->fmt.pix.width; s32 h = fmt->fmt.pix.height; int field = fmt->fmt.pix.field; @@ -544,8 +544,8 @@ static int ivtv_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format static int ivtv_try_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv *itv = fh2id(fh)->itv; - struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; + struct ivtv *itv = file2id(file)->itv; + struct ivtv_stream *s = &itv->streams[file2id(file)->type]; u32 chromakey = fmt->fmt.win.chromakey; u8 global_alpha = fmt->fmt.win.global_alpha; @@ -566,7 +566,7 @@ static int ivtv_s_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_fo static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; struct v4l2_subdev_format format = { .which = V4L2_SUBDEV_FORMAT_ACTIVE, @@ -597,7 +597,7 @@ static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f static int ivtv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; if (!ivtv_raw_vbi(itv) && atomic_read(&itv->capturing) > 0) return -EBUSY; @@ -610,7 +610,7 @@ static int ivtv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f static int ivtv_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; int ret = ivtv_try_fmt_sliced_vbi_cap(file, fh, fmt); @@ -628,7 +628,7 @@ static int ivtv_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_fo static int ivtv_s_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; struct yuv_playback_info *yi = &itv->yuv_info; int ret = ivtv_try_fmt_vid_out(file, fh, fmt); @@ -673,7 +673,7 @@ static int ivtv_s_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *f static int ivtv_s_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; int ret = ivtv_try_fmt_vid_out_overlay(file, fh, fmt); if (ret == 0) { @@ -710,7 +710,7 @@ static int ivtv_itvc(struct ivtv *itv, bool get, u64 reg, u64 *val) static int ivtv_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; reg->size = 4; return ivtv_itvc(itv, true, reg->reg, ®->val); @@ -718,7 +718,7 @@ static int ivtv_g_register(struct file *file, void *fh, struct v4l2_dbg_register static int ivtv_s_register(struct file *file, void *fh, const struct v4l2_dbg_register *reg) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; u64 val = reg->val; return ivtv_itvc(itv, false, reg->reg, &val); @@ -727,7 +727,7 @@ static int ivtv_s_register(struct file *file, void *fh, const struct v4l2_dbg_re static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vcap) { - struct ivtv_open_id *id = fh2id(file_to_v4l2_fh(file)); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; strscpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver)); @@ -738,14 +738,14 @@ static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vc static int ivtv_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; return ivtv_get_audio_input(itv, vin->index, vin); } static int ivtv_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; vin->index = itv->audio_input; return ivtv_get_audio_input(itv, vin->index, vin); @@ -753,7 +753,7 @@ static int ivtv_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) static int ivtv_s_audio(struct file *file, void *fh, const struct v4l2_audio *vout) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; if (vout->index >= itv->nof_audio_inputs) return -EINVAL; @@ -766,7 +766,7 @@ static int ivtv_s_audio(struct file *file, void *fh, const struct v4l2_audio *vo static int ivtv_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vin) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; /* set it to defaults from our table */ return ivtv_get_audio_output(itv, vin->index, vin); @@ -774,7 +774,7 @@ static int ivtv_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vi static int ivtv_g_audout(struct file *file, void *fh, struct v4l2_audioout *vin) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; vin->index = 0; return ivtv_get_audio_output(itv, vin->index, vin); @@ -782,7 +782,7 @@ static int ivtv_g_audout(struct file *file, void *fh, struct v4l2_audioout *vin) static int ivtv_s_audout(struct file *file, void *fh, const struct v4l2_audioout *vout) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; if (itv->card->video_outputs == NULL || vout->index != 0) return -EINVAL; @@ -791,7 +791,7 @@ static int ivtv_s_audout(struct file *file, void *fh, const struct v4l2_audioout static int ivtv_enum_input(struct file *file, void *fh, struct v4l2_input *vin) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; /* set it to defaults from our table */ return ivtv_get_input(itv, vin->index, vin); @@ -799,7 +799,7 @@ static int ivtv_enum_input(struct file *file, void *fh, struct v4l2_input *vin) static int ivtv_enum_output(struct file *file, void *fh, struct v4l2_output *vout) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; return ivtv_get_output(itv, vout->index, vout); } @@ -807,7 +807,7 @@ static int ivtv_enum_output(struct file *file, void *fh, struct v4l2_output *vou static int ivtv_g_pixelaspect(struct file *file, void *fh, int type, struct v4l2_fract *f) { - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { @@ -825,7 +825,7 @@ static int ivtv_g_pixelaspect(struct file *file, void *fh, static int ivtv_s_selection(struct file *file, void *fh, struct v4l2_selection *sel) { - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; struct yuv_playback_info *yi = &itv->yuv_info; struct v4l2_rect r = { 0, 0, 720, 0 }; @@ -868,7 +868,7 @@ static int ivtv_s_selection(struct file *file, void *fh, static int ivtv_g_selection(struct file *file, void *fh, struct v4l2_selection *sel) { - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; struct yuv_playback_info *yi = &itv->yuv_info; struct v4l2_rect r = { 0, 0, 720, 0 }; @@ -924,8 +924,8 @@ static int ivtv_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdes .description = "MPEG", .pixelformat = V4L2_PIX_FMT_MPEG, }; - struct ivtv *itv = fh2id(fh)->itv; - struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; + struct ivtv *itv = file2id(file)->itv; + struct ivtv_stream *s = &itv->streams[file2id(file)->type]; if (fmt->index) return -EINVAL; @@ -951,8 +951,8 @@ static int ivtv_enum_fmt_vid_out(struct file *file, void *fh, struct v4l2_fmtdes .description = "MPEG", .pixelformat = V4L2_PIX_FMT_MPEG, }; - struct ivtv *itv = fh2id(fh)->itv; - struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; + struct ivtv *itv = file2id(file)->itv; + struct ivtv_stream *s = &itv->streams[file2id(file)->type]; if (fmt->index) return -EINVAL; @@ -967,7 +967,7 @@ static int ivtv_enum_fmt_vid_out(struct file *file, void *fh, struct v4l2_fmtdes static int ivtv_g_input(struct file *file, void *fh, unsigned int *i) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; *i = itv->active_input; @@ -976,7 +976,7 @@ static int ivtv_g_input(struct file *file, void *fh, unsigned int *i) int ivtv_s_input(struct file *file, void *fh, unsigned int inp) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; v4l2_std_id std; int i; @@ -1019,7 +1019,7 @@ int ivtv_s_input(struct file *file, void *fh, unsigned int inp) static int ivtv_g_output(struct file *file, void *fh, unsigned int *i) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) return -EINVAL; @@ -1031,7 +1031,7 @@ static int ivtv_g_output(struct file *file, void *fh, unsigned int *i) static int ivtv_s_output(struct file *file, void *fh, unsigned int outp) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; if (outp >= itv->card->nof_outputs) return -EINVAL; @@ -1053,8 +1053,8 @@ static int ivtv_s_output(struct file *file, void *fh, unsigned int outp) static int ivtv_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) { - struct ivtv *itv = fh2id(fh)->itv; - struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; + struct ivtv *itv = file2id(file)->itv; + struct ivtv_stream *s = &itv->streams[file2id(file)->type]; if (s->vdev.vfl_dir) return -ENOTTY; @@ -1067,8 +1067,8 @@ static int ivtv_g_frequency(struct file *file, void *fh, struct v4l2_frequency * int ivtv_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf) { - struct ivtv *itv = fh2id(fh)->itv; - struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; + struct ivtv *itv = file2id(file)->itv; + struct ivtv_stream *s = &itv->streams[file2id(file)->type]; if (s->vdev.vfl_dir) return -ENOTTY; @@ -1084,7 +1084,7 @@ int ivtv_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *v static int ivtv_g_std(struct file *file, void *fh, v4l2_std_id *std) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; *std = itv->std; return 0; @@ -1157,7 +1157,7 @@ void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id std) static int ivtv_s_std(struct file *file, void *fh, v4l2_std_id std) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; if ((std & V4L2_STD_ALL) == 0) return -EINVAL; @@ -1185,7 +1185,7 @@ static int ivtv_s_std(struct file *file, void *fh, v4l2_std_id std) static int ivtv_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) { - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; if (vt->index != 0) @@ -1198,7 +1198,7 @@ static int ivtv_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt static int ivtv_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; if (vt->index != 0) return -EINVAL; @@ -1214,7 +1214,7 @@ static int ivtv_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) static int ivtv_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; int set = itv->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525; int f, l; @@ -1249,7 +1249,7 @@ static int ivtv_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced static int ivtv_g_enc_index(struct file *file, void *fh, struct v4l2_enc_idx *idx) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; struct v4l2_enc_idx_entry *e = idx->entry; int entries; int i; @@ -1275,7 +1275,7 @@ static int ivtv_g_enc_index(struct file *file, void *fh, struct v4l2_enc_idx *id static int ivtv_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc) { - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; @@ -1327,7 +1327,7 @@ static int ivtv_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd static int ivtv_try_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; switch (enc->cmd) { case V4L2_ENC_CMD_START: @@ -1357,8 +1357,8 @@ static int ivtv_try_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder static int ivtv_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) { - struct ivtv *itv = fh2id(fh)->itv; - struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; + struct ivtv *itv = file2id(file)->itv; + struct ivtv_stream *s = &itv->streams[file2id(file)->type]; u32 data[CX2341X_MBOX_MAX_DATA]; struct yuv_playback_info *yi = &itv->yuv_info; @@ -1444,9 +1444,9 @@ static int ivtv_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) static int ivtv_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *fb) { - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; - struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; + struct ivtv_stream *s = &itv->streams[file2id(file)->type]; struct yuv_playback_info *yi = &itv->yuv_info; if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) @@ -1465,9 +1465,9 @@ static int ivtv_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffe static int ivtv_overlay(struct file *file, void *fh, unsigned int on) { - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; - struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; + struct ivtv_stream *s = &itv->streams[file2id(file)->type]; if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) return -ENOTTY; @@ -1492,7 +1492,7 @@ static int ivtv_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subs static int ivtv_log_status(struct file *file, void *fh) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; u32 data[CX2341X_MBOX_MAX_DATA]; int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT; @@ -1584,7 +1584,7 @@ static int ivtv_log_status(struct file *file, void *fh) static int ivtv_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dec) { - struct ivtv_open_id *id = fh2id(file_to_v4l2_fh(file)); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; IVTV_DEBUG_IOCTL("VIDIOC_DECODER_CMD %d\n", dec->cmd); @@ -1593,7 +1593,7 @@ static int ivtv_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd static int ivtv_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dec) { - struct ivtv_open_id *id = fh2id(file_to_v4l2_fh(file)); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; IVTV_DEBUG_IOCTL("VIDIOC_TRY_DECODER_CMD %d\n", dec->cmd); @@ -1602,7 +1602,7 @@ static int ivtv_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) { - struct ivtv_open_id *id = fh2id(file_to_v4l2_fh(filp)); + struct ivtv_open_id *id = file2id(filp); struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; @@ -1645,7 +1645,7 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) static long ivtv_default(struct file *file, void *fh, bool valid_prio, unsigned int cmd, void *arg) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; if (!valid_prio) { switch (cmd) { From 536a8cdb4a5217dc3ce7d81ba67bc96e07cdba05 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:48 +0300 Subject: [PATCH 00566/11391] media: usb: hdpvr: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. Signed-off-by: Jacopo Mondi Signed-off-by: Hans Verkuil --- drivers/media/usb/hdpvr/hdpvr-video.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index 6c6e467f8554..8a5c2c5227eb 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -52,6 +52,11 @@ struct hdpvr_fh { bool legacy_mode; }; +static inline struct hdpvr_fh *file_to_hdpvr_fh(struct file *file) +{ + return container_of(file_to_v4l2_fh(file), struct hdpvr_fh, fh); +} + static uint list_size(struct list_head *list) { struct list_head *tmp; @@ -589,7 +594,7 @@ static int vidioc_s_std(struct file *file, void *_fh, v4l2_std_id std) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); u8 std_type = 1; if (!fh->legacy_mode && dev->options.video_input == HDPVR_COMPONENT) @@ -609,7 +614,8 @@ static int vidioc_g_std(struct file *file, void *_fh, v4l2_std_id *std) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); + if (!fh->legacy_mode && dev->options.video_input == HDPVR_COMPONENT) return -ENODATA; @@ -620,8 +626,8 @@ static int vidioc_g_std(struct file *file, void *_fh, static int vidioc_querystd(struct file *file, void *_fh, v4l2_std_id *a) { struct hdpvr_device *dev = video_drvdata(file); + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); struct hdpvr_video_info vid_info; - struct hdpvr_fh *fh = _fh; int ret; *a = V4L2_STD_UNKNOWN; @@ -640,7 +646,7 @@ static int vidioc_s_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); int i; fh->legacy_mode = false; @@ -663,7 +669,7 @@ static int vidioc_g_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); fh->legacy_mode = false; if (dev->options.video_input) @@ -676,7 +682,7 @@ static int vidioc_query_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); struct hdpvr_video_info vid_info; bool interlaced; int ret = 0; @@ -718,7 +724,7 @@ static int vidioc_enum_dv_timings(struct file *file, void *_fh, struct v4l2_enum_dv_timings *timings) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); fh->legacy_mode = false; memset(timings->reserved, 0, sizeof(timings->reserved)); @@ -734,7 +740,7 @@ static int vidioc_dv_timings_cap(struct file *file, void *_fh, struct v4l2_dv_timings_cap *cap) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); fh->legacy_mode = false; if (dev->options.video_input) @@ -994,7 +1000,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *_fh, struct v4l2_format *f) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); int ret; /* From ee7aa3dff32e1745bd501b0d442f347aa111d04f Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:49 +0300 Subject: [PATCH 00567/11391] media: usb: uvc: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. Signed-off-by: Jacopo Mondi Signed-off-by: Hans Verkuil --- drivers/media/usb/uvc/uvc_v4l2.c | 36 ++++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 09677ed639ae..10196d62f287 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -391,7 +391,7 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, static int uvc_ioctl_g_fmt(struct file *file, void *fh, struct v4l2_format *fmt) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; const struct uvc_format *format; const struct uvc_frame *frame; @@ -427,7 +427,7 @@ static int uvc_ioctl_g_fmt(struct file *file, void *fh, static int uvc_ioctl_s_fmt(struct file *file, void *fh, struct v4l2_format *fmt) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; struct uvc_streaming_control probe; const struct uvc_format *format; @@ -460,7 +460,7 @@ static int uvc_ioctl_g_parm(struct file *file, void *fh, struct v4l2_streamparm *parm) { u32 numerator, denominator; - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; if (parm->type != stream->type) @@ -496,7 +496,7 @@ static int uvc_ioctl_g_parm(struct file *file, void *fh, static int uvc_ioctl_s_parm(struct file *file, void *fh, struct v4l2_streamparm *parm) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; struct uvc_streaming_control probe; struct v4l2_fract timeperframe; @@ -641,7 +641,7 @@ static int uvc_ioctl_querycap(struct file *file, void *fh, static int uvc_ioctl_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; enum v4l2_buf_type type = fmt->type; const struct uvc_format *format; @@ -665,7 +665,7 @@ static int uvc_ioctl_enum_fmt(struct file *file, void *fh, static int uvc_ioctl_try_fmt(struct file *file, void *fh, struct v4l2_format *fmt) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; struct uvc_streaming_control probe; @@ -675,7 +675,7 @@ static int uvc_ioctl_try_fmt(struct file *file, void *fh, static int uvc_ioctl_enum_input(struct file *file, void *fh, struct v4l2_input *input) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; const struct uvc_entity *selector = chain->selector; struct uvc_entity *iterm = NULL; @@ -717,7 +717,7 @@ static int uvc_ioctl_enum_input(struct file *file, void *fh, static int uvc_ioctl_g_input(struct file *file, void *fh, unsigned int *input) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; u8 *buf; int ret; @@ -745,7 +745,7 @@ static int uvc_ioctl_g_input(struct file *file, void *fh, unsigned int *input) static int uvc_ioctl_s_input(struct file *file, void *fh, unsigned int input) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; struct uvc_video_chain *chain = handle->chain; u8 *buf; @@ -780,7 +780,7 @@ static int uvc_ioctl_s_input(struct file *file, void *fh, unsigned int input) static int uvc_ioctl_query_ext_ctrl(struct file *file, void *fh, struct v4l2_query_ext_ctrl *qec) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; return uvc_query_v4l2_ctrl(chain, qec); @@ -808,7 +808,7 @@ static int uvc_ctrl_check_access(struct uvc_video_chain *chain, static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *ctrls) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; struct v4l2_ext_control *ctrl = ctrls->controls; unsigned int i; @@ -892,7 +892,7 @@ static int uvc_ioctl_s_try_ext_ctrls(struct uvc_fh *handle, static int uvc_ioctl_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *ctrls) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); return uvc_ioctl_s_try_ext_ctrls(handle, ctrls, VIDIOC_S_EXT_CTRLS); } @@ -900,7 +900,7 @@ static int uvc_ioctl_s_ext_ctrls(struct file *file, void *fh, static int uvc_ioctl_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *ctrls) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); return uvc_ioctl_s_try_ext_ctrls(handle, ctrls, VIDIOC_TRY_EXT_CTRLS); } @@ -908,7 +908,7 @@ static int uvc_ioctl_try_ext_ctrls(struct file *file, void *fh, static int uvc_ioctl_querymenu(struct file *file, void *fh, struct v4l2_querymenu *qm) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; return uvc_query_v4l2_menu(chain, qm); @@ -917,7 +917,7 @@ static int uvc_ioctl_querymenu(struct file *file, void *fh, static int uvc_ioctl_g_selection(struct file *file, void *fh, struct v4l2_selection *sel) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; if (sel->type != stream->type) @@ -951,7 +951,7 @@ static int uvc_ioctl_g_selection(struct file *file, void *fh, static int uvc_ioctl_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; const struct uvc_format *format = NULL; const struct uvc_frame *frame = NULL; @@ -991,7 +991,7 @@ static int uvc_ioctl_enum_framesizes(struct file *file, void *fh, static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh, struct v4l2_frmivalenum *fival) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; const struct uvc_format *format = NULL; const struct uvc_frame *frame = NULL; @@ -1063,7 +1063,7 @@ static int uvc_ioctl_subscribe_event(struct v4l2_fh *fh, static long uvc_ioctl_default(struct file *file, void *fh, bool valid_prio, unsigned int cmd, void *arg) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; switch (cmd) { From d2683099c456c82894d214175862a14bc13bbd09 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sun, 10 Aug 2025 04:30:50 +0300 Subject: [PATCH 00568/11391] media: staging: imx: Access v4l2_fh from file The v4l2_fh associated with an open file handle is now guaranteed to be available in file->private_data, initialised by v4l2_fh_add(). Access the v4l2_fh, and from there the driver-specific structure, from the file * in all ioctl handlers. Signed-off-by: Jacopo Mondi Co-developed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/staging/media/imx/imx-media-csc-scaler.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/staging/media/imx/imx-media-csc-scaler.c b/drivers/staging/media/imx/imx-media-csc-scaler.c index dc7f9a77cbe6..1869c5792ecb 100644 --- a/drivers/staging/media/imx/imx-media-csc-scaler.c +++ b/drivers/staging/media/imx/imx-media-csc-scaler.c @@ -23,8 +23,6 @@ #include "imx-media.h" -#define fh_to_ctx(__fh) container_of(__fh, struct ipu_csc_scaler_ctx, fh) - #define IMX_CSC_SCALER_NAME "imx-csc-scaler" enum { @@ -68,7 +66,7 @@ struct ipu_csc_scaler_ctx { static inline struct ipu_csc_scaler_ctx *file_to_ctx(struct file *filp) { - return fh_to_ctx(file_to_v4l2_fh(filp)); + return container_of(file_to_v4l2_fh(filp), struct ipu_csc_scaler_ctx, fh); } static struct ipu_csc_scaler_q_data *get_q_data(struct ipu_csc_scaler_ctx *ctx, @@ -184,7 +182,7 @@ static int ipu_csc_scaler_enum_fmt(struct file *file, void *fh, static int ipu_csc_scaler_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct ipu_csc_scaler_ctx *ctx = fh_to_ctx(priv); + struct ipu_csc_scaler_ctx *ctx = file_to_ctx(file); struct ipu_csc_scaler_q_data *q_data; q_data = get_q_data(ctx, f->type); @@ -197,7 +195,7 @@ static int ipu_csc_scaler_g_fmt(struct file *file, void *priv, static int ipu_csc_scaler_try_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct ipu_csc_scaler_ctx *ctx = fh_to_ctx(priv); + struct ipu_csc_scaler_ctx *ctx = file_to_ctx(file); struct ipu_csc_scaler_q_data *q_data = get_q_data(ctx, f->type); struct ipu_image test_in, test_out; enum v4l2_field field; @@ -245,8 +243,8 @@ static int ipu_csc_scaler_try_fmt(struct file *file, void *priv, static int ipu_csc_scaler_s_fmt(struct file *file, void *priv, struct v4l2_format *f) { + struct ipu_csc_scaler_ctx *ctx = file_to_ctx(file); struct ipu_csc_scaler_q_data *q_data; - struct ipu_csc_scaler_ctx *ctx = fh_to_ctx(priv); struct vb2_queue *vq; int ret; @@ -301,7 +299,7 @@ static int ipu_csc_scaler_s_fmt(struct file *file, void *priv, static int ipu_csc_scaler_g_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct ipu_csc_scaler_ctx *ctx = fh_to_ctx(priv); + struct ipu_csc_scaler_ctx *ctx = file_to_ctx(file); struct ipu_csc_scaler_q_data *q_data; switch (s->target) { @@ -339,7 +337,7 @@ static int ipu_csc_scaler_g_selection(struct file *file, void *priv, static int ipu_csc_scaler_s_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct ipu_csc_scaler_ctx *ctx = fh_to_ctx(priv); + struct ipu_csc_scaler_ctx *ctx = file_to_ctx(file); struct ipu_csc_scaler_q_data *q_data; switch (s->target) { From 0f1a7facb64abe5104c3eb235824ea8d6296474d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:30:51 +0300 Subject: [PATCH 00569/11391] media: v4l2-ioctl: Stop passing fh pointer to ioctl handlers Now that all drivers access the v4l2_fh from the file structure, there is no need to pass it as an explicit argument to ioctl handlers. Set the argument to NULL in the __video_do_ioctl() function, and rename the 'fh' argument in the ioctl handler declarations to 'priv' indicate it does not contain a file handle. The argument could be removed altogether with a mechanical change (probably using coccinelle), but there are plans to pass a new argument to the ioctl handlers in the near future. The tree-wide change to remove the argument, only to add another one soon after, would be too much churn. While at it, fix argument alignment in vidioc_try_fmt_vid_out_overlay(). Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 2 +- drivers/media/v4l2-core/v4l2-ioctl.c | 4 +- include/media/v4l2-ioctl.h | 238 +++++++++--------- 3 files changed, 122 insertions(+), 122 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index e5642e639811..85c10ba9f813 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -691,7 +691,7 @@ static inline bool ctrl_is_pointer(struct file *file, u32 id) if (!ops || !ops->vidioc_query_ext_ctrl) return false; - return !ops->vidioc_query_ext_ctrl(file, fh, &qec) && + return !ops->vidioc_query_ext_ctrl(file, NULL, &qec) && (qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD); } diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 378a2a149fec..d815291624a9 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -3126,11 +3126,11 @@ static long __video_do_ioctl(struct file *file, write_only = _IOC_DIR(cmd) == _IOC_WRITE; if (info != &default_info) { - ret = info->func(ops, file, vfh, arg); + ret = info->func(ops, file, NULL, arg); } else if (!ops->vidioc_default) { ret = -ENOTTY; } else { - ret = ops->vidioc_default(file, vfh, + ret = ops->vidioc_default(file, NULL, v4l2_prio_check(vfd->prio, vfh->prio) >= 0, cmd, arg); } diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index 82695c3a300a..6f7a58350441 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -293,144 +293,144 @@ struct v4l2_ioctl_ops { /* ioctl callbacks */ /* VIDIOC_QUERYCAP handler */ - int (*vidioc_querycap)(struct file *file, void *fh, + int (*vidioc_querycap)(struct file *file, void *priv, struct v4l2_capability *cap); /* VIDIOC_ENUM_FMT handlers */ - int (*vidioc_enum_fmt_vid_cap)(struct file *file, void *fh, + int (*vidioc_enum_fmt_vid_cap)(struct file *file, void *priv, struct v4l2_fmtdesc *f); - int (*vidioc_enum_fmt_vid_overlay)(struct file *file, void *fh, + int (*vidioc_enum_fmt_vid_overlay)(struct file *file, void *priv, struct v4l2_fmtdesc *f); - int (*vidioc_enum_fmt_vid_out)(struct file *file, void *fh, + int (*vidioc_enum_fmt_vid_out)(struct file *file, void *priv, struct v4l2_fmtdesc *f); - int (*vidioc_enum_fmt_sdr_cap)(struct file *file, void *fh, + int (*vidioc_enum_fmt_sdr_cap)(struct file *file, void *priv, struct v4l2_fmtdesc *f); - int (*vidioc_enum_fmt_sdr_out)(struct file *file, void *fh, + int (*vidioc_enum_fmt_sdr_out)(struct file *file, void *priv, struct v4l2_fmtdesc *f); - int (*vidioc_enum_fmt_meta_cap)(struct file *file, void *fh, + int (*vidioc_enum_fmt_meta_cap)(struct file *file, void *priv, struct v4l2_fmtdesc *f); - int (*vidioc_enum_fmt_meta_out)(struct file *file, void *fh, + int (*vidioc_enum_fmt_meta_out)(struct file *file, void *priv, struct v4l2_fmtdesc *f); /* VIDIOC_G_FMT handlers */ - int (*vidioc_g_fmt_vid_cap)(struct file *file, void *fh, + int (*vidioc_g_fmt_vid_cap)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_g_fmt_vid_overlay)(struct file *file, void *fh, + int (*vidioc_g_fmt_vid_overlay)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_g_fmt_vid_out)(struct file *file, void *fh, + int (*vidioc_g_fmt_vid_out)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_g_fmt_vid_out_overlay)(struct file *file, void *fh, + int (*vidioc_g_fmt_vid_out_overlay)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_g_fmt_vbi_cap)(struct file *file, void *fh, + int (*vidioc_g_fmt_vbi_cap)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_g_fmt_vbi_out)(struct file *file, void *fh, + int (*vidioc_g_fmt_vbi_out)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_g_fmt_sliced_vbi_cap)(struct file *file, void *fh, + int (*vidioc_g_fmt_sliced_vbi_cap)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_g_fmt_sliced_vbi_out)(struct file *file, void *fh, + int (*vidioc_g_fmt_sliced_vbi_out)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_g_fmt_vid_cap_mplane)(struct file *file, void *fh, + int (*vidioc_g_fmt_vid_cap_mplane)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_g_fmt_vid_out_mplane)(struct file *file, void *fh, + int (*vidioc_g_fmt_vid_out_mplane)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_g_fmt_sdr_cap)(struct file *file, void *fh, + int (*vidioc_g_fmt_sdr_cap)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_g_fmt_sdr_out)(struct file *file, void *fh, + int (*vidioc_g_fmt_sdr_out)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_g_fmt_meta_cap)(struct file *file, void *fh, + int (*vidioc_g_fmt_meta_cap)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_g_fmt_meta_out)(struct file *file, void *fh, + int (*vidioc_g_fmt_meta_out)(struct file *file, void *priv, struct v4l2_format *f); /* VIDIOC_S_FMT handlers */ - int (*vidioc_s_fmt_vid_cap)(struct file *file, void *fh, + int (*vidioc_s_fmt_vid_cap)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_s_fmt_vid_overlay)(struct file *file, void *fh, + int (*vidioc_s_fmt_vid_overlay)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_s_fmt_vid_out)(struct file *file, void *fh, + int (*vidioc_s_fmt_vid_out)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_s_fmt_vid_out_overlay)(struct file *file, void *fh, + int (*vidioc_s_fmt_vid_out_overlay)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_s_fmt_vbi_cap)(struct file *file, void *fh, + int (*vidioc_s_fmt_vbi_cap)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_s_fmt_vbi_out)(struct file *file, void *fh, + int (*vidioc_s_fmt_vbi_out)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_s_fmt_sliced_vbi_cap)(struct file *file, void *fh, + int (*vidioc_s_fmt_sliced_vbi_cap)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_s_fmt_sliced_vbi_out)(struct file *file, void *fh, + int (*vidioc_s_fmt_sliced_vbi_out)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_s_fmt_vid_cap_mplane)(struct file *file, void *fh, + int (*vidioc_s_fmt_vid_cap_mplane)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_s_fmt_vid_out_mplane)(struct file *file, void *fh, + int (*vidioc_s_fmt_vid_out_mplane)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_s_fmt_sdr_cap)(struct file *file, void *fh, + int (*vidioc_s_fmt_sdr_cap)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_s_fmt_sdr_out)(struct file *file, void *fh, + int (*vidioc_s_fmt_sdr_out)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_s_fmt_meta_cap)(struct file *file, void *fh, + int (*vidioc_s_fmt_meta_cap)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_s_fmt_meta_out)(struct file *file, void *fh, + int (*vidioc_s_fmt_meta_out)(struct file *file, void *priv, struct v4l2_format *f); /* VIDIOC_TRY_FMT handlers */ - int (*vidioc_try_fmt_vid_cap)(struct file *file, void *fh, + int (*vidioc_try_fmt_vid_cap)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_try_fmt_vid_overlay)(struct file *file, void *fh, + int (*vidioc_try_fmt_vid_overlay)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_try_fmt_vid_out)(struct file *file, void *fh, + int (*vidioc_try_fmt_vid_out)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_try_fmt_vid_out_overlay)(struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_try_fmt_vbi_cap)(struct file *file, void *fh, + int (*vidioc_try_fmt_vid_out_overlay)(struct file *file, void *priv, + struct v4l2_format *f); + int (*vidioc_try_fmt_vbi_cap)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_try_fmt_vbi_out)(struct file *file, void *fh, + int (*vidioc_try_fmt_vbi_out)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_try_fmt_sliced_vbi_cap)(struct file *file, void *fh, + int (*vidioc_try_fmt_sliced_vbi_cap)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_try_fmt_sliced_vbi_out)(struct file *file, void *fh, + int (*vidioc_try_fmt_sliced_vbi_out)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_try_fmt_vid_cap_mplane)(struct file *file, void *fh, + int (*vidioc_try_fmt_vid_cap_mplane)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_try_fmt_vid_out_mplane)(struct file *file, void *fh, + int (*vidioc_try_fmt_vid_out_mplane)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_try_fmt_sdr_cap)(struct file *file, void *fh, + int (*vidioc_try_fmt_sdr_cap)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_try_fmt_sdr_out)(struct file *file, void *fh, + int (*vidioc_try_fmt_sdr_out)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_try_fmt_meta_cap)(struct file *file, void *fh, + int (*vidioc_try_fmt_meta_cap)(struct file *file, void *priv, struct v4l2_format *f); - int (*vidioc_try_fmt_meta_out)(struct file *file, void *fh, + int (*vidioc_try_fmt_meta_out)(struct file *file, void *priv, struct v4l2_format *f); /* Buffer handlers */ - int (*vidioc_reqbufs)(struct file *file, void *fh, + int (*vidioc_reqbufs)(struct file *file, void *priv, struct v4l2_requestbuffers *b); - int (*vidioc_querybuf)(struct file *file, void *fh, + int (*vidioc_querybuf)(struct file *file, void *priv, struct v4l2_buffer *b); - int (*vidioc_qbuf)(struct file *file, void *fh, + int (*vidioc_qbuf)(struct file *file, void *priv, struct v4l2_buffer *b); - int (*vidioc_expbuf)(struct file *file, void *fh, + int (*vidioc_expbuf)(struct file *file, void *priv, struct v4l2_exportbuffer *e); - int (*vidioc_dqbuf)(struct file *file, void *fh, + int (*vidioc_dqbuf)(struct file *file, void *priv, struct v4l2_buffer *b); - int (*vidioc_create_bufs)(struct file *file, void *fh, + int (*vidioc_create_bufs)(struct file *file, void *priv, struct v4l2_create_buffers *b); - int (*vidioc_prepare_buf)(struct file *file, void *fh, + int (*vidioc_prepare_buf)(struct file *file, void *priv, struct v4l2_buffer *b); - int (*vidioc_remove_bufs)(struct file *file, void *fh, + int (*vidioc_remove_bufs)(struct file *file, void *priv, struct v4l2_remove_buffers *d); - int (*vidioc_overlay)(struct file *file, void *fh, unsigned int i); - int (*vidioc_g_fbuf)(struct file *file, void *fh, + int (*vidioc_overlay)(struct file *file, void *priv, unsigned int i); + int (*vidioc_g_fbuf)(struct file *file, void *priv, struct v4l2_framebuffer *a); - int (*vidioc_s_fbuf)(struct file *file, void *fh, + int (*vidioc_s_fbuf)(struct file *file, void *priv, const struct v4l2_framebuffer *a); /* Stream on/off */ - int (*vidioc_streamon)(struct file *file, void *fh, + int (*vidioc_streamon)(struct file *file, void *priv, enum v4l2_buf_type i); - int (*vidioc_streamoff)(struct file *file, void *fh, + int (*vidioc_streamoff)(struct file *file, void *priv, enum v4l2_buf_type i); /* @@ -438,135 +438,135 @@ struct v4l2_ioctl_ops { * * Note: ENUMSTD is handled by videodev.c */ - int (*vidioc_g_std)(struct file *file, void *fh, v4l2_std_id *norm); - int (*vidioc_s_std)(struct file *file, void *fh, v4l2_std_id norm); - int (*vidioc_querystd)(struct file *file, void *fh, v4l2_std_id *a); + int (*vidioc_g_std)(struct file *file, void *priv, v4l2_std_id *norm); + int (*vidioc_s_std)(struct file *file, void *priv, v4l2_std_id norm); + int (*vidioc_querystd)(struct file *file, void *priv, v4l2_std_id *a); /* Input handling */ - int (*vidioc_enum_input)(struct file *file, void *fh, + int (*vidioc_enum_input)(struct file *file, void *priv, struct v4l2_input *inp); - int (*vidioc_g_input)(struct file *file, void *fh, unsigned int *i); - int (*vidioc_s_input)(struct file *file, void *fh, unsigned int i); + int (*vidioc_g_input)(struct file *file, void *priv, unsigned int *i); + int (*vidioc_s_input)(struct file *file, void *priv, unsigned int i); /* Output handling */ - int (*vidioc_enum_output)(struct file *file, void *fh, + int (*vidioc_enum_output)(struct file *file, void *priv, struct v4l2_output *a); - int (*vidioc_g_output)(struct file *file, void *fh, unsigned int *i); - int (*vidioc_s_output)(struct file *file, void *fh, unsigned int i); + int (*vidioc_g_output)(struct file *file, void *priv, unsigned int *i); + int (*vidioc_s_output)(struct file *file, void *priv, unsigned int i); /* Control handling */ - int (*vidioc_query_ext_ctrl)(struct file *file, void *fh, + int (*vidioc_query_ext_ctrl)(struct file *file, void *priv, struct v4l2_query_ext_ctrl *a); - int (*vidioc_g_ext_ctrls)(struct file *file, void *fh, + int (*vidioc_g_ext_ctrls)(struct file *file, void *priv, struct v4l2_ext_controls *a); - int (*vidioc_s_ext_ctrls)(struct file *file, void *fh, + int (*vidioc_s_ext_ctrls)(struct file *file, void *priv, struct v4l2_ext_controls *a); - int (*vidioc_try_ext_ctrls)(struct file *file, void *fh, + int (*vidioc_try_ext_ctrls)(struct file *file, void *priv, struct v4l2_ext_controls *a); - int (*vidioc_querymenu)(struct file *file, void *fh, + int (*vidioc_querymenu)(struct file *file, void *priv, struct v4l2_querymenu *a); /* Audio ioctls */ - int (*vidioc_enumaudio)(struct file *file, void *fh, + int (*vidioc_enumaudio)(struct file *file, void *priv, struct v4l2_audio *a); - int (*vidioc_g_audio)(struct file *file, void *fh, + int (*vidioc_g_audio)(struct file *file, void *priv, struct v4l2_audio *a); - int (*vidioc_s_audio)(struct file *file, void *fh, + int (*vidioc_s_audio)(struct file *file, void *priv, const struct v4l2_audio *a); /* Audio out ioctls */ - int (*vidioc_enumaudout)(struct file *file, void *fh, + int (*vidioc_enumaudout)(struct file *file, void *priv, struct v4l2_audioout *a); - int (*vidioc_g_audout)(struct file *file, void *fh, + int (*vidioc_g_audout)(struct file *file, void *priv, struct v4l2_audioout *a); - int (*vidioc_s_audout)(struct file *file, void *fh, + int (*vidioc_s_audout)(struct file *file, void *priv, const struct v4l2_audioout *a); - int (*vidioc_g_modulator)(struct file *file, void *fh, + int (*vidioc_g_modulator)(struct file *file, void *priv, struct v4l2_modulator *a); - int (*vidioc_s_modulator)(struct file *file, void *fh, + int (*vidioc_s_modulator)(struct file *file, void *priv, const struct v4l2_modulator *a); /* Crop ioctls */ - int (*vidioc_g_pixelaspect)(struct file *file, void *fh, + int (*vidioc_g_pixelaspect)(struct file *file, void *priv, int buf_type, struct v4l2_fract *aspect); - int (*vidioc_g_selection)(struct file *file, void *fh, + int (*vidioc_g_selection)(struct file *file, void *priv, struct v4l2_selection *s); - int (*vidioc_s_selection)(struct file *file, void *fh, + int (*vidioc_s_selection)(struct file *file, void *priv, struct v4l2_selection *s); /* Compression ioctls */ - int (*vidioc_g_jpegcomp)(struct file *file, void *fh, + int (*vidioc_g_jpegcomp)(struct file *file, void *priv, struct v4l2_jpegcompression *a); - int (*vidioc_s_jpegcomp)(struct file *file, void *fh, + int (*vidioc_s_jpegcomp)(struct file *file, void *priv, const struct v4l2_jpegcompression *a); - int (*vidioc_g_enc_index)(struct file *file, void *fh, + int (*vidioc_g_enc_index)(struct file *file, void *priv, struct v4l2_enc_idx *a); - int (*vidioc_encoder_cmd)(struct file *file, void *fh, + int (*vidioc_encoder_cmd)(struct file *file, void *priv, struct v4l2_encoder_cmd *a); - int (*vidioc_try_encoder_cmd)(struct file *file, void *fh, + int (*vidioc_try_encoder_cmd)(struct file *file, void *priv, struct v4l2_encoder_cmd *a); - int (*vidioc_decoder_cmd)(struct file *file, void *fh, + int (*vidioc_decoder_cmd)(struct file *file, void *priv, struct v4l2_decoder_cmd *a); - int (*vidioc_try_decoder_cmd)(struct file *file, void *fh, + int (*vidioc_try_decoder_cmd)(struct file *file, void *priv, struct v4l2_decoder_cmd *a); /* Stream type-dependent parameter ioctls */ - int (*vidioc_g_parm)(struct file *file, void *fh, + int (*vidioc_g_parm)(struct file *file, void *priv, struct v4l2_streamparm *a); - int (*vidioc_s_parm)(struct file *file, void *fh, + int (*vidioc_s_parm)(struct file *file, void *priv, struct v4l2_streamparm *a); /* Tuner ioctls */ - int (*vidioc_g_tuner)(struct file *file, void *fh, + int (*vidioc_g_tuner)(struct file *file, void *priv, struct v4l2_tuner *a); - int (*vidioc_s_tuner)(struct file *file, void *fh, + int (*vidioc_s_tuner)(struct file *file, void *priv, const struct v4l2_tuner *a); - int (*vidioc_g_frequency)(struct file *file, void *fh, + int (*vidioc_g_frequency)(struct file *file, void *priv, struct v4l2_frequency *a); - int (*vidioc_s_frequency)(struct file *file, void *fh, + int (*vidioc_s_frequency)(struct file *file, void *priv, const struct v4l2_frequency *a); - int (*vidioc_enum_freq_bands)(struct file *file, void *fh, + int (*vidioc_enum_freq_bands)(struct file *file, void *priv, struct v4l2_frequency_band *band); /* Sliced VBI cap */ - int (*vidioc_g_sliced_vbi_cap)(struct file *file, void *fh, + int (*vidioc_g_sliced_vbi_cap)(struct file *file, void *priv, struct v4l2_sliced_vbi_cap *a); /* Log status ioctl */ - int (*vidioc_log_status)(struct file *file, void *fh); + int (*vidioc_log_status)(struct file *file, void *priv); - int (*vidioc_s_hw_freq_seek)(struct file *file, void *fh, + int (*vidioc_s_hw_freq_seek)(struct file *file, void *priv, const struct v4l2_hw_freq_seek *a); /* Debugging ioctls */ #ifdef CONFIG_VIDEO_ADV_DEBUG - int (*vidioc_g_register)(struct file *file, void *fh, + int (*vidioc_g_register)(struct file *file, void *priv, struct v4l2_dbg_register *reg); - int (*vidioc_s_register)(struct file *file, void *fh, + int (*vidioc_s_register)(struct file *file, void *priv, const struct v4l2_dbg_register *reg); - int (*vidioc_g_chip_info)(struct file *file, void *fh, + int (*vidioc_g_chip_info)(struct file *file, void *priv, struct v4l2_dbg_chip_info *chip); #endif - int (*vidioc_enum_framesizes)(struct file *file, void *fh, + int (*vidioc_enum_framesizes)(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize); - int (*vidioc_enum_frameintervals)(struct file *file, void *fh, + int (*vidioc_enum_frameintervals)(struct file *file, void *priv, struct v4l2_frmivalenum *fival); /* DV Timings IOCTLs */ - int (*vidioc_s_dv_timings)(struct file *file, void *fh, + int (*vidioc_s_dv_timings)(struct file *file, void *priv, struct v4l2_dv_timings *timings); - int (*vidioc_g_dv_timings)(struct file *file, void *fh, + int (*vidioc_g_dv_timings)(struct file *file, void *priv, struct v4l2_dv_timings *timings); - int (*vidioc_query_dv_timings)(struct file *file, void *fh, + int (*vidioc_query_dv_timings)(struct file *file, void *priv, struct v4l2_dv_timings *timings); - int (*vidioc_enum_dv_timings)(struct file *file, void *fh, + int (*vidioc_enum_dv_timings)(struct file *file, void *priv, struct v4l2_enum_dv_timings *timings); - int (*vidioc_dv_timings_cap)(struct file *file, void *fh, + int (*vidioc_dv_timings_cap)(struct file *file, void *priv, struct v4l2_dv_timings_cap *cap); - int (*vidioc_g_edid)(struct file *file, void *fh, + int (*vidioc_g_edid)(struct file *file, void *priv, struct v4l2_edid *edid); - int (*vidioc_s_edid)(struct file *file, void *fh, + int (*vidioc_s_edid)(struct file *file, void *priv, struct v4l2_edid *edid); int (*vidioc_subscribe_event)(struct v4l2_fh *fh, @@ -575,7 +575,7 @@ struct v4l2_ioctl_ops { const struct v4l2_event_subscription *sub); /* For other private ioctls */ - long (*vidioc_default)(struct file *file, void *fh, + long (*vidioc_default)(struct file *file, void *priv, bool valid_prio, unsigned int cmd, void *arg); }; From 35c0ae6d7a2f9b61644c38836929a27a86bcaa1d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:30:52 +0300 Subject: [PATCH 00570/11391] media: v4l2-ioctl: Push NULL fh argument down to ioctl wrappers As ioctl handlers do not expect a priv argument anymore, start pushing the NULL pointer down from __video_do_ioctl() to the ioctl wrappers. This paves the way to dropping the void *priv argument to ioctl handlers themselves. Changes to ioctl wrappers have been generated with the following coccinelle semantic patch: @ioctl@ identifier v4l2_ioctls; identifier ioctl; identifier fn; identifier debug; expression flags; @@ struct v4l2_ioctl_info v4l2_ioctls[] = { ..., IOCTL_INFO(ioctl, fn, debug, flags), ..., }; @depends on ioctl@ identifier ioctl.fn; identifier ops; identifier file; identifier fh; identifier arg; identifier handler; expression list args; @@ -int fn(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) +int fn(const struct v4l2_ioctl_ops *ops, struct file *file, void *arg) { <... - ops->handler(file, fh, args) + ops->handler(file, NULL, args) ...> } Manual changes have been added to handle the calls to v4l_[gs]_selection(), drop the fh argument in the v4l2_ioctl_info structure definition and in the DEFINE_V4L_STUB_FUNC() macro, and stop passing NULL to the wrappers in __video_do_ioctl() Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/v4l2-core/v4l2-ioctl.c | 402 +++++++++++++-------------- 1 file changed, 201 insertions(+), 201 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index d815291624a9..01cf52c3ea33 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1089,8 +1089,8 @@ static void v4l_sanitize_format(struct v4l2_format *fmt) } } -static int v4l_querycap(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_querycap(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct v4l2_capability *cap = (struct v4l2_capability *)arg; struct video_device *vfd = video_devdata(file); @@ -1103,7 +1103,7 @@ static int v4l_querycap(const struct v4l2_ioctl_ops *ops, media_set_bus_info(cap->bus_info, sizeof(cap->bus_info), vfd->dev_parent); - ret = ops->vidioc_querycap(file, fh, cap); + ret = ops->vidioc_querycap(file, NULL, cap); /* * Drivers must not change device_caps, so check for this and @@ -1123,8 +1123,8 @@ static int v4l_querycap(const struct v4l2_ioctl_ops *ops, return ret; } -static int v4l_g_input(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_g_input(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); @@ -1133,11 +1133,11 @@ static int v4l_g_input(const struct v4l2_ioctl_ops *ops, return 0; } - return ops->vidioc_g_input(file, fh, arg); + return ops->vidioc_g_input(file, NULL, arg); } -static int v4l_g_output(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_g_output(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); @@ -1146,11 +1146,11 @@ static int v4l_g_output(const struct v4l2_ioctl_ops *ops, return 0; } - return ops->vidioc_g_output(file, fh, arg); + return ops->vidioc_g_output(file, NULL, arg); } -static int v4l_s_input(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_s_input(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); int ret; @@ -1162,22 +1162,22 @@ static int v4l_s_input(const struct v4l2_ioctl_ops *ops, if (vfd->device_caps & V4L2_CAP_IO_MC) return *(int *)arg ? -EINVAL : 0; - return ops->vidioc_s_input(file, fh, *(unsigned int *)arg); + return ops->vidioc_s_input(file, NULL, *(unsigned int *)arg); } -static int v4l_s_output(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_s_output(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); if (vfd->device_caps & V4L2_CAP_IO_MC) return *(int *)arg ? -EINVAL : 0; - return ops->vidioc_s_output(file, fh, *(unsigned int *)arg); + return ops->vidioc_s_output(file, NULL, *(unsigned int *)arg); } -static int v4l_g_priority(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_g_priority(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd; u32 *p = arg; @@ -1187,8 +1187,8 @@ static int v4l_g_priority(const struct v4l2_ioctl_ops *ops, return 0; } -static int v4l_s_priority(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_s_priority(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd; struct v4l2_fh *vfh; @@ -1199,8 +1199,8 @@ static int v4l_s_priority(const struct v4l2_ioctl_ops *ops, return v4l2_prio_change(vfd->prio, &vfh->prio, *p); } -static int v4l_enuminput(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_enuminput(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_input *p = arg; @@ -1222,11 +1222,11 @@ static int v4l_enuminput(const struct v4l2_ioctl_ops *ops, return 0; } - return ops->vidioc_enum_input(file, fh, p); + return ops->vidioc_enum_input(file, NULL, p); } -static int v4l_enumoutput(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_enumoutput(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_output *p = arg; @@ -1248,7 +1248,7 @@ static int v4l_enumoutput(const struct v4l2_ioctl_ops *ops, return 0; } - return ops->vidioc_enum_output(file, fh, p); + return ops->vidioc_enum_output(file, NULL, p); } static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) @@ -1587,8 +1587,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) fmt->flags |= flags; } -static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vdev = video_devdata(file); struct v4l2_fmtdesc *p = arg; @@ -1618,12 +1618,12 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops, if (unlikely(!ops->vidioc_enum_fmt_vid_cap)) break; - ret = ops->vidioc_enum_fmt_vid_cap(file, fh, arg); + ret = ops->vidioc_enum_fmt_vid_cap(file, NULL, arg); break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: if (unlikely(!ops->vidioc_enum_fmt_vid_overlay)) break; - ret = ops->vidioc_enum_fmt_vid_overlay(file, fh, arg); + ret = ops->vidioc_enum_fmt_vid_overlay(file, NULL, arg); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: @@ -1635,27 +1635,27 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops, if (unlikely(!ops->vidioc_enum_fmt_vid_out)) break; - ret = ops->vidioc_enum_fmt_vid_out(file, fh, arg); + ret = ops->vidioc_enum_fmt_vid_out(file, NULL, arg); break; case V4L2_BUF_TYPE_SDR_CAPTURE: if (unlikely(!ops->vidioc_enum_fmt_sdr_cap)) break; - ret = ops->vidioc_enum_fmt_sdr_cap(file, fh, arg); + ret = ops->vidioc_enum_fmt_sdr_cap(file, NULL, arg); break; case V4L2_BUF_TYPE_SDR_OUTPUT: if (unlikely(!ops->vidioc_enum_fmt_sdr_out)) break; - ret = ops->vidioc_enum_fmt_sdr_out(file, fh, arg); + ret = ops->vidioc_enum_fmt_sdr_out(file, NULL, arg); break; case V4L2_BUF_TYPE_META_CAPTURE: if (unlikely(!ops->vidioc_enum_fmt_meta_cap)) break; - ret = ops->vidioc_enum_fmt_meta_cap(file, fh, arg); + ret = ops->vidioc_enum_fmt_meta_cap(file, NULL, arg); break; case V4L2_BUF_TYPE_META_OUTPUT: if (unlikely(!ops->vidioc_enum_fmt_meta_out)) break; - ret = ops->vidioc_enum_fmt_meta_out(file, fh, arg); + ret = ops->vidioc_enum_fmt_meta_out(file, NULL, arg); break; } if (ret == 0) @@ -1678,8 +1678,8 @@ static void v4l_pix_format_touch(struct v4l2_pix_format *p) p->xfer_func = 0; } -static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct v4l2_format *p = arg; struct video_device *vfd = video_devdata(file); @@ -1695,50 +1695,50 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops, if (unlikely(!ops->vidioc_g_fmt_vid_cap)) break; p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; - ret = ops->vidioc_g_fmt_vid_cap(file, fh, arg); + ret = ops->vidioc_g_fmt_vid_cap(file, NULL, arg); /* just in case the driver zeroed it again */ p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; if (vfd->vfl_type == VFL_TYPE_TOUCH) v4l_pix_format_touch(&p->fmt.pix); return ret; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - return ops->vidioc_g_fmt_vid_cap_mplane(file, fh, arg); + return ops->vidioc_g_fmt_vid_cap_mplane(file, NULL, arg); case V4L2_BUF_TYPE_VIDEO_OVERLAY: - return ops->vidioc_g_fmt_vid_overlay(file, fh, arg); + return ops->vidioc_g_fmt_vid_overlay(file, NULL, arg); case V4L2_BUF_TYPE_VBI_CAPTURE: - return ops->vidioc_g_fmt_vbi_cap(file, fh, arg); + return ops->vidioc_g_fmt_vbi_cap(file, NULL, arg); case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - return ops->vidioc_g_fmt_sliced_vbi_cap(file, fh, arg); + return ops->vidioc_g_fmt_sliced_vbi_cap(file, NULL, arg); case V4L2_BUF_TYPE_VIDEO_OUTPUT: if (unlikely(!ops->vidioc_g_fmt_vid_out)) break; p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; - ret = ops->vidioc_g_fmt_vid_out(file, fh, arg); + ret = ops->vidioc_g_fmt_vid_out(file, NULL, arg); /* just in case the driver zeroed it again */ p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; return ret; case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - return ops->vidioc_g_fmt_vid_out_mplane(file, fh, arg); + return ops->vidioc_g_fmt_vid_out_mplane(file, NULL, arg); case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - return ops->vidioc_g_fmt_vid_out_overlay(file, fh, arg); + return ops->vidioc_g_fmt_vid_out_overlay(file, NULL, arg); case V4L2_BUF_TYPE_VBI_OUTPUT: - return ops->vidioc_g_fmt_vbi_out(file, fh, arg); + return ops->vidioc_g_fmt_vbi_out(file, NULL, arg); case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - return ops->vidioc_g_fmt_sliced_vbi_out(file, fh, arg); + return ops->vidioc_g_fmt_sliced_vbi_out(file, NULL, arg); case V4L2_BUF_TYPE_SDR_CAPTURE: - return ops->vidioc_g_fmt_sdr_cap(file, fh, arg); + return ops->vidioc_g_fmt_sdr_cap(file, NULL, arg); case V4L2_BUF_TYPE_SDR_OUTPUT: - return ops->vidioc_g_fmt_sdr_out(file, fh, arg); + return ops->vidioc_g_fmt_sdr_out(file, NULL, arg); case V4L2_BUF_TYPE_META_CAPTURE: - return ops->vidioc_g_fmt_meta_cap(file, fh, arg); + return ops->vidioc_g_fmt_meta_cap(file, NULL, arg); case V4L2_BUF_TYPE_META_OUTPUT: - return ops->vidioc_g_fmt_meta_out(file, fh, arg); + return ops->vidioc_g_fmt_meta_out(file, NULL, arg); } return -EINVAL; } -static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct v4l2_format *p = arg; struct video_device *vfd = video_devdata(file); @@ -1758,7 +1758,7 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, if (unlikely(!ops->vidioc_s_fmt_vid_cap)) break; memset_after(p, 0, fmt.pix); - ret = ops->vidioc_s_fmt_vid_cap(file, fh, arg); + ret = ops->vidioc_s_fmt_vid_cap(file, NULL, arg); /* just in case the driver zeroed it again */ p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; if (vfd->vfl_type == VFL_TYPE_TOUCH) @@ -1771,7 +1771,7 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, for (i = 0; i < p->fmt.pix_mp.num_planes; i++) memset_after(&p->fmt.pix_mp.plane_fmt[i], 0, bytesperline); - return ops->vidioc_s_fmt_vid_cap_mplane(file, fh, arg); + return ops->vidioc_s_fmt_vid_cap_mplane(file, NULL, arg); case V4L2_BUF_TYPE_VIDEO_OVERLAY: if (unlikely(!ops->vidioc_s_fmt_vid_overlay)) break; @@ -1779,22 +1779,22 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, p->fmt.win.clips = NULL; p->fmt.win.clipcount = 0; p->fmt.win.bitmap = NULL; - return ops->vidioc_s_fmt_vid_overlay(file, fh, arg); + return ops->vidioc_s_fmt_vid_overlay(file, NULL, arg); case V4L2_BUF_TYPE_VBI_CAPTURE: if (unlikely(!ops->vidioc_s_fmt_vbi_cap)) break; memset_after(p, 0, fmt.vbi.flags); - return ops->vidioc_s_fmt_vbi_cap(file, fh, arg); + return ops->vidioc_s_fmt_vbi_cap(file, NULL, arg); case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: if (unlikely(!ops->vidioc_s_fmt_sliced_vbi_cap)) break; memset_after(p, 0, fmt.sliced.io_size); - return ops->vidioc_s_fmt_sliced_vbi_cap(file, fh, arg); + return ops->vidioc_s_fmt_sliced_vbi_cap(file, NULL, arg); case V4L2_BUF_TYPE_VIDEO_OUTPUT: if (unlikely(!ops->vidioc_s_fmt_vid_out)) break; memset_after(p, 0, fmt.pix); - ret = ops->vidioc_s_fmt_vid_out(file, fh, arg); + ret = ops->vidioc_s_fmt_vid_out(file, NULL, arg); /* just in case the driver zeroed it again */ p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; return ret; @@ -1805,7 +1805,7 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, for (i = 0; i < p->fmt.pix_mp.num_planes; i++) memset_after(&p->fmt.pix_mp.plane_fmt[i], 0, bytesperline); - return ops->vidioc_s_fmt_vid_out_mplane(file, fh, arg); + return ops->vidioc_s_fmt_vid_out_mplane(file, NULL, arg); case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: if (unlikely(!ops->vidioc_s_fmt_vid_out_overlay)) break; @@ -1813,43 +1813,43 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, p->fmt.win.clips = NULL; p->fmt.win.clipcount = 0; p->fmt.win.bitmap = NULL; - return ops->vidioc_s_fmt_vid_out_overlay(file, fh, arg); + return ops->vidioc_s_fmt_vid_out_overlay(file, NULL, arg); case V4L2_BUF_TYPE_VBI_OUTPUT: if (unlikely(!ops->vidioc_s_fmt_vbi_out)) break; memset_after(p, 0, fmt.vbi.flags); - return ops->vidioc_s_fmt_vbi_out(file, fh, arg); + return ops->vidioc_s_fmt_vbi_out(file, NULL, arg); case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: if (unlikely(!ops->vidioc_s_fmt_sliced_vbi_out)) break; memset_after(p, 0, fmt.sliced.io_size); - return ops->vidioc_s_fmt_sliced_vbi_out(file, fh, arg); + return ops->vidioc_s_fmt_sliced_vbi_out(file, NULL, arg); case V4L2_BUF_TYPE_SDR_CAPTURE: if (unlikely(!ops->vidioc_s_fmt_sdr_cap)) break; memset_after(p, 0, fmt.sdr.buffersize); - return ops->vidioc_s_fmt_sdr_cap(file, fh, arg); + return ops->vidioc_s_fmt_sdr_cap(file, NULL, arg); case V4L2_BUF_TYPE_SDR_OUTPUT: if (unlikely(!ops->vidioc_s_fmt_sdr_out)) break; memset_after(p, 0, fmt.sdr.buffersize); - return ops->vidioc_s_fmt_sdr_out(file, fh, arg); + return ops->vidioc_s_fmt_sdr_out(file, NULL, arg); case V4L2_BUF_TYPE_META_CAPTURE: if (unlikely(!ops->vidioc_s_fmt_meta_cap)) break; memset_after(p, 0, fmt.meta); - return ops->vidioc_s_fmt_meta_cap(file, fh, arg); + return ops->vidioc_s_fmt_meta_cap(file, NULL, arg); case V4L2_BUF_TYPE_META_OUTPUT: if (unlikely(!ops->vidioc_s_fmt_meta_out)) break; memset_after(p, 0, fmt.meta); - return ops->vidioc_s_fmt_meta_out(file, fh, arg); + return ops->vidioc_s_fmt_meta_out(file, NULL, arg); } return -EINVAL; } -static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct v4l2_format *p = arg; struct video_device *vfd = video_devdata(file); @@ -1866,7 +1866,7 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, if (unlikely(!ops->vidioc_try_fmt_vid_cap)) break; memset_after(p, 0, fmt.pix); - ret = ops->vidioc_try_fmt_vid_cap(file, fh, arg); + ret = ops->vidioc_try_fmt_vid_cap(file, NULL, arg); /* just in case the driver zeroed it again */ p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; if (vfd->vfl_type == VFL_TYPE_TOUCH) @@ -1879,7 +1879,7 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, for (i = 0; i < p->fmt.pix_mp.num_planes; i++) memset_after(&p->fmt.pix_mp.plane_fmt[i], 0, bytesperline); - return ops->vidioc_try_fmt_vid_cap_mplane(file, fh, arg); + return ops->vidioc_try_fmt_vid_cap_mplane(file, NULL, arg); case V4L2_BUF_TYPE_VIDEO_OVERLAY: if (unlikely(!ops->vidioc_try_fmt_vid_overlay)) break; @@ -1887,22 +1887,22 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, p->fmt.win.clips = NULL; p->fmt.win.clipcount = 0; p->fmt.win.bitmap = NULL; - return ops->vidioc_try_fmt_vid_overlay(file, fh, arg); + return ops->vidioc_try_fmt_vid_overlay(file, NULL, arg); case V4L2_BUF_TYPE_VBI_CAPTURE: if (unlikely(!ops->vidioc_try_fmt_vbi_cap)) break; memset_after(p, 0, fmt.vbi.flags); - return ops->vidioc_try_fmt_vbi_cap(file, fh, arg); + return ops->vidioc_try_fmt_vbi_cap(file, NULL, arg); case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: if (unlikely(!ops->vidioc_try_fmt_sliced_vbi_cap)) break; memset_after(p, 0, fmt.sliced.io_size); - return ops->vidioc_try_fmt_sliced_vbi_cap(file, fh, arg); + return ops->vidioc_try_fmt_sliced_vbi_cap(file, NULL, arg); case V4L2_BUF_TYPE_VIDEO_OUTPUT: if (unlikely(!ops->vidioc_try_fmt_vid_out)) break; memset_after(p, 0, fmt.pix); - ret = ops->vidioc_try_fmt_vid_out(file, fh, arg); + ret = ops->vidioc_try_fmt_vid_out(file, NULL, arg); /* just in case the driver zeroed it again */ p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; return ret; @@ -1913,7 +1913,7 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, for (i = 0; i < p->fmt.pix_mp.num_planes; i++) memset_after(&p->fmt.pix_mp.plane_fmt[i], 0, bytesperline); - return ops->vidioc_try_fmt_vid_out_mplane(file, fh, arg); + return ops->vidioc_try_fmt_vid_out_mplane(file, NULL, arg); case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: if (unlikely(!ops->vidioc_try_fmt_vid_out_overlay)) break; @@ -1921,55 +1921,55 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, p->fmt.win.clips = NULL; p->fmt.win.clipcount = 0; p->fmt.win.bitmap = NULL; - return ops->vidioc_try_fmt_vid_out_overlay(file, fh, arg); + return ops->vidioc_try_fmt_vid_out_overlay(file, NULL, arg); case V4L2_BUF_TYPE_VBI_OUTPUT: if (unlikely(!ops->vidioc_try_fmt_vbi_out)) break; memset_after(p, 0, fmt.vbi.flags); - return ops->vidioc_try_fmt_vbi_out(file, fh, arg); + return ops->vidioc_try_fmt_vbi_out(file, NULL, arg); case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: if (unlikely(!ops->vidioc_try_fmt_sliced_vbi_out)) break; memset_after(p, 0, fmt.sliced.io_size); - return ops->vidioc_try_fmt_sliced_vbi_out(file, fh, arg); + return ops->vidioc_try_fmt_sliced_vbi_out(file, NULL, arg); case V4L2_BUF_TYPE_SDR_CAPTURE: if (unlikely(!ops->vidioc_try_fmt_sdr_cap)) break; memset_after(p, 0, fmt.sdr.buffersize); - return ops->vidioc_try_fmt_sdr_cap(file, fh, arg); + return ops->vidioc_try_fmt_sdr_cap(file, NULL, arg); case V4L2_BUF_TYPE_SDR_OUTPUT: if (unlikely(!ops->vidioc_try_fmt_sdr_out)) break; memset_after(p, 0, fmt.sdr.buffersize); - return ops->vidioc_try_fmt_sdr_out(file, fh, arg); + return ops->vidioc_try_fmt_sdr_out(file, NULL, arg); case V4L2_BUF_TYPE_META_CAPTURE: if (unlikely(!ops->vidioc_try_fmt_meta_cap)) break; memset_after(p, 0, fmt.meta); - return ops->vidioc_try_fmt_meta_cap(file, fh, arg); + return ops->vidioc_try_fmt_meta_cap(file, NULL, arg); case V4L2_BUF_TYPE_META_OUTPUT: if (unlikely(!ops->vidioc_try_fmt_meta_out)) break; memset_after(p, 0, fmt.meta); - return ops->vidioc_try_fmt_meta_out(file, fh, arg); + return ops->vidioc_try_fmt_meta_out(file, NULL, arg); } return -EINVAL; } -static int v4l_streamon(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_streamon(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { - return ops->vidioc_streamon(file, fh, *(unsigned int *)arg); + return ops->vidioc_streamon(file, NULL, *(unsigned int *)arg); } -static int v4l_streamoff(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_streamoff(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { - return ops->vidioc_streamoff(file, fh, *(unsigned int *)arg); + return ops->vidioc_streamoff(file, NULL, *(unsigned int *)arg); } -static int v4l_g_tuner(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_g_tuner(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_tuner *p = arg; @@ -1977,14 +1977,14 @@ static int v4l_g_tuner(const struct v4l2_ioctl_ops *ops, p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - err = ops->vidioc_g_tuner(file, fh, p); + err = ops->vidioc_g_tuner(file, NULL, p); if (!err) p->capability |= V4L2_TUNER_CAP_FREQ_BANDS; return err; } -static int v4l_s_tuner(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_s_tuner(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_tuner *p = arg; @@ -1995,11 +1995,11 @@ static int v4l_s_tuner(const struct v4l2_ioctl_ops *ops, return ret; p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - return ops->vidioc_s_tuner(file, fh, p); + return ops->vidioc_s_tuner(file, NULL, p); } static int v4l_g_modulator(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_modulator *p = arg; @@ -2008,14 +2008,14 @@ static int v4l_g_modulator(const struct v4l2_ioctl_ops *ops, if (vfd->vfl_type == VFL_TYPE_RADIO) p->type = V4L2_TUNER_RADIO; - err = ops->vidioc_g_modulator(file, fh, p); + err = ops->vidioc_g_modulator(file, NULL, p); if (!err) p->capability |= V4L2_TUNER_CAP_FREQ_BANDS; return err; } static int v4l_s_modulator(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_modulator *p = arg; @@ -2023,11 +2023,11 @@ static int v4l_s_modulator(const struct v4l2_ioctl_ops *ops, if (vfd->vfl_type == VFL_TYPE_RADIO) p->type = V4L2_TUNER_RADIO; - return ops->vidioc_s_modulator(file, fh, p); + return ops->vidioc_s_modulator(file, NULL, p); } static int v4l_g_frequency(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_frequency *p = arg; @@ -2037,11 +2037,11 @@ static int v4l_g_frequency(const struct v4l2_ioctl_ops *ops, else p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - return ops->vidioc_g_frequency(file, fh, p); + return ops->vidioc_g_frequency(file, NULL, p); } static int v4l_s_frequency(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct video_device *vfd = video_devdata(file); const struct v4l2_frequency *p = arg; @@ -2060,11 +2060,11 @@ static int v4l_s_frequency(const struct v4l2_ioctl_ops *ops, if (type != p->type) return -EINVAL; } - return ops->vidioc_s_frequency(file, fh, p); + return ops->vidioc_s_frequency(file, NULL, p); } -static int v4l_enumstd(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_enumstd(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_standard *p = arg; @@ -2072,8 +2072,8 @@ static int v4l_enumstd(const struct v4l2_ioctl_ops *ops, return v4l_video_std_enumstd(p, vfd->tvnorms); } -static int v4l_s_std(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_s_std(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); v4l2_std_id id = *(v4l2_std_id *)arg, norm; @@ -2087,11 +2087,11 @@ static int v4l_s_std(const struct v4l2_ioctl_ops *ops, return -EINVAL; /* Calls the specific handler */ - return ops->vidioc_s_std(file, fh, norm); + return ops->vidioc_s_std(file, NULL, norm); } -static int v4l_querystd(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_querystd(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); v4l2_std_id *p = arg; @@ -2109,11 +2109,11 @@ static int v4l_querystd(const struct v4l2_ioctl_ops *ops, * their efforts to improve the standards detection. */ *p = vfd->tvnorms; - return ops->vidioc_querystd(file, fh, arg); + return ops->vidioc_querystd(file, NULL, arg); } static int v4l_s_hw_freq_seek(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_hw_freq_seek *p = arg; @@ -2131,26 +2131,26 @@ static int v4l_s_hw_freq_seek(const struct v4l2_ioctl_ops *ops, V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; if (p->type != type) return -EINVAL; - return ops->vidioc_s_hw_freq_seek(file, fh, p); + return ops->vidioc_s_hw_freq_seek(file, NULL, p); } -static int v4l_s_fbuf(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_s_fbuf(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct v4l2_framebuffer *p = arg; p->base = NULL; - return ops->vidioc_s_fbuf(file, fh, p); + return ops->vidioc_s_fbuf(file, NULL, p); } -static int v4l_overlay(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_overlay(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { - return ops->vidioc_overlay(file, fh, *(unsigned int *)arg); + return ops->vidioc_overlay(file, NULL, *(unsigned int *)arg); } -static int v4l_reqbufs(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_reqbufs(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_requestbuffers *p = arg; @@ -2165,38 +2165,38 @@ static int v4l_reqbufs(const struct v4l2_ioctl_ops *ops, if (is_valid_ioctl(vfd, VIDIOC_REMOVE_BUFS)) p->capabilities = V4L2_BUF_CAP_SUPPORTS_REMOVE_BUFS; - return ops->vidioc_reqbufs(file, fh, p); + return ops->vidioc_reqbufs(file, NULL, p); } -static int v4l_querybuf(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_querybuf(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct v4l2_buffer *p = arg; int ret = check_fmt(file, p->type); - return ret ? ret : ops->vidioc_querybuf(file, fh, p); + return ret ? ret : ops->vidioc_querybuf(file, NULL, p); } -static int v4l_qbuf(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_qbuf(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct v4l2_buffer *p = arg; int ret = check_fmt(file, p->type); - return ret ? ret : ops->vidioc_qbuf(file, fh, p); + return ret ? ret : ops->vidioc_qbuf(file, NULL, p); } -static int v4l_dqbuf(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_dqbuf(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct v4l2_buffer *p = arg; int ret = check_fmt(file, p->type); - return ret ? ret : ops->vidioc_dqbuf(file, fh, p); + return ret ? ret : ops->vidioc_dqbuf(file, NULL, p); } static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_create_buffers *create = arg; @@ -2213,7 +2213,7 @@ static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops, if (is_valid_ioctl(vfd, VIDIOC_REMOVE_BUFS)) create->capabilities = V4L2_BUF_CAP_SUPPORTS_REMOVE_BUFS; - ret = ops->vidioc_create_bufs(file, fh, create); + ret = ops->vidioc_create_bufs(file, NULL, create); if (create->format.type == V4L2_BUF_TYPE_VIDEO_CAPTURE || create->format.type == V4L2_BUF_TYPE_VIDEO_OUTPUT) @@ -2223,27 +2223,27 @@ static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops, } static int v4l_prepare_buf(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct v4l2_buffer *b = arg; int ret = check_fmt(file, b->type); - return ret ? ret : ops->vidioc_prepare_buf(file, fh, b); + return ret ? ret : ops->vidioc_prepare_buf(file, NULL, b); } static int v4l_remove_bufs(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct v4l2_remove_buffers *remove = arg; if (ops->vidioc_remove_bufs) - return ops->vidioc_remove_bufs(file, fh, remove); + return ops->vidioc_remove_bufs(file, NULL, remove); return -ENOTTY; } -static int v4l_g_parm(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_g_parm(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_streamparm *p = arg; @@ -2253,20 +2253,20 @@ static int v4l_g_parm(const struct v4l2_ioctl_ops *ops, if (ret) return ret; if (ops->vidioc_g_parm) - return ops->vidioc_g_parm(file, fh, p); + return ops->vidioc_g_parm(file, NULL, p); if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) return -EINVAL; if (vfd->device_caps & V4L2_CAP_READWRITE) p->parm.capture.readbuffers = 2; - ret = ops->vidioc_g_std(file, fh, &std); + ret = ops->vidioc_g_std(file, NULL, &std); if (ret == 0) v4l2_video_std_frame_period(std, &p->parm.capture.timeperframe); return ret; } -static int v4l_s_parm(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_s_parm(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct v4l2_streamparm *p = arg; int ret = check_fmt(file, p->type); @@ -2286,11 +2286,11 @@ static int v4l_s_parm(const struct v4l2_ioctl_ops *ops, p->parm.capture.extendedmode = 0; p->parm.capture.capturemode &= V4L2_MODE_HIGHQUALITY; } - return ops->vidioc_s_parm(file, fh, p); + return ops->vidioc_s_parm(file, NULL, p); } -static int v4l_queryctrl(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_queryctrl(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_query_ext_ctrl qec = {}; @@ -2307,7 +2307,7 @@ static int v4l_queryctrl(const struct v4l2_ioctl_ops *ops, /* Simulate query_ext_ctr using query_ctrl. */ qec.id = p->id; - ret = ops->vidioc_query_ext_ctrl(file, fh, &qec); + ret = ops->vidioc_query_ext_ctrl(file, NULL, &qec); if (ret) return ret; v4l2_query_ext_ctrl_to_v4l2_queryctrl(p, &qec); @@ -2315,7 +2315,7 @@ static int v4l_queryctrl(const struct v4l2_ioctl_ops *ops, } static int v4l_query_ext_ctrl(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_query_ext_ctrl *p = arg; @@ -2326,12 +2326,12 @@ static int v4l_query_ext_ctrl(const struct v4l2_ioctl_ops *ops, if (vfd->ctrl_handler) return v4l2_query_ext_ctrl(vfd->ctrl_handler, p); if (ops->vidioc_query_ext_ctrl) - return ops->vidioc_query_ext_ctrl(file, fh, p); + return ops->vidioc_query_ext_ctrl(file, NULL, p); return -ENOTTY; } -static int v4l_querymenu(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_querymenu(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_querymenu *p = arg; @@ -2342,12 +2342,12 @@ static int v4l_querymenu(const struct v4l2_ioctl_ops *ops, if (vfd->ctrl_handler) return v4l2_querymenu(vfd->ctrl_handler, p); if (ops->vidioc_querymenu) - return ops->vidioc_querymenu(file, fh, p); + return ops->vidioc_querymenu(file, NULL, p); return -ENOTTY; } -static int v4l_g_ctrl(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_g_ctrl(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_control *p = arg; @@ -2368,7 +2368,7 @@ static int v4l_g_ctrl(const struct v4l2_ioctl_ops *ops, ctrl.id = p->id; ctrl.value = p->value; if (check_ext_ctrls(&ctrls, VIDIOC_G_CTRL)) { - int ret = ops->vidioc_g_ext_ctrls(file, fh, &ctrls); + int ret = ops->vidioc_g_ext_ctrls(file, NULL, &ctrls); if (ret == 0) p->value = ctrl.value; @@ -2377,8 +2377,8 @@ static int v4l_g_ctrl(const struct v4l2_ioctl_ops *ops, return -EINVAL; } -static int v4l_s_ctrl(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_s_ctrl(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_control *p = arg; @@ -2401,13 +2401,13 @@ static int v4l_s_ctrl(const struct v4l2_ioctl_ops *ops, ctrl.value = p->value; if (!check_ext_ctrls(&ctrls, VIDIOC_S_CTRL)) return -EINVAL; - ret = ops->vidioc_s_ext_ctrls(file, fh, &ctrls); + ret = ops->vidioc_s_ext_ctrls(file, NULL, &ctrls); p->value = ctrl.value; return ret; } static int v4l_g_ext_ctrls(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_ext_controls *p = arg; @@ -2423,11 +2423,11 @@ static int v4l_g_ext_ctrls(const struct v4l2_ioctl_ops *ops, if (ops->vidioc_g_ext_ctrls == NULL) return -ENOTTY; return check_ext_ctrls(p, VIDIOC_G_EXT_CTRLS) ? - ops->vidioc_g_ext_ctrls(file, fh, p) : -EINVAL; + ops->vidioc_g_ext_ctrls(file, NULL, p) : -EINVAL; } static int v4l_s_ext_ctrls(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_ext_controls *p = arg; @@ -2443,11 +2443,11 @@ static int v4l_s_ext_ctrls(const struct v4l2_ioctl_ops *ops, if (ops->vidioc_s_ext_ctrls == NULL) return -ENOTTY; return check_ext_ctrls(p, VIDIOC_S_EXT_CTRLS) ? - ops->vidioc_s_ext_ctrls(file, fh, p) : -EINVAL; + ops->vidioc_s_ext_ctrls(file, NULL, p) : -EINVAL; } static int v4l_try_ext_ctrls(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_ext_controls *p = arg; @@ -2463,7 +2463,7 @@ static int v4l_try_ext_ctrls(const struct v4l2_ioctl_ops *ops, if (ops->vidioc_try_ext_ctrls == NULL) return -ENOTTY; return check_ext_ctrls(p, VIDIOC_TRY_EXT_CTRLS) ? - ops->vidioc_try_ext_ctrls(file, fh, p) : -EINVAL; + ops->vidioc_try_ext_ctrls(file, NULL, p) : -EINVAL; } /* @@ -2476,7 +2476,7 @@ static int v4l_try_ext_ctrls(const struct v4l2_ioctl_ops *ops, * type and drivers don't need to check for both. */ static int v4l_g_selection(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct v4l2_selection *p = arg; u32 old_type = p->type; @@ -2486,13 +2486,13 @@ static int v4l_g_selection(const struct v4l2_ioctl_ops *ops, p->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; else if (p->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) p->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - ret = ops->vidioc_g_selection(file, fh, p); + ret = ops->vidioc_g_selection(file, NULL, p); p->type = old_type; return ret; } static int v4l_s_selection(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct v4l2_selection *p = arg; u32 old_type = p->type; @@ -2502,13 +2502,13 @@ static int v4l_s_selection(const struct v4l2_ioctl_ops *ops, p->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; else if (p->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) p->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - ret = ops->vidioc_s_selection(file, fh, p); + ret = ops->vidioc_s_selection(file, NULL, p); p->type = old_type; return ret; } -static int v4l_g_crop(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_g_crop(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_crop *p = arg; @@ -2529,7 +2529,7 @@ static int v4l_g_crop(const struct v4l2_ioctl_ops *ops, s.target = s.target == V4L2_SEL_TGT_COMPOSE ? V4L2_SEL_TGT_CROP : V4L2_SEL_TGT_COMPOSE; - ret = v4l_g_selection(ops, file, fh, &s); + ret = v4l_g_selection(ops, file, &s); /* copying results to old structure on success */ if (!ret) @@ -2537,8 +2537,8 @@ static int v4l_g_crop(const struct v4l2_ioctl_ops *ops, return ret; } -static int v4l_s_crop(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_s_crop(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_crop *p = arg; @@ -2559,11 +2559,11 @@ static int v4l_s_crop(const struct v4l2_ioctl_ops *ops, s.target = s.target == V4L2_SEL_TGT_COMPOSE ? V4L2_SEL_TGT_CROP : V4L2_SEL_TGT_COMPOSE; - return v4l_s_selection(ops, file, fh, &s); + return v4l_s_selection(ops, file, &s); } -static int v4l_cropcap(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_cropcap(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_cropcap *p = arg; @@ -2587,7 +2587,7 @@ static int v4l_cropcap(const struct v4l2_ioctl_ops *ops, return -ENOTTY; if (ops->vidioc_g_pixelaspect) - ret = ops->vidioc_g_pixelaspect(file, fh, s.type, + ret = ops->vidioc_g_pixelaspect(file, NULL, s.type, &p->pixelaspect); /* @@ -2609,7 +2609,7 @@ static int v4l_cropcap(const struct v4l2_ioctl_ops *ops, s.target = s.target == V4L2_SEL_TGT_COMPOSE_BOUNDS ? V4L2_SEL_TGT_CROP_BOUNDS : V4L2_SEL_TGT_COMPOSE_BOUNDS; - ret = v4l_g_selection(ops, file, fh, &s); + ret = v4l_g_selection(ops, file, &s); if (ret) return ret; p->bounds = s.r; @@ -2620,7 +2620,7 @@ static int v4l_cropcap(const struct v4l2_ioctl_ops *ops, else s.target = V4L2_SEL_TGT_CROP_DEFAULT; - ret = v4l_g_selection(ops, file, fh, &s); + ret = v4l_g_selection(ops, file, &s); if (ret) return ret; p->defrect = s.r; @@ -2628,8 +2628,8 @@ static int v4l_cropcap(const struct v4l2_ioctl_ops *ops, return 0; } -static int v4l_log_status(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_log_status(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); int ret; @@ -2637,7 +2637,7 @@ static int v4l_log_status(const struct v4l2_ioctl_ops *ops, if (vfd->v4l2_dev) pr_info("%s: ================= START STATUS =================\n", vfd->v4l2_dev->name); - ret = ops->vidioc_log_status(file, fh); + ret = ops->vidioc_log_status(file, NULL); if (vfd->v4l2_dev) pr_info("%s: ================== END STATUS ==================\n", vfd->v4l2_dev->name); @@ -2645,7 +2645,7 @@ static int v4l_log_status(const struct v4l2_ioctl_ops *ops, } static int v4l_dbg_g_register(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { #ifdef CONFIG_VIDEO_ADV_DEBUG struct v4l2_dbg_register *p = arg; @@ -2665,7 +2665,7 @@ static int v4l_dbg_g_register(const struct v4l2_ioctl_ops *ops, } if (ops->vidioc_g_register && p->match.type == V4L2_CHIP_MATCH_BRIDGE && (ops->vidioc_g_chip_info || p->match.addr == 0)) - return ops->vidioc_g_register(file, fh, p); + return ops->vidioc_g_register(file, NULL, p); return -EINVAL; #else return -ENOTTY; @@ -2673,7 +2673,7 @@ static int v4l_dbg_g_register(const struct v4l2_ioctl_ops *ops, } static int v4l_dbg_s_register(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { #ifdef CONFIG_VIDEO_ADV_DEBUG const struct v4l2_dbg_register *p = arg; @@ -2693,7 +2693,7 @@ static int v4l_dbg_s_register(const struct v4l2_ioctl_ops *ops, } if (ops->vidioc_s_register && p->match.type == V4L2_CHIP_MATCH_BRIDGE && (ops->vidioc_g_chip_info || p->match.addr == 0)) - return ops->vidioc_s_register(file, fh, p); + return ops->vidioc_s_register(file, NULL, p); return -EINVAL; #else return -ENOTTY; @@ -2701,7 +2701,7 @@ static int v4l_dbg_s_register(const struct v4l2_ioctl_ops *ops, } static int v4l_dbg_g_chip_info(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { #ifdef CONFIG_VIDEO_ADV_DEBUG struct video_device *vfd = video_devdata(file); @@ -2717,7 +2717,7 @@ static int v4l_dbg_g_chip_info(const struct v4l2_ioctl_ops *ops, p->flags |= V4L2_CHIP_FL_READABLE; strscpy(p->name, vfd->v4l2_dev->name, sizeof(p->name)); if (ops->vidioc_g_chip_info) - return ops->vidioc_g_chip_info(file, fh, arg); + return ops->vidioc_g_chip_info(file, NULL, arg); if (p->match.addr) return -EINVAL; return 0; @@ -2743,8 +2743,8 @@ static int v4l_dbg_g_chip_info(const struct v4l2_ioctl_ops *ops, #endif } -static int v4l_dqevent(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_dqevent(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct v4l2_fh *vfh = file_to_v4l2_fh(file); @@ -2752,7 +2752,7 @@ static int v4l_dqevent(const struct v4l2_ioctl_ops *ops, } static int v4l_subscribe_event(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct v4l2_fh *vfh = file_to_v4l2_fh(file); @@ -2760,7 +2760,7 @@ static int v4l_subscribe_event(const struct v4l2_ioctl_ops *ops, } static int v4l_unsubscribe_event(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct v4l2_fh *vfh = file_to_v4l2_fh(file); @@ -2768,7 +2768,7 @@ static int v4l_unsubscribe_event(const struct v4l2_ioctl_ops *ops, } static int v4l_g_sliced_vbi_cap(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct v4l2_sliced_vbi_cap *p = arg; int ret = check_fmt(file, p->type); @@ -2779,11 +2779,11 @@ static int v4l_g_sliced_vbi_cap(const struct v4l2_ioctl_ops *ops, /* Clear up to type, everything after type is zeroed already */ memset(p, 0, offsetof(struct v4l2_sliced_vbi_cap, type)); - return ops->vidioc_g_sliced_vbi_cap(file, fh, p); + return ops->vidioc_g_sliced_vbi_cap(file, NULL, p); } static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_frequency_band *p = arg; @@ -2801,7 +2801,7 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops, return -EINVAL; } if (ops->vidioc_enum_freq_bands) { - err = ops->vidioc_enum_freq_bands(file, fh, p); + err = ops->vidioc_enum_freq_bands(file, NULL, p); if (err != -ENOTTY) return err; } @@ -2813,7 +2813,7 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops, if (p->index) return -EINVAL; - err = ops->vidioc_g_tuner(file, fh, &t); + err = ops->vidioc_g_tuner(file, NULL, &t); if (err) return err; p->capability = t.capability | V4L2_TUNER_CAP_FREQ_BANDS; @@ -2832,7 +2832,7 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops, return -EINVAL; if (p->index) return -EINVAL; - err = ops->vidioc_g_modulator(file, fh, &m); + err = ops->vidioc_g_modulator(file, NULL, &m); if (err) return err; p->capability = m.capability | V4L2_TUNER_CAP_FREQ_BANDS; @@ -2849,7 +2849,7 @@ struct v4l2_ioctl_info { u32 flags; const char * const name; int (*func)(const struct v4l2_ioctl_ops *ops, struct file *file, - void *fh, void *p); + void *p); void (*debug)(const void *arg, bool write_only); }; @@ -2870,9 +2870,9 @@ struct v4l2_ioctl_info { #define DEFINE_V4L_STUB_FUNC(_vidioc) \ static int v4l_stub_ ## _vidioc( \ const struct v4l2_ioctl_ops *ops, \ - struct file *file, void *fh, void *p) \ + struct file *file, void *p) \ { \ - return ops->vidioc_ ## _vidioc(file, fh, p); \ + return ops->vidioc_ ## _vidioc(file, NULL, p); \ } #define IOCTL_INFO(_ioctl, _func, _debug, _flags) \ @@ -3126,7 +3126,7 @@ static long __video_do_ioctl(struct file *file, write_only = _IOC_DIR(cmd) == _IOC_WRITE; if (info != &default_info) { - ret = info->func(ops, file, NULL, arg); + ret = info->func(ops, file, arg); } else if (!ops->vidioc_default) { ret = -ENOTTY; } else { From bb74fac758d46edddad56c66ae593a41b1553a2b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:30:53 +0300 Subject: [PATCH 00571/11391] media: test-drivers: Rename second ioctl handlers argument to 'void *priv' The second argument to the ioctl handlers is not a file handle any more. Rename it from 'void *fh' to 'void *priv', to avoid misconceptions. This is particularly important in test drivers as they are meant to be used as reference implementations. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- .../media/test-drivers/vicodec/vicodec-core.c | 14 +-- .../media/test-drivers/vimc/vimc-capture.c | 2 +- drivers/media/test-drivers/vivid/vivid-core.c | 96 +++++++++---------- .../media/test-drivers/vivid/vivid-radio-rx.c | 8 +- .../media/test-drivers/vivid/vivid-radio-rx.h | 8 +- .../media/test-drivers/vivid/vivid-radio-tx.c | 4 +- .../media/test-drivers/vivid/vivid-radio-tx.h | 4 +- .../media/test-drivers/vivid/vivid-sdr-cap.c | 18 ++-- .../media/test-drivers/vivid/vivid-sdr-cap.h | 18 ++-- .../media/test-drivers/vivid/vivid-vbi-cap.c | 10 +- .../media/test-drivers/vivid/vivid-vbi-cap.h | 8 +- .../media/test-drivers/vivid/vivid-vbi-out.c | 8 +- .../media/test-drivers/vivid/vivid-vbi-out.h | 6 +- .../media/test-drivers/vivid/vivid-vid-cap.c | 24 ++--- .../media/test-drivers/vivid/vivid-vid-cap.h | 24 ++--- .../test-drivers/vivid/vivid-vid-common.c | 8 +- .../test-drivers/vivid/vivid-vid-common.h | 8 +- .../media/test-drivers/vivid/vivid-vid-out.c | 16 ++-- .../media/test-drivers/vivid/vivid-vid-out.h | 16 ++-- 19 files changed, 150 insertions(+), 150 deletions(-) diff --git a/drivers/media/test-drivers/vicodec/vicodec-core.c b/drivers/media/test-drivers/vicodec/vicodec-core.c index c340fd226040..174ea761d09a 100644 --- a/drivers/media/test-drivers/vicodec/vicodec-core.c +++ b/drivers/media/test-drivers/vicodec/vicodec-core.c @@ -1207,20 +1207,20 @@ static int vidioc_s_selection(struct file *file, void *priv, return 0; } -static int vicodec_encoder_cmd(struct file *file, void *fh, +static int vicodec_encoder_cmd(struct file *file, void *priv, struct v4l2_encoder_cmd *ec) { struct vicodec_ctx *ctx = file2ctx(file); int ret; - ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec); + ret = v4l2_m2m_ioctl_try_encoder_cmd(file, priv, ec); if (ret < 0) return ret; if (!vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q)) return 0; - ret = v4l2_m2m_ioctl_encoder_cmd(file, fh, ec); + ret = v4l2_m2m_ioctl_encoder_cmd(file, priv, ec); if (ret < 0) return ret; @@ -1235,7 +1235,7 @@ static int vicodec_encoder_cmd(struct file *file, void *fh, return 0; } -static int vicodec_decoder_cmd(struct file *file, void *fh, +static int vicodec_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *dc) { struct vicodec_ctx *ctx = file2ctx(file); @@ -1247,14 +1247,14 @@ static int vicodec_decoder_cmd(struct file *file, void *fh, */ WARN_ON(ctx->is_stateless); - ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc); + ret = v4l2_m2m_ioctl_try_decoder_cmd(file, priv, dc); if (ret < 0) return ret; if (!vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q)) return 0; - ret = v4l2_m2m_ioctl_decoder_cmd(file, fh, dc); + ret = v4l2_m2m_ioctl_decoder_cmd(file, priv, dc); if (ret < 0) return ret; @@ -1269,7 +1269,7 @@ static int vicodec_decoder_cmd(struct file *file, void *fh, return 0; } -static int vicodec_enum_framesizes(struct file *file, void *fh, +static int vicodec_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize) { switch (fsize->pixel_format) { diff --git a/drivers/media/test-drivers/vimc/vimc-capture.c b/drivers/media/test-drivers/vimc/vimc-capture.c index 10df039278e7..45fda9d17bcb 100644 --- a/drivers/media/test-drivers/vimc/vimc-capture.c +++ b/drivers/media/test-drivers/vimc/vimc-capture.c @@ -169,7 +169,7 @@ static int vimc_capture_enum_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int vimc_capture_enum_framesizes(struct file *file, void *fh, +static int vimc_capture_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize) { const struct vimc_pix_map *vpix; diff --git a/drivers/media/test-drivers/vivid/vivid-core.c b/drivers/media/test-drivers/vivid/vivid-core.c index 9c9a93a3b540..86506be36acb 100644 --- a/drivers/media/test-drivers/vivid/vivid-core.c +++ b/drivers/media/test-drivers/vivid/vivid-core.c @@ -277,49 +277,49 @@ static int vidioc_querycap(struct file *file, void *priv, return 0; } -static int vidioc_s_hw_freq_seek(struct file *file, void *fh, const struct v4l2_hw_freq_seek *a) +static int vidioc_s_hw_freq_seek(struct file *file, void *priv, const struct v4l2_hw_freq_seek *a) { struct video_device *vdev = video_devdata(file); if (vdev->vfl_type == VFL_TYPE_RADIO) - return vivid_radio_rx_s_hw_freq_seek(file, fh, a); + return vivid_radio_rx_s_hw_freq_seek(file, priv, a); return -ENOTTY; } -static int vidioc_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band) +static int vidioc_enum_freq_bands(struct file *file, void *priv, struct v4l2_frequency_band *band) { struct video_device *vdev = video_devdata(file); if (vdev->vfl_type == VFL_TYPE_RADIO) - return vivid_radio_rx_enum_freq_bands(file, fh, band); + return vivid_radio_rx_enum_freq_bands(file, priv, band); if (vdev->vfl_type == VFL_TYPE_SDR) - return vivid_sdr_enum_freq_bands(file, fh, band); + return vivid_sdr_enum_freq_bands(file, priv, band); return -ENOTTY; } -static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) { struct video_device *vdev = video_devdata(file); if (vdev->vfl_type == VFL_TYPE_RADIO) - return vivid_radio_rx_g_tuner(file, fh, vt); + return vivid_radio_rx_g_tuner(file, priv, vt); if (vdev->vfl_type == VFL_TYPE_SDR) - return vivid_sdr_g_tuner(file, fh, vt); - return vivid_video_g_tuner(file, fh, vt); + return vivid_sdr_g_tuner(file, priv, vt); + return vivid_video_g_tuner(file, priv, vt); } -static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) +static int vidioc_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *vt) { struct video_device *vdev = video_devdata(file); if (vdev->vfl_type == VFL_TYPE_RADIO) - return vivid_radio_rx_s_tuner(file, fh, vt); + return vivid_radio_rx_s_tuner(file, priv, vt); if (vdev->vfl_type == VFL_TYPE_SDR) - return vivid_sdr_s_tuner(file, fh, vt); - return vivid_video_s_tuner(file, fh, vt); + return vivid_sdr_s_tuner(file, priv, vt); + return vivid_video_s_tuner(file, priv, vt); } -static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) +static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *vf) { struct vivid_dev *dev = video_drvdata(file); struct video_device *vdev = video_devdata(file); @@ -329,11 +329,11 @@ static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency vdev->vfl_dir == VFL_DIR_RX ? &dev->radio_rx_freq : &dev->radio_tx_freq, vf); if (vdev->vfl_type == VFL_TYPE_SDR) - return vivid_sdr_g_frequency(file, fh, vf); - return vivid_video_g_frequency(file, fh, vf); + return vivid_sdr_g_frequency(file, priv, vf); + return vivid_video_g_frequency(file, priv, vf); } -static int vidioc_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf) +static int vidioc_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *vf) { struct vivid_dev *dev = video_drvdata(file); struct video_device *vdev = video_devdata(file); @@ -343,113 +343,113 @@ static int vidioc_s_frequency(struct file *file, void *fh, const struct v4l2_fre vdev->vfl_dir == VFL_DIR_RX ? &dev->radio_rx_freq : &dev->radio_tx_freq, vf); if (vdev->vfl_type == VFL_TYPE_SDR) - return vivid_sdr_s_frequency(file, fh, vf); - return vivid_video_s_frequency(file, fh, vf); + return vivid_sdr_s_frequency(file, priv, vf); + return vivid_video_s_frequency(file, priv, vf); } -static int vidioc_overlay(struct file *file, void *fh, unsigned i) +static int vidioc_overlay(struct file *file, void *priv, unsigned i) { struct video_device *vdev = video_devdata(file); if (vdev->vfl_dir == VFL_DIR_RX) return -ENOTTY; - return vivid_vid_out_overlay(file, fh, i); + return vivid_vid_out_overlay(file, priv, i); } -static int vidioc_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *a) +static int vidioc_g_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *a) { struct video_device *vdev = video_devdata(file); if (vdev->vfl_dir == VFL_DIR_RX) return -ENOTTY; - return vivid_vid_out_g_fbuf(file, fh, a); + return vivid_vid_out_g_fbuf(file, priv, a); } -static int vidioc_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *a) +static int vidioc_s_fbuf(struct file *file, void *priv, const struct v4l2_framebuffer *a) { struct video_device *vdev = video_devdata(file); if (vdev->vfl_dir == VFL_DIR_RX) return -ENOTTY; - return vivid_vid_out_s_fbuf(file, fh, a); + return vivid_vid_out_s_fbuf(file, priv, a); } -static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id id) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) { struct video_device *vdev = video_devdata(file); if (vdev->vfl_dir == VFL_DIR_RX) - return vivid_vid_cap_s_std(file, fh, id); - return vivid_vid_out_s_std(file, fh, id); + return vivid_vid_cap_s_std(file, priv, id); + return vivid_vid_out_s_std(file, priv, id); } -static int vidioc_s_dv_timings(struct file *file, void *fh, struct v4l2_dv_timings *timings) +static int vidioc_s_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct video_device *vdev = video_devdata(file); if (vdev->vfl_dir == VFL_DIR_RX) - return vivid_vid_cap_s_dv_timings(file, fh, timings); - return vivid_vid_out_s_dv_timings(file, fh, timings); + return vivid_vid_cap_s_dv_timings(file, priv, timings); + return vivid_vid_out_s_dv_timings(file, priv, timings); } -static int vidioc_g_pixelaspect(struct file *file, void *fh, +static int vidioc_g_pixelaspect(struct file *file, void *priv, int type, struct v4l2_fract *f) { struct video_device *vdev = video_devdata(file); if (vdev->vfl_dir == VFL_DIR_RX) - return vivid_vid_cap_g_pixelaspect(file, fh, type, f); - return vivid_vid_out_g_pixelaspect(file, fh, type, f); + return vivid_vid_cap_g_pixelaspect(file, priv, type, f); + return vivid_vid_out_g_pixelaspect(file, priv, type, f); } -static int vidioc_g_selection(struct file *file, void *fh, +static int vidioc_g_selection(struct file *file, void *priv, struct v4l2_selection *sel) { struct video_device *vdev = video_devdata(file); if (vdev->vfl_dir == VFL_DIR_RX) - return vivid_vid_cap_g_selection(file, fh, sel); - return vivid_vid_out_g_selection(file, fh, sel); + return vivid_vid_cap_g_selection(file, priv, sel); + return vivid_vid_out_g_selection(file, priv, sel); } -static int vidioc_s_selection(struct file *file, void *fh, +static int vidioc_s_selection(struct file *file, void *priv, struct v4l2_selection *sel) { struct video_device *vdev = video_devdata(file); if (vdev->vfl_dir == VFL_DIR_RX) - return vivid_vid_cap_s_selection(file, fh, sel); - return vivid_vid_out_s_selection(file, fh, sel); + return vivid_vid_cap_s_selection(file, priv, sel); + return vivid_vid_out_s_selection(file, priv, sel); } -static int vidioc_g_parm(struct file *file, void *fh, +static int vidioc_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm) { struct video_device *vdev = video_devdata(file); if (vdev->vfl_type == VFL_TYPE_TOUCH) - return vivid_g_parm_tch(file, fh, parm); + return vivid_g_parm_tch(file, priv, parm); if (vdev->vfl_dir == VFL_DIR_RX) - return vivid_vid_cap_g_parm(file, fh, parm); - return vivid_vid_out_g_parm(file, fh, parm); + return vivid_vid_cap_g_parm(file, priv, parm); + return vivid_vid_out_g_parm(file, priv, parm); } -static int vidioc_s_parm(struct file *file, void *fh, +static int vidioc_s_parm(struct file *file, void *priv, struct v4l2_streamparm *parm) { struct video_device *vdev = video_devdata(file); if (vdev->vfl_dir == VFL_DIR_RX) - return vivid_vid_cap_s_parm(file, fh, parm); + return vivid_vid_cap_s_parm(file, priv, parm); return -ENOTTY; } -static int vidioc_log_status(struct file *file, void *fh) +static int vidioc_log_status(struct file *file, void *priv) { struct vivid_dev *dev = video_drvdata(file); struct video_device *vdev = video_devdata(file); - v4l2_ctrl_log_status(file, fh); + v4l2_ctrl_log_status(file, priv); if (vdev->vfl_dir == VFL_DIR_RX && vdev->vfl_type == VFL_TYPE_VIDEO) tpg_log_status(&dev->tpg); return 0; diff --git a/drivers/media/test-drivers/vivid/vivid-radio-rx.c b/drivers/media/test-drivers/vivid/vivid-radio-rx.c index be711cae2d49..b5e3026f883e 100644 --- a/drivers/media/test-drivers/vivid/vivid-radio-rx.c +++ b/drivers/media/test-drivers/vivid/vivid-radio-rx.c @@ -133,7 +133,7 @@ __poll_t vivid_radio_rx_poll(struct file *file, struct poll_table_struct *wait) return EPOLLIN | EPOLLRDNORM | v4l2_ctrl_poll(file, wait); } -int vivid_radio_rx_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band) +int vivid_radio_rx_enum_freq_bands(struct file *file, void *priv, struct v4l2_frequency_band *band) { if (band->tuner != 0) return -EINVAL; @@ -145,7 +145,7 @@ int vivid_radio_rx_enum_freq_bands(struct file *file, void *fh, struct v4l2_freq return 0; } -int vivid_radio_rx_s_hw_freq_seek(struct file *file, void *fh, const struct v4l2_hw_freq_seek *a) +int vivid_radio_rx_s_hw_freq_seek(struct file *file, void *priv, const struct v4l2_hw_freq_seek *a) { struct vivid_dev *dev = video_drvdata(file); unsigned low, high; @@ -214,7 +214,7 @@ int vivid_radio_rx_s_hw_freq_seek(struct file *file, void *fh, const struct v4l2 return 0; } -int vivid_radio_rx_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +int vivid_radio_rx_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) { struct vivid_dev *dev = video_drvdata(file); int delta = 800; @@ -267,7 +267,7 @@ int vivid_radio_rx_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) return 0; } -int vivid_radio_rx_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) +int vivid_radio_rx_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *vt) { struct vivid_dev *dev = video_drvdata(file); diff --git a/drivers/media/test-drivers/vivid/vivid-radio-rx.h b/drivers/media/test-drivers/vivid/vivid-radio-rx.h index c9c7849f6f99..a2ae17c78ece 100644 --- a/drivers/media/test-drivers/vivid/vivid-radio-rx.h +++ b/drivers/media/test-drivers/vivid/vivid-radio-rx.h @@ -11,9 +11,9 @@ ssize_t vivid_radio_rx_read(struct file *, char __user *, size_t, loff_t *); __poll_t vivid_radio_rx_poll(struct file *file, struct poll_table_struct *wait); -int vivid_radio_rx_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band); -int vivid_radio_rx_s_hw_freq_seek(struct file *file, void *fh, const struct v4l2_hw_freq_seek *a); -int vivid_radio_rx_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt); -int vivid_radio_rx_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt); +int vivid_radio_rx_enum_freq_bands(struct file *file, void *priv, struct v4l2_frequency_band *band); +int vivid_radio_rx_s_hw_freq_seek(struct file *file, void *priv, const struct v4l2_hw_freq_seek *a); +int vivid_radio_rx_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt); +int vivid_radio_rx_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *vt); #endif diff --git a/drivers/media/test-drivers/vivid/vivid-radio-tx.c b/drivers/media/test-drivers/vivid/vivid-radio-tx.c index f6e80b8d00a6..ada60722066e 100644 --- a/drivers/media/test-drivers/vivid/vivid-radio-tx.c +++ b/drivers/media/test-drivers/vivid/vivid-radio-tx.c @@ -96,7 +96,7 @@ __poll_t vivid_radio_tx_poll(struct file *file, struct poll_table_struct *wait) return EPOLLOUT | EPOLLWRNORM | v4l2_ctrl_poll(file, wait); } -int vidioc_g_modulator(struct file *file, void *fh, struct v4l2_modulator *a) +int vidioc_g_modulator(struct file *file, void *priv, struct v4l2_modulator *a) { struct vivid_dev *dev = video_drvdata(file); @@ -115,7 +115,7 @@ int vidioc_g_modulator(struct file *file, void *fh, struct v4l2_modulator *a) return 0; } -int vidioc_s_modulator(struct file *file, void *fh, const struct v4l2_modulator *a) +int vidioc_s_modulator(struct file *file, void *priv, const struct v4l2_modulator *a) { struct vivid_dev *dev = video_drvdata(file); diff --git a/drivers/media/test-drivers/vivid/vivid-radio-tx.h b/drivers/media/test-drivers/vivid/vivid-radio-tx.h index c2bf1e7e634a..20cb6f1363ff 100644 --- a/drivers/media/test-drivers/vivid/vivid-radio-tx.h +++ b/drivers/media/test-drivers/vivid/vivid-radio-tx.h @@ -11,7 +11,7 @@ ssize_t vivid_radio_tx_write(struct file *, const char __user *, size_t, loff_t *); __poll_t vivid_radio_tx_poll(struct file *file, struct poll_table_struct *wait); -int vidioc_g_modulator(struct file *file, void *fh, struct v4l2_modulator *a); -int vidioc_s_modulator(struct file *file, void *fh, const struct v4l2_modulator *a); +int vidioc_g_modulator(struct file *file, void *priv, struct v4l2_modulator *a); +int vidioc_s_modulator(struct file *file, void *priv, const struct v4l2_modulator *a); #endif diff --git a/drivers/media/test-drivers/vivid/vivid-sdr-cap.c b/drivers/media/test-drivers/vivid/vivid-sdr-cap.c index c633fc2ed664..2664a593e8e1 100644 --- a/drivers/media/test-drivers/vivid/vivid-sdr-cap.c +++ b/drivers/media/test-drivers/vivid/vivid-sdr-cap.c @@ -344,7 +344,7 @@ const struct vb2_ops vivid_sdr_cap_qops = { .buf_request_complete = sdr_cap_buf_request_complete, }; -int vivid_sdr_enum_freq_bands(struct file *file, void *fh, +int vivid_sdr_enum_freq_bands(struct file *file, void *priv, struct v4l2_frequency_band *band) { switch (band->tuner) { @@ -363,7 +363,7 @@ int vivid_sdr_enum_freq_bands(struct file *file, void *fh, } } -int vivid_sdr_g_frequency(struct file *file, void *fh, +int vivid_sdr_g_frequency(struct file *file, void *priv, struct v4l2_frequency *vf) { struct vivid_dev *dev = video_drvdata(file); @@ -382,7 +382,7 @@ int vivid_sdr_g_frequency(struct file *file, void *fh, } } -int vivid_sdr_s_frequency(struct file *file, void *fh, +int vivid_sdr_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *vf) { struct vivid_dev *dev = video_drvdata(file); @@ -423,7 +423,7 @@ int vivid_sdr_s_frequency(struct file *file, void *fh, } } -int vivid_sdr_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +int vivid_sdr_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) { switch (vt->index) { case 0: @@ -447,14 +447,14 @@ int vivid_sdr_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) } } -int vivid_sdr_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) +int vivid_sdr_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *vt) { if (vt->index > 1) return -EINVAL; return 0; } -int vidioc_enum_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) +int vidioc_enum_fmt_sdr_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (f->index >= ARRAY_SIZE(formats)) return -EINVAL; @@ -462,7 +462,7 @@ int vidioc_enum_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) return 0; } -int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f) +int vidioc_g_fmt_sdr_cap(struct file *file, void *priv, struct v4l2_format *f) { struct vivid_dev *dev = video_drvdata(file); @@ -471,7 +471,7 @@ int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f) return 0; } -int vidioc_s_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f) +int vidioc_s_fmt_sdr_cap(struct file *file, void *priv, struct v4l2_format *f) { struct vivid_dev *dev = video_drvdata(file); struct vb2_queue *q = &dev->vb_sdr_cap_q; @@ -495,7 +495,7 @@ int vidioc_s_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f) return 0; } -int vidioc_try_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f) +int vidioc_try_fmt_sdr_cap(struct file *file, void *priv, struct v4l2_format *f) { int i; diff --git a/drivers/media/test-drivers/vivid/vivid-sdr-cap.h b/drivers/media/test-drivers/vivid/vivid-sdr-cap.h index 813c9248e5a7..3d8eeabbfc10 100644 --- a/drivers/media/test-drivers/vivid/vivid-sdr-cap.h +++ b/drivers/media/test-drivers/vivid/vivid-sdr-cap.h @@ -8,15 +8,15 @@ #ifndef _VIVID_SDR_CAP_H_ #define _VIVID_SDR_CAP_H_ -int vivid_sdr_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band); -int vivid_sdr_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf); -int vivid_sdr_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf); -int vivid_sdr_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt); -int vivid_sdr_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt); -int vidioc_enum_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f); -int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f); -int vidioc_s_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f); -int vidioc_try_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f); +int vivid_sdr_enum_freq_bands(struct file *file, void *priv, struct v4l2_frequency_band *band); +int vivid_sdr_g_frequency(struct file *file, void *priv, struct v4l2_frequency *vf); +int vivid_sdr_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *vf); +int vivid_sdr_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt); +int vivid_sdr_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *vt); +int vidioc_enum_fmt_sdr_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f); +int vidioc_g_fmt_sdr_cap(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_s_fmt_sdr_cap(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_try_fmt_sdr_cap(struct file *file, void *priv, struct v4l2_format *f); void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf); extern const struct vb2_ops vivid_sdr_cap_qops; diff --git a/drivers/media/test-drivers/vivid/vivid-vbi-cap.c b/drivers/media/test-drivers/vivid/vivid-vbi-cap.c index a09f62c66c33..791382a54b4f 100644 --- a/drivers/media/test-drivers/vivid/vivid-vbi-cap.c +++ b/drivers/media/test-drivers/vivid/vivid-vbi-cap.c @@ -282,7 +282,7 @@ void vivid_fill_service_lines(struct v4l2_sliced_vbi_format *vbi, u32 service_se } } -int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) +int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv, struct v4l2_format *fmt) { struct vivid_dev *dev = video_drvdata(file); struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; @@ -294,7 +294,7 @@ int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format return 0; } -int vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) +int vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *priv, struct v4l2_format *fmt) { struct vivid_dev *dev = video_drvdata(file); struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; @@ -310,11 +310,11 @@ int vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_forma return 0; } -int vidioc_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) +int vidioc_s_fmt_sliced_vbi_cap(struct file *file, void *priv, struct v4l2_format *fmt) { struct vivid_dev *dev = video_drvdata(file); struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; - int ret = vidioc_try_fmt_sliced_vbi_cap(file, fh, fmt); + int ret = vidioc_try_fmt_sliced_vbi_cap(file, priv, fmt); if (ret) return ret; @@ -324,7 +324,7 @@ int vidioc_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format return 0; } -int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap) +int vidioc_g_sliced_vbi_cap(struct file *file, void *priv, struct v4l2_sliced_vbi_cap *cap) { struct vivid_dev *dev = video_drvdata(file); struct video_device *vdev = video_devdata(file); diff --git a/drivers/media/test-drivers/vivid/vivid-vbi-cap.h b/drivers/media/test-drivers/vivid/vivid-vbi-cap.h index 91d2de01381c..ec2d200c9e0d 100644 --- a/drivers/media/test-drivers/vivid/vivid-vbi-cap.h +++ b/drivers/media/test-drivers/vivid/vivid-vbi-cap.h @@ -16,10 +16,10 @@ int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, struct v4l2_format *f); int vidioc_s_fmt_vbi_cap(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt); -int vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt); -int vidioc_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt); -int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap); +int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv, struct v4l2_format *fmt); +int vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *priv, struct v4l2_format *fmt); +int vidioc_s_fmt_sliced_vbi_cap(struct file *file, void *priv, struct v4l2_format *fmt); +int vidioc_g_sliced_vbi_cap(struct file *file, void *priv, struct v4l2_sliced_vbi_cap *cap); void vivid_fill_service_lines(struct v4l2_sliced_vbi_format *vbi, u32 service_set); diff --git a/drivers/media/test-drivers/vivid/vivid-vbi-out.c b/drivers/media/test-drivers/vivid/vivid-vbi-out.c index b7a09d2f394e..7b3ea96744bb 100644 --- a/drivers/media/test-drivers/vivid/vivid-vbi-out.c +++ b/drivers/media/test-drivers/vivid/vivid-vbi-out.c @@ -168,7 +168,7 @@ int vidioc_s_fmt_vbi_out(struct file *file, void *priv, return 0; } -int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) +int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *priv, struct v4l2_format *fmt) { struct vivid_dev *dev = video_drvdata(file); struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; @@ -180,7 +180,7 @@ int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format return 0; } -int vidioc_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) +int vidioc_try_fmt_sliced_vbi_out(struct file *file, void *priv, struct v4l2_format *fmt) { struct vivid_dev *dev = video_drvdata(file); struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; @@ -196,12 +196,12 @@ int vidioc_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_forma return 0; } -int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh, +int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *priv, struct v4l2_format *fmt) { struct vivid_dev *dev = video_drvdata(file); struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; - int ret = vidioc_try_fmt_sliced_vbi_out(file, fh, fmt); + int ret = vidioc_try_fmt_sliced_vbi_out(file, priv, fmt); if (ret) return ret; diff --git a/drivers/media/test-drivers/vivid/vivid-vbi-out.h b/drivers/media/test-drivers/vivid/vivid-vbi-out.h index 76584940cdaf..a28e55519ade 100644 --- a/drivers/media/test-drivers/vivid/vivid-vbi-out.h +++ b/drivers/media/test-drivers/vivid/vivid-vbi-out.h @@ -13,9 +13,9 @@ int vidioc_g_fmt_vbi_out(struct file *file, void *priv, struct v4l2_format *f); int vidioc_s_fmt_vbi_out(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt); -int vidioc_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt); -int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt); +int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *priv, struct v4l2_format *fmt); +int vidioc_try_fmt_sliced_vbi_out(struct file *file, void *priv, struct v4l2_format *fmt); +int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *priv, struct v4l2_format *fmt); extern const struct vb2_ops vivid_vbi_out_qops; diff --git a/drivers/media/test-drivers/vivid/vivid-vid-cap.c b/drivers/media/test-drivers/vivid/vivid-vid-cap.c index 2e4c1ed37cd2..8b3162e82032 100644 --- a/drivers/media/test-drivers/vivid/vivid-vid-cap.c +++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.c @@ -899,7 +899,7 @@ int vivid_vid_cap_g_selection(struct file *file, void *priv, return 0; } -int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection *s) +int vivid_vid_cap_s_selection(struct file *file, void *priv, struct v4l2_selection *s) { struct vivid_dev *dev = video_drvdata(file); struct v4l2_rect *crop = &dev->crop_cap; @@ -1222,7 +1222,7 @@ int vidioc_s_input(struct file *file, void *priv, unsigned i) return 0; } -int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin) +int vidioc_enumaudio(struct file *file, void *priv, struct v4l2_audio *vin) { if (vin->index >= ARRAY_SIZE(vivid_audio_inputs)) return -EINVAL; @@ -1230,7 +1230,7 @@ int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin) return 0; } -int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) +int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *vin) { struct vivid_dev *dev = video_drvdata(file); @@ -1240,7 +1240,7 @@ int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) return 0; } -int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *vin) +int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio *vin) { struct vivid_dev *dev = video_drvdata(file); @@ -1252,7 +1252,7 @@ int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *vin) return 0; } -int vivid_video_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) +int vivid_video_g_frequency(struct file *file, void *priv, struct v4l2_frequency *vf) { struct vivid_dev *dev = video_drvdata(file); @@ -1262,7 +1262,7 @@ int vivid_video_g_frequency(struct file *file, void *fh, struct v4l2_frequency * return 0; } -int vivid_video_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf) +int vivid_video_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *vf) { struct vivid_dev *dev = video_drvdata(file); @@ -1274,7 +1274,7 @@ int vivid_video_s_frequency(struct file *file, void *fh, const struct v4l2_frequ return 0; } -int vivid_video_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) +int vivid_video_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *vt) { struct vivid_dev *dev = video_drvdata(file); @@ -1286,7 +1286,7 @@ int vivid_video_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt return 0; } -int vivid_video_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +int vivid_video_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) { struct vivid_dev *dev = video_drvdata(file); enum tpg_quality qual; @@ -1490,7 +1490,7 @@ static bool valid_cvt_gtf_timings(struct v4l2_dv_timings *timings) return false; } -int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh, +int vivid_vid_cap_s_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct vivid_dev *dev = video_drvdata(file); @@ -1513,7 +1513,7 @@ int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh, return 0; } -int vidioc_query_dv_timings(struct file *file, void *_fh, +int vidioc_query_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct vivid_dev *dev = video_drvdata(file); @@ -1600,7 +1600,7 @@ void vivid_update_connected_outputs(struct vivid_dev *dev) } } -int vidioc_s_edid(struct file *file, void *_fh, +int vidioc_s_edid(struct file *file, void *priv, struct v4l2_edid *edid) { struct vivid_dev *dev = video_drvdata(file); @@ -1638,7 +1638,7 @@ int vidioc_s_edid(struct file *file, void *_fh, return 0; } -int vidioc_enum_framesizes(struct file *file, void *fh, +int vidioc_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize) { struct vivid_dev *dev = video_drvdata(file); diff --git a/drivers/media/test-drivers/vivid/vivid-vid-cap.h b/drivers/media/test-drivers/vivid/vivid-vid-cap.h index 7a8daf0af2ca..38a99f7e038e 100644 --- a/drivers/media/test-drivers/vivid/vivid-vid-cap.h +++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.h @@ -29,7 +29,7 @@ int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); int vivid_vid_cap_g_selection(struct file *file, void *priv, struct v4l2_selection *sel); -int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection *s); +int vivid_vid_cap_s_selection(struct file *file, void *priv, struct v4l2_selection *s); int vivid_vid_cap_g_pixelaspect(struct file *file, void *priv, int type, struct v4l2_fract *f); int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_fmtdesc *f); int vidioc_g_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f); @@ -38,19 +38,19 @@ int vidioc_s_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format * int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *inp); int vidioc_g_input(struct file *file, void *priv, unsigned *i); int vidioc_s_input(struct file *file, void *priv, unsigned i); -int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin); -int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *vin); -int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *vin); -int vivid_video_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf); -int vivid_video_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf); -int vivid_video_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt); -int vivid_video_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt); +int vidioc_enumaudio(struct file *file, void *priv, struct v4l2_audio *vin); +int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *vin); +int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio *vin); +int vivid_video_g_frequency(struct file *file, void *priv, struct v4l2_frequency *vf); +int vivid_video_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *vf); +int vivid_video_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *vt); +int vivid_video_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt); int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *id); int vivid_vid_cap_s_std(struct file *file, void *priv, v4l2_std_id id); -int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings); -int vidioc_query_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings); -int vidioc_s_edid(struct file *file, void *_fh, struct v4l2_edid *edid); -int vidioc_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize); +int vivid_vid_cap_s_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings); +int vidioc_query_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings); +int vidioc_s_edid(struct file *file, void *priv, struct v4l2_edid *edid); +int vidioc_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize); int vidioc_enum_frameintervals(struct file *file, void *priv, struct v4l2_frmivalenum *fival); int vivid_vid_cap_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm); int vivid_vid_cap_s_parm(struct file *file, void *priv, struct v4l2_streamparm *parm); diff --git a/drivers/media/test-drivers/vivid/vivid-vid-common.c b/drivers/media/test-drivers/vivid/vivid-vid-common.c index df7678db67fb..786a1aa3b26b 100644 --- a/drivers/media/test-drivers/vivid/vivid-vid-common.c +++ b/drivers/media/test-drivers/vivid/vivid-vid-common.c @@ -1021,7 +1021,7 @@ int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) return 0; } -int vidioc_g_dv_timings(struct file *file, void *_fh, +int vidioc_g_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct vivid_dev *dev = video_drvdata(file); @@ -1039,7 +1039,7 @@ int vidioc_g_dv_timings(struct file *file, void *_fh, return 0; } -int vidioc_enum_dv_timings(struct file *file, void *_fh, +int vidioc_enum_dv_timings(struct file *file, void *priv, struct v4l2_enum_dv_timings *timings) { struct vivid_dev *dev = video_drvdata(file); @@ -1056,7 +1056,7 @@ int vidioc_enum_dv_timings(struct file *file, void *_fh, NULL, NULL); } -int vidioc_dv_timings_cap(struct file *file, void *_fh, +int vidioc_dv_timings_cap(struct file *file, void *priv, struct v4l2_dv_timings_cap *cap) { struct vivid_dev *dev = video_drvdata(file); @@ -1073,7 +1073,7 @@ int vidioc_dv_timings_cap(struct file *file, void *_fh, return 0; } -int vidioc_g_edid(struct file *file, void *_fh, +int vidioc_g_edid(struct file *file, void *priv, struct v4l2_edid *edid) { struct vivid_dev *dev = video_drvdata(file); diff --git a/drivers/media/test-drivers/vivid/vivid-vid-common.h b/drivers/media/test-drivers/vivid/vivid-vid-common.h index c49ac85abaed..fb5878174dba 100644 --- a/drivers/media/test-drivers/vivid/vivid-vid-common.h +++ b/drivers/media/test-drivers/vivid/vivid-vid-common.h @@ -32,10 +32,10 @@ int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r); int vivid_enum_fmt_vid(struct file *file, void *priv, struct v4l2_fmtdesc *f); int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id); -int vidioc_g_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings); -int vidioc_enum_dv_timings(struct file *file, void *_fh, struct v4l2_enum_dv_timings *timings); -int vidioc_dv_timings_cap(struct file *file, void *_fh, struct v4l2_dv_timings_cap *cap); -int vidioc_g_edid(struct file *file, void *_fh, struct v4l2_edid *edid); +int vidioc_g_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings); +int vidioc_enum_dv_timings(struct file *file, void *priv, struct v4l2_enum_dv_timings *timings); +int vidioc_dv_timings_cap(struct file *file, void *priv, struct v4l2_dv_timings_cap *cap); +int vidioc_g_edid(struct file *file, void *priv, struct v4l2_edid *edid); int vidioc_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub); #endif diff --git a/drivers/media/test-drivers/vivid/vivid-vid-out.c b/drivers/media/test-drivers/vivid/vivid-vid-out.c index c3398bce6c15..8c037b90833e 100644 --- a/drivers/media/test-drivers/vivid/vivid-vid-out.c +++ b/drivers/media/test-drivers/vivid/vivid-vid-out.c @@ -672,7 +672,7 @@ int vivid_vid_out_g_selection(struct file *file, void *priv, return 0; } -int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection *s) +int vivid_vid_out_s_selection(struct file *file, void *priv, struct v4l2_selection *s) { struct vivid_dev *dev = video_drvdata(file); struct v4l2_rect *crop = &dev->crop_out; @@ -880,7 +880,7 @@ int vidioc_s_fmt_vid_out_overlay(struct file *file, void *priv, return ret; } -int vivid_vid_out_overlay(struct file *file, void *fh, unsigned i) +int vivid_vid_out_overlay(struct file *file, void *priv, unsigned i) { struct vivid_dev *dev = video_drvdata(file); @@ -893,7 +893,7 @@ int vivid_vid_out_overlay(struct file *file, void *fh, unsigned i) return 0; } -int vivid_vid_out_g_fbuf(struct file *file, void *fh, +int vivid_vid_out_g_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *a) { struct vivid_dev *dev = video_drvdata(file); @@ -920,7 +920,7 @@ int vivid_vid_out_g_fbuf(struct file *file, void *fh, return 0; } -int vivid_vid_out_s_fbuf(struct file *file, void *fh, +int vivid_vid_out_s_fbuf(struct file *file, void *priv, const struct v4l2_framebuffer *a) { struct vivid_dev *dev = video_drvdata(file); @@ -1016,7 +1016,7 @@ int vidioc_s_output(struct file *file, void *priv, unsigned o) return 0; } -int vidioc_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vout) +int vidioc_enumaudout(struct file *file, void *priv, struct v4l2_audioout *vout) { if (vout->index >= ARRAY_SIZE(vivid_audio_outputs)) return -EINVAL; @@ -1024,7 +1024,7 @@ int vidioc_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vout) return 0; } -int vidioc_g_audout(struct file *file, void *fh, struct v4l2_audioout *vout) +int vidioc_g_audout(struct file *file, void *priv, struct v4l2_audioout *vout) { struct vivid_dev *dev = video_drvdata(file); @@ -1034,7 +1034,7 @@ int vidioc_g_audout(struct file *file, void *fh, struct v4l2_audioout *vout) return 0; } -int vidioc_s_audout(struct file *file, void *fh, const struct v4l2_audioout *vout) +int vidioc_s_audout(struct file *file, void *priv, const struct v4l2_audioout *vout) { struct vivid_dev *dev = video_drvdata(file); @@ -1072,7 +1072,7 @@ static bool valid_cvt_gtf_timings(struct v4l2_dv_timings *timings) return false; } -int vivid_vid_out_s_dv_timings(struct file *file, void *_fh, +int vivid_vid_out_s_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct vivid_dev *dev = video_drvdata(file); diff --git a/drivers/media/test-drivers/vivid/vivid-vid-out.h b/drivers/media/test-drivers/vivid/vivid-vid-out.h index 8d56314f4ea1..1d03891a5de5 100644 --- a/drivers/media/test-drivers/vivid/vivid-vid-out.h +++ b/drivers/media/test-drivers/vivid/vivid-vid-out.h @@ -22,23 +22,23 @@ int vidioc_g_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); int vidioc_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); int vidioc_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); int vivid_vid_out_g_selection(struct file *file, void *priv, struct v4l2_selection *sel); -int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection *s); +int vivid_vid_out_s_selection(struct file *file, void *priv, struct v4l2_selection *s); int vivid_vid_out_g_pixelaspect(struct file *file, void *priv, int type, struct v4l2_fract *f); int vidioc_enum_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_fmtdesc *f); int vidioc_g_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_format *f); int vidioc_try_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_format *f); int vidioc_s_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_format *f); -int vivid_vid_out_overlay(struct file *file, void *fh, unsigned i); -int vivid_vid_out_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *a); -int vivid_vid_out_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *a); +int vivid_vid_out_overlay(struct file *file, void *priv, unsigned i); +int vivid_vid_out_g_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *a); +int vivid_vid_out_s_fbuf(struct file *file, void *priv, const struct v4l2_framebuffer *a); int vidioc_enum_output(struct file *file, void *priv, struct v4l2_output *out); int vidioc_g_output(struct file *file, void *priv, unsigned *i); int vidioc_s_output(struct file *file, void *priv, unsigned i); -int vidioc_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vout); -int vidioc_g_audout(struct file *file, void *fh, struct v4l2_audioout *vout); -int vidioc_s_audout(struct file *file, void *fh, const struct v4l2_audioout *vout); +int vidioc_enumaudout(struct file *file, void *priv, struct v4l2_audioout *vout); +int vidioc_g_audout(struct file *file, void *priv, struct v4l2_audioout *vout); +int vidioc_s_audout(struct file *file, void *priv, const struct v4l2_audioout *vout); int vivid_vid_out_s_std(struct file *file, void *priv, v4l2_std_id id); -int vivid_vid_out_s_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings); +int vivid_vid_out_s_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings); int vivid_vid_out_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm); #endif From 0960b6937bd99d775b3a7220135ecc546bfb9623 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:30:54 +0300 Subject: [PATCH 00572/11391] media: uvcvideo: Rename second ioctl handlers argument to 'void *priv' The second argument to the ioctl handlers is not a file handle any more. Rename it from 'void *fh' to 'void *priv', to avoid misconceptions. This is particularly important in the uvcvideo driver, as it is widely used and can be taken as an example for new drivers. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/usb/uvc/uvc_metadata.c | 12 ++++----- drivers/media/usb/uvc/uvc_v4l2.c | 38 ++++++++++++++-------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_metadata.c b/drivers/media/usb/uvc/uvc_metadata.c index 4cbf6ce314fd..3b0b39289511 100644 --- a/drivers/media/usb/uvc/uvc_metadata.c +++ b/drivers/media/usb/uvc/uvc_metadata.c @@ -23,7 +23,7 @@ * V4L2 ioctls */ -static int uvc_meta_v4l2_querycap(struct file *file, void *fh, +static int uvc_meta_v4l2_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { struct v4l2_fh *vfh = file_to_v4l2_fh(file); @@ -39,7 +39,7 @@ static int uvc_meta_v4l2_querycap(struct file *file, void *fh, return 0; } -static int uvc_meta_v4l2_get_format(struct file *file, void *fh, +static int uvc_meta_v4l2_get_format(struct file *file, void *priv, struct v4l2_format *format) { struct v4l2_fh *vfh = file_to_v4l2_fh(file); @@ -57,7 +57,7 @@ static int uvc_meta_v4l2_get_format(struct file *file, void *fh, return 0; } -static int uvc_meta_v4l2_try_format(struct file *file, void *fh, +static int uvc_meta_v4l2_try_format(struct file *file, void *priv, struct v4l2_format *format) { struct v4l2_fh *vfh = file_to_v4l2_fh(file); @@ -83,7 +83,7 @@ static int uvc_meta_v4l2_try_format(struct file *file, void *fh, return 0; } -static int uvc_meta_v4l2_set_format(struct file *file, void *fh, +static int uvc_meta_v4l2_set_format(struct file *file, void *priv, struct v4l2_format *format) { struct v4l2_fh *vfh = file_to_v4l2_fh(file); @@ -91,7 +91,7 @@ static int uvc_meta_v4l2_set_format(struct file *file, void *fh, struct v4l2_meta_format *fmt = &format->fmt.meta; int ret; - ret = uvc_meta_v4l2_try_format(file, fh, format); + ret = uvc_meta_v4l2_try_format(file, priv, format); if (ret < 0) return ret; @@ -112,7 +112,7 @@ static int uvc_meta_v4l2_set_format(struct file *file, void *fh, return ret; } -static int uvc_meta_v4l2_enum_formats(struct file *file, void *fh, +static int uvc_meta_v4l2_enum_formats(struct file *file, void *priv, struct v4l2_fmtdesc *fdesc) { struct v4l2_fh *vfh = file_to_v4l2_fh(file); diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 10196d62f287..f6e065f36ce0 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -388,7 +388,7 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, return ret; } -static int uvc_ioctl_g_fmt(struct file *file, void *fh, +static int uvc_ioctl_g_fmt(struct file *file, void *priv, struct v4l2_format *fmt) { struct uvc_fh *handle = to_uvc_fh(file); @@ -424,7 +424,7 @@ static int uvc_ioctl_g_fmt(struct file *file, void *fh, return ret; } -static int uvc_ioctl_s_fmt(struct file *file, void *fh, +static int uvc_ioctl_s_fmt(struct file *file, void *priv, struct v4l2_format *fmt) { struct uvc_fh *handle = to_uvc_fh(file); @@ -456,7 +456,7 @@ static int uvc_ioctl_s_fmt(struct file *file, void *fh, return ret; } -static int uvc_ioctl_g_parm(struct file *file, void *fh, +static int uvc_ioctl_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm) { u32 numerator, denominator; @@ -493,7 +493,7 @@ static int uvc_ioctl_g_parm(struct file *file, void *fh, return 0; } -static int uvc_ioctl_s_parm(struct file *file, void *fh, +static int uvc_ioctl_s_parm(struct file *file, void *priv, struct v4l2_streamparm *parm) { struct uvc_fh *handle = to_uvc_fh(file); @@ -622,7 +622,7 @@ static int uvc_v4l2_release(struct file *file) return 0; } -static int uvc_ioctl_querycap(struct file *file, void *fh, +static int uvc_ioctl_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { struct uvc_fh *handle = to_uvc_fh(file); @@ -638,7 +638,7 @@ static int uvc_ioctl_querycap(struct file *file, void *fh, return 0; } -static int uvc_ioctl_enum_fmt(struct file *file, void *fh, +static int uvc_ioctl_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *fmt) { struct uvc_fh *handle = to_uvc_fh(file); @@ -662,7 +662,7 @@ static int uvc_ioctl_enum_fmt(struct file *file, void *fh, return 0; } -static int uvc_ioctl_try_fmt(struct file *file, void *fh, +static int uvc_ioctl_try_fmt(struct file *file, void *priv, struct v4l2_format *fmt) { struct uvc_fh *handle = to_uvc_fh(file); @@ -672,7 +672,7 @@ static int uvc_ioctl_try_fmt(struct file *file, void *fh, return uvc_v4l2_try_format(stream, fmt, &probe, NULL, NULL); } -static int uvc_ioctl_enum_input(struct file *file, void *fh, +static int uvc_ioctl_enum_input(struct file *file, void *priv, struct v4l2_input *input) { struct uvc_fh *handle = to_uvc_fh(file); @@ -715,7 +715,7 @@ static int uvc_ioctl_enum_input(struct file *file, void *fh, return 0; } -static int uvc_ioctl_g_input(struct file *file, void *fh, unsigned int *input) +static int uvc_ioctl_g_input(struct file *file, void *priv, unsigned int *input) { struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; @@ -743,7 +743,7 @@ static int uvc_ioctl_g_input(struct file *file, void *fh, unsigned int *input) return ret; } -static int uvc_ioctl_s_input(struct file *file, void *fh, unsigned int input) +static int uvc_ioctl_s_input(struct file *file, void *priv, unsigned int input) { struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; @@ -777,7 +777,7 @@ static int uvc_ioctl_s_input(struct file *file, void *fh, unsigned int input) return ret; } -static int uvc_ioctl_query_ext_ctrl(struct file *file, void *fh, +static int uvc_ioctl_query_ext_ctrl(struct file *file, void *priv, struct v4l2_query_ext_ctrl *qec) { struct uvc_fh *handle = to_uvc_fh(file); @@ -805,7 +805,7 @@ static int uvc_ctrl_check_access(struct uvc_video_chain *chain, return ret; } -static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh, +static int uvc_ioctl_g_ext_ctrls(struct file *file, void *priv, struct v4l2_ext_controls *ctrls) { struct uvc_fh *handle = to_uvc_fh(file); @@ -889,7 +889,7 @@ static int uvc_ioctl_s_try_ext_ctrls(struct uvc_fh *handle, return uvc_ctrl_rollback(handle); } -static int uvc_ioctl_s_ext_ctrls(struct file *file, void *fh, +static int uvc_ioctl_s_ext_ctrls(struct file *file, void *priv, struct v4l2_ext_controls *ctrls) { struct uvc_fh *handle = to_uvc_fh(file); @@ -897,7 +897,7 @@ static int uvc_ioctl_s_ext_ctrls(struct file *file, void *fh, return uvc_ioctl_s_try_ext_ctrls(handle, ctrls, VIDIOC_S_EXT_CTRLS); } -static int uvc_ioctl_try_ext_ctrls(struct file *file, void *fh, +static int uvc_ioctl_try_ext_ctrls(struct file *file, void *priv, struct v4l2_ext_controls *ctrls) { struct uvc_fh *handle = to_uvc_fh(file); @@ -905,7 +905,7 @@ static int uvc_ioctl_try_ext_ctrls(struct file *file, void *fh, return uvc_ioctl_s_try_ext_ctrls(handle, ctrls, VIDIOC_TRY_EXT_CTRLS); } -static int uvc_ioctl_querymenu(struct file *file, void *fh, +static int uvc_ioctl_querymenu(struct file *file, void *priv, struct v4l2_querymenu *qm) { struct uvc_fh *handle = to_uvc_fh(file); @@ -914,7 +914,7 @@ static int uvc_ioctl_querymenu(struct file *file, void *fh, return uvc_query_v4l2_menu(chain, qm); } -static int uvc_ioctl_g_selection(struct file *file, void *fh, +static int uvc_ioctl_g_selection(struct file *file, void *priv, struct v4l2_selection *sel) { struct uvc_fh *handle = to_uvc_fh(file); @@ -948,7 +948,7 @@ static int uvc_ioctl_g_selection(struct file *file, void *fh, return 0; } -static int uvc_ioctl_enum_framesizes(struct file *file, void *fh, +static int uvc_ioctl_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize) { struct uvc_fh *handle = to_uvc_fh(file); @@ -988,7 +988,7 @@ static int uvc_ioctl_enum_framesizes(struct file *file, void *fh, return 0; } -static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh, +static int uvc_ioctl_enum_frameintervals(struct file *file, void *priv, struct v4l2_frmivalenum *fival) { struct uvc_fh *handle = to_uvc_fh(file); @@ -1060,7 +1060,7 @@ static int uvc_ioctl_subscribe_event(struct v4l2_fh *fh, } } -static long uvc_ioctl_default(struct file *file, void *fh, bool valid_prio, +static long uvc_ioctl_default(struct file *file, void *priv, bool valid_prio, unsigned int cmd, void *arg) { struct uvc_fh *handle = to_uvc_fh(file); From ad46aef5550a7600617aa156d788a01ad5c78b4d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:30:55 +0300 Subject: [PATCH 00573/11391] media: v4l2-pci-skeleton: Rename second ioctl handlers argument to 'void *priv' The second argument to the ioctl handlers is not a file handle any more. Rename it to 'void *priv', to avoid misconceptions. This is particularly important in the v4l2-pci-skeleton driver, as it is meant to be a base for new drivers. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- samples/v4l/v4l2-pci-skeleton.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/samples/v4l/v4l2-pci-skeleton.c b/samples/v4l/v4l2-pci-skeleton.c index d709d82800cd..69925d30329e 100644 --- a/samples/v4l/v4l2-pci-skeleton.c +++ b/samples/v4l/v4l2-pci-skeleton.c @@ -470,7 +470,7 @@ static int skeleton_querystd(struct file *file, void *priv, v4l2_std_id *std) return 0; } -static int skeleton_s_dv_timings(struct file *file, void *_fh, +static int skeleton_s_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct skeleton *skel = video_drvdata(file); @@ -509,7 +509,7 @@ static int skeleton_s_dv_timings(struct file *file, void *_fh, return 0; } -static int skeleton_g_dv_timings(struct file *file, void *_fh, +static int skeleton_g_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct skeleton *skel = video_drvdata(file); @@ -522,7 +522,7 @@ static int skeleton_g_dv_timings(struct file *file, void *_fh, return 0; } -static int skeleton_enum_dv_timings(struct file *file, void *_fh, +static int skeleton_enum_dv_timings(struct file *file, void *priv, struct v4l2_enum_dv_timings *timings) { struct skeleton *skel = video_drvdata(file); @@ -544,7 +544,7 @@ static int skeleton_enum_dv_timings(struct file *file, void *_fh, * can lock but that the DMA engine it is connected to cannot handle * pixelclocks above a certain frequency), then -ERANGE is returned. */ -static int skeleton_query_dv_timings(struct file *file, void *_fh, +static int skeleton_query_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct skeleton *skel = video_drvdata(file); @@ -573,7 +573,7 @@ static int skeleton_query_dv_timings(struct file *file, void *_fh, return 0; } -static int skeleton_dv_timings_cap(struct file *file, void *fh, +static int skeleton_dv_timings_cap(struct file *file, void *priv, struct v4l2_dv_timings_cap *cap) { struct skeleton *skel = video_drvdata(file); From 9d05191c4ed31bb817c03a1b7028ed81fefa8bfb Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:30:56 +0300 Subject: [PATCH 00574/11391] media: v4l2-core: Rename second ioctl handlers argument to 'void *priv' The second argument to the ioctl handlers is not a file handle any more. Rename it from 'void *fh' to 'void *priv' in the V4L2 core, to avoid misconceptions. While at it, align function arguments in include/media/v4l2-mem2mem.h. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/v4l2-core/v4l2-ctrls-api.c | 2 +- drivers/media/v4l2-core/v4l2-mem2mem.c | 6 ++-- include/media/v4l2-ctrls.h | 4 +-- include/media/v4l2-mem2mem.h | 42 ++++++++++++------------ 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-ctrls-api.c b/drivers/media/v4l2-core/v4l2-ctrls-api.c index afb4e5581b90..49a5c7538a09 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-api.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-api.c @@ -1250,7 +1250,7 @@ EXPORT_SYMBOL(v4l2_querymenu); * VIDIOC_LOG_STATUS helpers */ -int v4l2_ctrl_log_status(struct file *file, void *fh) +int v4l2_ctrl_log_status(struct file *file, void *priv) { struct video_device *vfd = video_devdata(file); diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index 7678b8dbedbd..21acd9bc8607 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -1460,7 +1460,7 @@ int v4l2_m2m_ioctl_streamoff(struct file *file, void *priv, } EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_streamoff); -int v4l2_m2m_ioctl_try_encoder_cmd(struct file *file, void *fh, +int v4l2_m2m_ioctl_try_encoder_cmd(struct file *file, void *priv, struct v4l2_encoder_cmd *ec) { if (ec->cmd != V4L2_ENC_CMD_STOP && ec->cmd != V4L2_ENC_CMD_START) @@ -1471,7 +1471,7 @@ int v4l2_m2m_ioctl_try_encoder_cmd(struct file *file, void *fh, } EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_try_encoder_cmd); -int v4l2_m2m_ioctl_try_decoder_cmd(struct file *file, void *fh, +int v4l2_m2m_ioctl_try_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *dc) { if (dc->cmd != V4L2_DEC_CMD_STOP && dc->cmd != V4L2_DEC_CMD_START) @@ -1553,7 +1553,7 @@ int v4l2_m2m_ioctl_decoder_cmd(struct file *file, void *priv, } EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_decoder_cmd); -int v4l2_m2m_ioctl_stateless_try_decoder_cmd(struct file *file, void *fh, +int v4l2_m2m_ioctl_stateless_try_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *dc) { if (dc->cmd != V4L2_DEC_CMD_FLUSH) diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index c32c46286441..4a294a5c7bdd 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -1313,13 +1313,13 @@ void v4l2_ctrl_merge(const struct v4l2_event *old, struct v4l2_event *new); * v4l2_ctrl_log_status - helper function to implement %VIDIOC_LOG_STATUS ioctl * * @file: pointer to struct file - * @fh: unused. Kept just to be compatible to the arguments expected by + * @priv: unused. Kept just to be compatible to the arguments expected by * &struct v4l2_ioctl_ops.vidioc_log_status. * * Can be used as a vidioc_log_status function that just dumps all controls * associated with the filehandle. */ -int v4l2_ctrl_log_status(struct file *file, void *fh); +int v4l2_ctrl_log_status(struct file *file, void *priv); /** * v4l2_ctrl_subscribe_event - Subscribes to an event diff --git a/include/media/v4l2-mem2mem.h b/include/media/v4l2-mem2mem.h index 0af330cf91c3..09c6164577cc 100644 --- a/include/media/v4l2-mem2mem.h +++ b/include/media/v4l2-mem2mem.h @@ -864,34 +864,34 @@ void v4l2_m2m_request_queue(struct media_request *req); /* v4l2 ioctl helpers */ int v4l2_m2m_ioctl_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *rb); -int v4l2_m2m_ioctl_create_bufs(struct file *file, void *fh, - struct v4l2_create_buffers *create); + struct v4l2_requestbuffers *rb); +int v4l2_m2m_ioctl_create_bufs(struct file *file, void *priv, + struct v4l2_create_buffers *create); int v4l2_m2m_ioctl_remove_bufs(struct file *file, void *priv, struct v4l2_remove_buffers *d); -int v4l2_m2m_ioctl_querybuf(struct file *file, void *fh, - struct v4l2_buffer *buf); -int v4l2_m2m_ioctl_expbuf(struct file *file, void *fh, - struct v4l2_exportbuffer *eb); -int v4l2_m2m_ioctl_qbuf(struct file *file, void *fh, - struct v4l2_buffer *buf); -int v4l2_m2m_ioctl_dqbuf(struct file *file, void *fh, - struct v4l2_buffer *buf); -int v4l2_m2m_ioctl_prepare_buf(struct file *file, void *fh, +int v4l2_m2m_ioctl_querybuf(struct file *file, void *priv, + struct v4l2_buffer *buf); +int v4l2_m2m_ioctl_expbuf(struct file *file, void *priv, + struct v4l2_exportbuffer *eb); +int v4l2_m2m_ioctl_qbuf(struct file *file, void *priv, + struct v4l2_buffer *buf); +int v4l2_m2m_ioctl_dqbuf(struct file *file, void *priv, + struct v4l2_buffer *buf); +int v4l2_m2m_ioctl_prepare_buf(struct file *file, void *priv, struct v4l2_buffer *buf); -int v4l2_m2m_ioctl_streamon(struct file *file, void *fh, - enum v4l2_buf_type type); -int v4l2_m2m_ioctl_streamoff(struct file *file, void *fh, - enum v4l2_buf_type type); -int v4l2_m2m_ioctl_encoder_cmd(struct file *file, void *fh, +int v4l2_m2m_ioctl_streamon(struct file *file, void *priv, + enum v4l2_buf_type type); +int v4l2_m2m_ioctl_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type); +int v4l2_m2m_ioctl_encoder_cmd(struct file *file, void *priv, struct v4l2_encoder_cmd *ec); -int v4l2_m2m_ioctl_decoder_cmd(struct file *file, void *fh, +int v4l2_m2m_ioctl_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *dc); -int v4l2_m2m_ioctl_try_encoder_cmd(struct file *file, void *fh, +int v4l2_m2m_ioctl_try_encoder_cmd(struct file *file, void *priv, struct v4l2_encoder_cmd *ec); -int v4l2_m2m_ioctl_try_decoder_cmd(struct file *file, void *fh, +int v4l2_m2m_ioctl_try_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *dc); -int v4l2_m2m_ioctl_stateless_try_decoder_cmd(struct file *file, void *fh, +int v4l2_m2m_ioctl_stateless_try_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *dc); int v4l2_m2m_ioctl_stateless_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *dc); From 5396f5ae0e7b210ee5098c257ccb1c3fdd4bd04f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:30:57 +0300 Subject: [PATCH 00575/11391] media: v4l2: Rename second ioctl handlers argument to 'void *priv' The second argument to the ioctl handlers is not a file handle any more. The standard practice is to name it 'void *priv' in drivers. Many drivers still name it 'void *fh', and a few use more exotic names. Replace those more exotic names with 'void *priv' in all media drivers. Signed-off-by: Laurent Pinchart Acked-by: Jai Luthra Signed-off-by: Hans Verkuil --- .../extron-da-hd-4k-plus.c | 4 +- drivers/media/pci/bt8xx/bttv-driver.c | 14 ++--- drivers/media/pci/bt8xx/bttv-vbi.c | 6 +- drivers/media/pci/cobalt/cobalt-v4l2.c | 60 +++++++++---------- drivers/media/pci/saa7134/saa7134-video.c | 4 +- drivers/media/platform/rockchip/rga/rga.c | 14 ++--- drivers/media/platform/samsung/s5p-g2d/g2d.c | 18 +++--- .../platform/samsung/s5p-mfc/s5p_mfc_dec.c | 2 +- .../platform/samsung/s5p-mfc/s5p_mfc_enc.c | 2 +- drivers/media/platform/st/stm32/dma2d/dma2d.c | 10 ++-- .../sunxi/sun6i-csi/sun6i_csi_capture.c | 16 ++--- .../platform/synopsys/hdmirx/snps_hdmirx.c | 8 +-- .../platform/ti/j721e-csi2rx/j721e-csi2rx.c | 2 +- drivers/media/platform/ti/omap/omap_vout.c | 6 +- .../radio/si4713/radio-platform-si4713.c | 10 ++-- drivers/media/usb/cx231xx/cx231xx-417.c | 2 +- drivers/media/usb/gspca/gspca.c | 18 +++--- drivers/media/usb/hdpvr/hdpvr-video.c | 30 +++++----- 18 files changed, 113 insertions(+), 113 deletions(-) diff --git a/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c b/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c index 41d019b01ec0..c476e8d1279e 100644 --- a/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c +++ b/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c @@ -1252,7 +1252,7 @@ static int extron_s_output(struct file *file, void *priv, unsigned int o) return o ? -EINVAL : 0; } -static int extron_g_edid(struct file *file, void *_fh, +static int extron_g_edid(struct file *file, void *priv, struct v4l2_edid *edid) { struct extron_port *port = video_drvdata(file); @@ -1280,7 +1280,7 @@ static int extron_g_edid(struct file *file, void *_fh, return 0; } -static int extron_s_edid(struct file *file, void *_fh, struct v4l2_edid *edid) +static int extron_s_edid(struct file *file, void *priv, struct v4l2_edid *edid) { struct extron_port *port = video_drvdata(file); diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 9ce67f515843..17e4529e537a 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -1620,7 +1620,7 @@ static int bttv_g_std(struct file *file, void *priv, v4l2_std_id *id) return 0; } -static int bttv_querystd(struct file *file, void *f, v4l2_std_id *id) +static int bttv_querystd(struct file *file, void *priv, v4l2_std_id *id) { struct bttv *btv = video_drvdata(file); @@ -1750,7 +1750,7 @@ static int bttv_s_frequency(struct file *file, void *priv, return 0; } -static int bttv_log_status(struct file *file, void *f) +static int bttv_log_status(struct file *file, void *priv) { struct video_device *vdev = video_devdata(file); struct bttv *btv = video_drvdata(file); @@ -1761,7 +1761,7 @@ static int bttv_log_status(struct file *file, void *f) } #ifdef CONFIG_VIDEO_ADV_DEBUG -static int bttv_g_register(struct file *file, void *f, +static int bttv_g_register(struct file *file, void *priv, struct v4l2_dbg_register *reg) { struct bttv *btv = video_drvdata(file); @@ -1774,7 +1774,7 @@ static int bttv_g_register(struct file *file, void *f, return 0; } -static int bttv_s_register(struct file *file, void *f, +static int bttv_s_register(struct file *file, void *priv, const struct v4l2_dbg_register *reg) { struct bttv *btv = video_drvdata(file); @@ -2159,7 +2159,7 @@ static int bttv_enum_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int bttv_g_parm(struct file *file, void *f, +static int bttv_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm) { struct bttv *btv = video_drvdata(file); @@ -2208,7 +2208,7 @@ static int bttv_g_pixelaspect(struct file *file, void *priv, return 0; } -static int bttv_g_selection(struct file *file, void *f, struct v4l2_selection *sel) +static int bttv_g_selection(struct file *file, void *priv, struct v4l2_selection *sel) { struct bttv *btv = video_drvdata(file); @@ -2232,7 +2232,7 @@ static int bttv_g_selection(struct file *file, void *f, struct v4l2_selection *s return 0; } -static int bttv_s_selection(struct file *file, void *f, struct v4l2_selection *sel) +static int bttv_s_selection(struct file *file, void *priv, struct v4l2_selection *sel) { struct bttv *btv = video_drvdata(file); const struct v4l2_rect *b; diff --git a/drivers/media/pci/bt8xx/bttv-vbi.c b/drivers/media/pci/bt8xx/bttv-vbi.c index a71440611e46..0ca88a2400ee 100644 --- a/drivers/media/pci/bt8xx/bttv-vbi.c +++ b/drivers/media/pci/bt8xx/bttv-vbi.c @@ -241,7 +241,7 @@ static int try_fmt(struct v4l2_vbi_format *f, const struct bttv_tvnorm *tvnorm, return 0; } -int bttv_try_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt) +int bttv_try_fmt_vbi_cap(struct file *file, void *priv, struct v4l2_format *frt) { struct bttv *btv = video_drvdata(file); const struct bttv_tvnorm *tvnorm; @@ -258,7 +258,7 @@ int bttv_try_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt) } -int bttv_s_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt) +int bttv_s_fmt_vbi_cap(struct file *file, void *priv, struct v4l2_format *frt) { struct bttv *btv = video_drvdata(file); const struct bttv_tvnorm *tvnorm; @@ -301,7 +301,7 @@ int bttv_s_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt) } -int bttv_g_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt) +int bttv_g_fmt_vbi_cap(struct file *file, void *priv, struct v4l2_format *frt) { const struct bttv_tvnorm *tvnorm; struct bttv *btv = video_drvdata(file); diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c index ae82427e3479..51fd9576c6c2 100644 --- a/drivers/media/pci/cobalt/cobalt-v4l2.c +++ b/drivers/media/pci/cobalt/cobalt-v4l2.c @@ -447,7 +447,7 @@ static int cobalt_cobaltc(struct cobalt *cobalt, unsigned int cmd, void *arg) return 0; } -static int cobalt_g_register(struct file *file, void *priv_fh, +static int cobalt_g_register(struct file *file, void *priv, struct v4l2_dbg_register *reg) { struct cobalt_stream *s = video_drvdata(file); @@ -456,7 +456,7 @@ static int cobalt_g_register(struct file *file, void *priv_fh, return cobalt_cobaltc(cobalt, VIDIOC_DBG_G_REGISTER, reg); } -static int cobalt_s_register(struct file *file, void *priv_fh, +static int cobalt_s_register(struct file *file, void *priv, const struct v4l2_dbg_register *reg) { struct cobalt_stream *s = video_drvdata(file); @@ -467,7 +467,7 @@ static int cobalt_s_register(struct file *file, void *priv_fh, } #endif -static int cobalt_querycap(struct file *file, void *priv_fh, +static int cobalt_querycap(struct file *file, void *priv, struct v4l2_capability *vcap) { struct cobalt_stream *s = video_drvdata(file); @@ -562,7 +562,7 @@ static void cobalt_video_input_status_show(struct cobalt_stream *s) cobalt_info("rx%d: Packer: %x\n", rx, ioread32(&packer->control)); } -static int cobalt_log_status(struct file *file, void *priv_fh) +static int cobalt_log_status(struct file *file, void *priv) { struct cobalt_stream *s = video_drvdata(file); struct cobalt *cobalt = s->cobalt; @@ -596,7 +596,7 @@ static int cobalt_log_status(struct file *file, void *priv_fh) return 0; } -static int cobalt_enum_dv_timings(struct file *file, void *priv_fh, +static int cobalt_enum_dv_timings(struct file *file, void *priv, struct v4l2_enum_dv_timings *timings) { struct cobalt_stream *s = video_drvdata(file); @@ -613,7 +613,7 @@ static int cobalt_enum_dv_timings(struct file *file, void *priv_fh, pad, enum_dv_timings, timings); } -static int cobalt_s_dv_timings(struct file *file, void *priv_fh, +static int cobalt_s_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct cobalt_stream *s = video_drvdata(file); @@ -641,7 +641,7 @@ static int cobalt_s_dv_timings(struct file *file, void *priv_fh, return err; } -static int cobalt_g_dv_timings(struct file *file, void *priv_fh, +static int cobalt_g_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct cobalt_stream *s = video_drvdata(file); @@ -654,7 +654,7 @@ static int cobalt_g_dv_timings(struct file *file, void *priv_fh, pad, g_dv_timings, 0, timings); } -static int cobalt_query_dv_timings(struct file *file, void *priv_fh, +static int cobalt_query_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct cobalt_stream *s = video_drvdata(file); @@ -667,7 +667,7 @@ static int cobalt_query_dv_timings(struct file *file, void *priv_fh, pad, query_dv_timings, 0, timings); } -static int cobalt_dv_timings_cap(struct file *file, void *priv_fh, +static int cobalt_dv_timings_cap(struct file *file, void *priv, struct v4l2_dv_timings_cap *cap) { struct cobalt_stream *s = video_drvdata(file); @@ -677,7 +677,7 @@ static int cobalt_dv_timings_cap(struct file *file, void *priv_fh, pad, dv_timings_cap, cap); } -static int cobalt_enum_fmt_vid_cap(struct file *file, void *priv_fh, +static int cobalt_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { switch (f->index) { @@ -697,7 +697,7 @@ static int cobalt_enum_fmt_vid_cap(struct file *file, void *priv_fh, return 0; } -static int cobalt_g_fmt_vid_cap(struct file *file, void *priv_fh, +static int cobalt_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cobalt_stream *s = video_drvdata(file); @@ -726,7 +726,7 @@ static int cobalt_g_fmt_vid_cap(struct file *file, void *priv_fh, return 0; } -static int cobalt_try_fmt_vid_cap(struct file *file, void *priv_fh, +static int cobalt_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cobalt_stream *s = video_drvdata(file); @@ -787,7 +787,7 @@ static int cobalt_try_fmt_vid_cap(struct file *file, void *priv_fh, return 0; } -static int cobalt_s_fmt_vid_cap(struct file *file, void *priv_fh, +static int cobalt_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cobalt_stream *s = video_drvdata(file); @@ -796,7 +796,7 @@ static int cobalt_s_fmt_vid_cap(struct file *file, void *priv_fh, if (vb2_is_busy(&s->q)) return -EBUSY; - if (cobalt_try_fmt_vid_cap(file, priv_fh, f)) + if (cobalt_try_fmt_vid_cap(file, priv, f)) return -EINVAL; s->width = pix->width; @@ -821,7 +821,7 @@ static int cobalt_s_fmt_vid_cap(struct file *file, void *priv_fh, return 0; } -static int cobalt_try_fmt_vid_out(struct file *file, void *priv_fh, +static int cobalt_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format *pix = &f->fmt.pix; @@ -862,7 +862,7 @@ static int cobalt_try_fmt_vid_out(struct file *file, void *priv_fh, return 0; } -static int cobalt_g_fmt_vid_out(struct file *file, void *priv_fh, +static int cobalt_g_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { struct cobalt_stream *s = video_drvdata(file); @@ -882,7 +882,7 @@ static int cobalt_g_fmt_vid_out(struct file *file, void *priv_fh, return 0; } -static int cobalt_enum_fmt_vid_out(struct file *file, void *priv_fh, +static int cobalt_enum_fmt_vid_out(struct file *file, void *priv, struct v4l2_fmtdesc *f) { switch (f->index) { @@ -899,7 +899,7 @@ static int cobalt_enum_fmt_vid_out(struct file *file, void *priv_fh, return 0; } -static int cobalt_s_fmt_vid_out(struct file *file, void *priv_fh, +static int cobalt_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { struct cobalt_stream *s = video_drvdata(file); @@ -909,7 +909,7 @@ static int cobalt_s_fmt_vid_out(struct file *file, void *priv_fh, }; u32 code; - if (cobalt_try_fmt_vid_out(file, priv_fh, f)) + if (cobalt_try_fmt_vid_out(file, priv, f)) return -EINVAL; if (vb2_is_busy(&s->q) && (pix->pixelformat != s->pixfmt || @@ -942,7 +942,7 @@ static int cobalt_s_fmt_vid_out(struct file *file, void *priv_fh, return 0; } -static int cobalt_enum_input(struct file *file, void *priv_fh, +static int cobalt_enum_input(struct file *file, void *priv, struct v4l2_input *inp) { struct cobalt_stream *s = video_drvdata(file); @@ -963,7 +963,7 @@ static int cobalt_enum_input(struct file *file, void *priv_fh, video, g_input_status, &inp->status); } -static int cobalt_g_input(struct file *file, void *priv_fh, unsigned int *i) +static int cobalt_g_input(struct file *file, void *priv, unsigned int *i) { struct cobalt_stream *s = video_drvdata(file); @@ -971,7 +971,7 @@ static int cobalt_g_input(struct file *file, void *priv_fh, unsigned int *i) return 0; } -static int cobalt_s_input(struct file *file, void *priv_fh, unsigned int i) +static int cobalt_s_input(struct file *file, void *priv, unsigned int i) { struct cobalt_stream *s = video_drvdata(file); @@ -990,7 +990,7 @@ static int cobalt_s_input(struct file *file, void *priv_fh, unsigned int i) ADV76XX_PAD_HDMI_PORT_A, 0, 0); } -static int cobalt_enum_output(struct file *file, void *priv_fh, +static int cobalt_enum_output(struct file *file, void *priv, struct v4l2_output *out) { if (out->index) @@ -1001,18 +1001,18 @@ static int cobalt_enum_output(struct file *file, void *priv_fh, return 0; } -static int cobalt_g_output(struct file *file, void *priv_fh, unsigned int *i) +static int cobalt_g_output(struct file *file, void *priv, unsigned int *i) { *i = 0; return 0; } -static int cobalt_s_output(struct file *file, void *priv_fh, unsigned int i) +static int cobalt_s_output(struct file *file, void *priv, unsigned int i) { return i ? -EINVAL : 0; } -static int cobalt_g_edid(struct file *file, void *fh, struct v4l2_edid *edid) +static int cobalt_g_edid(struct file *file, void *priv, struct v4l2_edid *edid) { struct cobalt_stream *s = video_drvdata(file); u32 pad = edid->pad; @@ -1026,7 +1026,7 @@ static int cobalt_g_edid(struct file *file, void *fh, struct v4l2_edid *edid) return ret; } -static int cobalt_s_edid(struct file *file, void *fh, struct v4l2_edid *edid) +static int cobalt_s_edid(struct file *file, void *priv, struct v4l2_edid *edid) { struct cobalt_stream *s = video_drvdata(file); u32 pad = edid->pad; @@ -1050,7 +1050,7 @@ static int cobalt_subscribe_event(struct v4l2_fh *fh, return v4l2_ctrl_subscribe_event(fh, sub); } -static int cobalt_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +static int cobalt_g_parm(struct file *file, void *priv, struct v4l2_streamparm *a) { struct cobalt_stream *s = video_drvdata(file); struct v4l2_fract fps; @@ -1065,7 +1065,7 @@ static int cobalt_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) return 0; } -static int cobalt_g_pixelaspect(struct file *file, void *fh, +static int cobalt_g_pixelaspect(struct file *file, void *priv, int type, struct v4l2_fract *f) { struct cobalt_stream *s = video_drvdata(file); @@ -1084,7 +1084,7 @@ static int cobalt_g_pixelaspect(struct file *file, void *fh, return err; } -static int cobalt_g_selection(struct file *file, void *fh, +static int cobalt_g_selection(struct file *file, void *priv, struct v4l2_selection *sel) { struct cobalt_stream *s = video_drvdata(file); diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index c88939bce56b..4a51b873e47a 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -1302,7 +1302,7 @@ static int saa7134_g_pixelaspect(struct file *file, void *priv, return 0; } -static int saa7134_g_selection(struct file *file, void *f, struct v4l2_selection *sel) +static int saa7134_g_selection(struct file *file, void *priv, struct v4l2_selection *sel) { struct saa7134_dev *dev = video_drvdata(file); @@ -1325,7 +1325,7 @@ static int saa7134_g_selection(struct file *file, void *f, struct v4l2_selection return 0; } -static int saa7134_s_selection(struct file *file, void *f, struct v4l2_selection *sel) +static int saa7134_s_selection(struct file *file, void *priv, struct v4l2_selection *sel) { struct saa7134_dev *dev = video_drvdata(file); struct v4l2_rect *b = &dev->crop_bounds; diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index 7c657df623f2..776046de979a 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -446,7 +446,7 @@ vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) return 0; } -static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f) +static int vidioc_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f) { struct rga_fmt *fmt; @@ -459,7 +459,7 @@ static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f) return 0; } -static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) +static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp; struct rga_ctx *ctx = file_to_rga_ctx(file); @@ -481,7 +481,7 @@ static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) return 0; } -static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f) +static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp; struct rga_fmt *fmt; @@ -501,7 +501,7 @@ static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f) return 0; } -static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) +static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp; struct rga_ctx *ctx = file_to_rga_ctx(file); @@ -514,7 +514,7 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) /* Adjust all values accordingly to the hardware capabilities * and chosen format. */ - ret = vidioc_try_fmt(file, prv, f); + ret = vidioc_try_fmt(file, priv, f); if (ret) return ret; vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); @@ -558,7 +558,7 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) return 0; } -static int vidioc_g_selection(struct file *file, void *prv, +static int vidioc_g_selection(struct file *file, void *priv, struct v4l2_selection *s) { struct rga_ctx *ctx = file_to_rga_ctx(file); @@ -606,7 +606,7 @@ static int vidioc_g_selection(struct file *file, void *prv, return 0; } -static int vidioc_s_selection(struct file *file, void *prv, +static int vidioc_s_selection(struct file *file, void *priv, struct v4l2_selection *s) { struct rga_ctx *ctx = file_to_rga_ctx(file); diff --git a/drivers/media/platform/samsung/s5p-g2d/g2d.c b/drivers/media/platform/samsung/s5p-g2d/g2d.c index 55f5130156b7..ffb9bee6cb9d 100644 --- a/drivers/media/platform/samsung/s5p-g2d/g2d.c +++ b/drivers/media/platform/samsung/s5p-g2d/g2d.c @@ -297,7 +297,7 @@ static int vidioc_querycap(struct file *file, void *priv, return 0; } -static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f) +static int vidioc_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (f->index >= NUM_FORMATS) return -EINVAL; @@ -305,7 +305,7 @@ static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f) return 0; } -static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) +static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct g2d_ctx *ctx = file2ctx(file); struct vb2_queue *vq; @@ -327,7 +327,7 @@ static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) return 0; } -static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f) +static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct g2d_fmt *fmt; enum v4l2_field *field; @@ -357,7 +357,7 @@ static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f) return 0; } -static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) +static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct g2d_ctx *ctx = file2ctx(file); struct g2d_dev *dev = ctx->dev; @@ -368,7 +368,7 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) /* Adjust all values accordingly to the hardware capabilities * and chosen format. */ - ret = vidioc_try_fmt(file, prv, f); + ret = vidioc_try_fmt(file, priv, f); if (ret) return ret; vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); @@ -397,7 +397,7 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) return 0; } -static int vidioc_g_selection(struct file *file, void *prv, +static int vidioc_g_selection(struct file *file, void *priv, struct v4l2_selection *s) { struct g2d_ctx *ctx = file2ctx(file); @@ -447,7 +447,7 @@ static int vidioc_g_selection(struct file *file, void *prv, return 0; } -static int vidioc_try_selection(struct file *file, void *prv, +static int vidioc_try_selection(struct file *file, void *priv, const struct v4l2_selection *s) { struct g2d_ctx *ctx = file2ctx(file); @@ -475,14 +475,14 @@ static int vidioc_try_selection(struct file *file, void *prv, return 0; } -static int vidioc_s_selection(struct file *file, void *prv, +static int vidioc_s_selection(struct file *file, void *priv, struct v4l2_selection *s) { struct g2d_ctx *ctx = file2ctx(file); struct g2d_frame *f; int ret; - ret = vidioc_try_selection(file, prv, s); + ret = vidioc_try_selection(file, priv, s); if (ret) return ret; f = get_frame(ctx, s->type); diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c index 606e1a7121b5..afd28beabfde 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c @@ -330,7 +330,7 @@ static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f, return 0; } -static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv, +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { return vidioc_enum_fmt(file, f, false); diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c index 694b68788a95..3f8701e5614f 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c @@ -1375,7 +1375,7 @@ static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f, return -EINVAL; } -static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv, +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { return vidioc_enum_fmt(file, f, false); diff --git a/drivers/media/platform/st/stm32/dma2d/dma2d.c b/drivers/media/platform/st/stm32/dma2d/dma2d.c index a22f587a5f83..468c247ba328 100644 --- a/drivers/media/platform/st/stm32/dma2d/dma2d.c +++ b/drivers/media/platform/st/stm32/dma2d/dma2d.c @@ -343,7 +343,7 @@ static int vidioc_querycap(struct file *file, void *priv, return 0; } -static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f) +static int vidioc_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (f->index >= NUM_FORMATS) return -EINVAL; @@ -352,7 +352,7 @@ static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f) return 0; } -static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) +static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct dma2d_ctx *ctx = file2ctx(file); struct vb2_queue *vq; @@ -377,7 +377,7 @@ static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) return 0; } -static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f) +static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct dma2d_ctx *ctx = file2ctx(file); struct dma2d_fmt *fmt; @@ -420,7 +420,7 @@ static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f) return 0; } -static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) +static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct dma2d_ctx *ctx = file2ctx(file); struct vb2_queue *vq; @@ -431,7 +431,7 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) /* Adjust all values accordingly to the hardware capabilities * and chosen format. */ - ret = vidioc_try_fmt(file, prv, f); + ret = vidioc_try_fmt(file, priv, f); if (ret) return ret; diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c index 76356bc7f10e..65879f4802c0 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c @@ -711,7 +711,7 @@ static void sun6i_csi_capture_format_prepare(struct v4l2_format *format) pix_format->xfer_func = V4L2_XFER_FUNC_DEFAULT; } -static int sun6i_csi_capture_querycap(struct file *file, void *private, +static int sun6i_csi_capture_querycap(struct file *file, void *priv, struct v4l2_capability *capability) { struct sun6i_csi_device *csi_dev = video_drvdata(file); @@ -725,7 +725,7 @@ static int sun6i_csi_capture_querycap(struct file *file, void *private, return 0; } -static int sun6i_csi_capture_enum_fmt(struct file *file, void *private, +static int sun6i_csi_capture_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *fmtdesc) { u32 index = fmtdesc->index; @@ -738,7 +738,7 @@ static int sun6i_csi_capture_enum_fmt(struct file *file, void *private, return 0; } -static int sun6i_csi_capture_g_fmt(struct file *file, void *private, +static int sun6i_csi_capture_g_fmt(struct file *file, void *priv, struct v4l2_format *format) { struct sun6i_csi_device *csi_dev = video_drvdata(file); @@ -748,7 +748,7 @@ static int sun6i_csi_capture_g_fmt(struct file *file, void *private, return 0; } -static int sun6i_csi_capture_s_fmt(struct file *file, void *private, +static int sun6i_csi_capture_s_fmt(struct file *file, void *priv, struct v4l2_format *format) { struct sun6i_csi_device *csi_dev = video_drvdata(file); @@ -764,7 +764,7 @@ static int sun6i_csi_capture_s_fmt(struct file *file, void *private, return 0; } -static int sun6i_csi_capture_try_fmt(struct file *file, void *private, +static int sun6i_csi_capture_try_fmt(struct file *file, void *priv, struct v4l2_format *format) { sun6i_csi_capture_format_prepare(format); @@ -772,7 +772,7 @@ static int sun6i_csi_capture_try_fmt(struct file *file, void *private, return 0; } -static int sun6i_csi_capture_enum_input(struct file *file, void *private, +static int sun6i_csi_capture_enum_input(struct file *file, void *priv, struct v4l2_input *input) { if (input->index != 0) @@ -784,7 +784,7 @@ static int sun6i_csi_capture_enum_input(struct file *file, void *private, return 0; } -static int sun6i_csi_capture_g_input(struct file *file, void *private, +static int sun6i_csi_capture_g_input(struct file *file, void *priv, unsigned int *index) { *index = 0; @@ -792,7 +792,7 @@ static int sun6i_csi_capture_g_input(struct file *file, void *private, return 0; } -static int sun6i_csi_capture_s_input(struct file *file, void *private, +static int sun6i_csi_capture_s_input(struct file *file, void *priv, unsigned int index) { if (index != 0) diff --git a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c index 7af6765532e3..b7d278b3889f 100644 --- a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c +++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c @@ -459,7 +459,7 @@ static bool port_no_link(struct snps_hdmirx_dev *hdmirx_dev) return !tx_5v_power_present(hdmirx_dev); } -static int hdmirx_query_dv_timings(struct file *file, void *_fh, +static int hdmirx_query_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct hdmirx_stream *stream = video_drvdata(file); @@ -751,7 +751,7 @@ static int hdmirx_dv_timings_cap(struct file *file, void *fh, return 0; } -static int hdmirx_enum_dv_timings(struct file *file, void *_fh, +static int hdmirx_enum_dv_timings(struct file *file, void *priv, struct v4l2_enum_dv_timings *timings) { return v4l2_enum_dv_timings_cap(timings, &hdmirx_timings_cap, NULL, NULL); @@ -1323,7 +1323,7 @@ static int hdmirx_g_fmt_vid_cap_mplane(struct file *file, void *fh, return 0; } -static int hdmirx_g_dv_timings(struct file *file, void *_fh, +static int hdmirx_g_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct hdmirx_stream *stream = video_drvdata(file); @@ -1339,7 +1339,7 @@ static int hdmirx_g_dv_timings(struct file *file, void *_fh, return 0; } -static int hdmirx_s_dv_timings(struct file *file, void *_fh, +static int hdmirx_s_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct hdmirx_stream *stream = video_drvdata(file); diff --git a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c index b628d6e081db..7fb565ebbe62 100644 --- a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c +++ b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c @@ -299,7 +299,7 @@ static int ti_csi2rx_enum_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int ti_csi2rx_g_fmt_vid_cap(struct file *file, void *prov, +static int ti_csi2rx_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct ti_csi2rx_dev *csi = video_drvdata(file); diff --git a/drivers/media/platform/ti/omap/omap_vout.c b/drivers/media/platform/ti/omap/omap_vout.c index a87d5030ac35..22782e9f1f4e 100644 --- a/drivers/media/platform/ti/omap/omap_vout.c +++ b/drivers/media/platform/ti/omap/omap_vout.c @@ -1236,7 +1236,7 @@ static int vidioc_g_fbuf(struct file *file, void *fh, return 0; } -static int vidioc_enum_output(struct file *file, void *priv_fh, +static int vidioc_enum_output(struct file *file, void *priv, struct v4l2_output *out) { if (out->index) @@ -1246,13 +1246,13 @@ static int vidioc_enum_output(struct file *file, void *priv_fh, return 0; } -static int vidioc_g_output(struct file *file, void *priv_fh, unsigned int *i) +static int vidioc_g_output(struct file *file, void *priv, unsigned int *i) { *i = 0; return 0; } -static int vidioc_s_output(struct file *file, void *priv_fh, unsigned int i) +static int vidioc_s_output(struct file *file, void *priv, unsigned int i) { return i ? -EINVAL : 0; } diff --git a/drivers/media/radio/si4713/radio-platform-si4713.c b/drivers/media/radio/si4713/radio-platform-si4713.c index 67b4afadc95a..4132968110e3 100644 --- a/drivers/media/radio/si4713/radio-platform-si4713.c +++ b/drivers/media/radio/si4713/radio-platform-si4713.c @@ -75,35 +75,35 @@ static inline struct v4l2_device *get_v4l2_dev(struct file *file) return &((struct radio_si4713_device *)video_drvdata(file))->v4l2_dev; } -static int radio_si4713_g_modulator(struct file *file, void *p, +static int radio_si4713_g_modulator(struct file *file, void *priv, struct v4l2_modulator *vm) { return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner, g_modulator, vm); } -static int radio_si4713_s_modulator(struct file *file, void *p, +static int radio_si4713_s_modulator(struct file *file, void *priv, const struct v4l2_modulator *vm) { return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner, s_modulator, vm); } -static int radio_si4713_g_frequency(struct file *file, void *p, +static int radio_si4713_g_frequency(struct file *file, void *priv, struct v4l2_frequency *vf) { return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner, g_frequency, vf); } -static int radio_si4713_s_frequency(struct file *file, void *p, +static int radio_si4713_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *vf) { return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner, s_frequency, vf); } -static long radio_si4713_default(struct file *file, void *p, +static long radio_si4713_default(struct file *file, void *priv, bool valid_prio, unsigned int cmd, void *arg) { return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core, diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index e585c8f6e4c5..c695a97e202b 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -1499,7 +1499,7 @@ static int vidioc_g_selection(struct file *file, void *priv, return 0; } -static int vidioc_g_std(struct file *file, void *fh0, v4l2_std_id *norm) +static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm) { struct cx231xx *dev = video_drvdata(file); diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index 25edd2189654..3fc15d16df8e 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -1029,15 +1029,15 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int vidioc_g_fmt_vid_cap(struct file *file, void *_priv, +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *fmt) { struct gspca_dev *gspca_dev = video_drvdata(file); - u32 priv = fmt->fmt.pix.priv; + u32 fmt_priv = fmt->fmt.pix.priv; fmt->fmt.pix = gspca_dev->pixfmt; /* some drivers use priv internally, so keep the original value */ - fmt->fmt.pix.priv = priv; + fmt->fmt.pix.priv = fmt_priv; return 0; } @@ -1075,24 +1075,24 @@ static int try_fmt_vid_cap(struct gspca_dev *gspca_dev, return mode; /* used when s_fmt */ } -static int vidioc_try_fmt_vid_cap(struct file *file, void *_priv, +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *fmt) { struct gspca_dev *gspca_dev = video_drvdata(file); - u32 priv = fmt->fmt.pix.priv; + u32 fmt_priv = fmt->fmt.pix.priv; if (try_fmt_vid_cap(gspca_dev, fmt) < 0) return -EINVAL; /* some drivers use priv internally, so keep the original value */ - fmt->fmt.pix.priv = priv; + fmt->fmt.pix.priv = fmt_priv; return 0; } -static int vidioc_s_fmt_vid_cap(struct file *file, void *_priv, +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *fmt) { struct gspca_dev *gspca_dev = video_drvdata(file); - u32 priv = fmt->fmt.pix.priv; + u32 fmt_priv = fmt->fmt.pix.priv; int mode; if (vb2_is_busy(&gspca_dev->queue)) @@ -1109,7 +1109,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *_priv, else gspca_dev->pixfmt = gspca_dev->cam.cam_mode[mode]; /* some drivers use priv internally, so keep the original value */ - fmt->fmt.pix.priv = priv; + fmt->fmt.pix.priv = fmt_priv; return 0; } diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index 8a5c2c5227eb..8c7ae362d992 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -590,7 +590,7 @@ static int vidioc_querycap(struct file *file, void *priv, return 0; } -static int vidioc_s_std(struct file *file, void *_fh, +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id std) { struct hdpvr_device *dev = video_drvdata(file); @@ -610,7 +610,7 @@ static int vidioc_s_std(struct file *file, void *_fh, return hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, std_type); } -static int vidioc_g_std(struct file *file, void *_fh, +static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std) { struct hdpvr_device *dev = video_drvdata(file); @@ -623,7 +623,7 @@ static int vidioc_g_std(struct file *file, void *_fh, return 0; } -static int vidioc_querystd(struct file *file, void *_fh, v4l2_std_id *a) +static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *a) { struct hdpvr_device *dev = video_drvdata(file); struct hdpvr_fh *fh = file_to_hdpvr_fh(file); @@ -642,7 +642,7 @@ static int vidioc_querystd(struct file *file, void *_fh, v4l2_std_id *a) return ret; } -static int vidioc_s_dv_timings(struct file *file, void *_fh, +static int vidioc_s_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct hdpvr_device *dev = video_drvdata(file); @@ -665,7 +665,7 @@ static int vidioc_s_dv_timings(struct file *file, void *_fh, return 0; } -static int vidioc_g_dv_timings(struct file *file, void *_fh, +static int vidioc_g_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct hdpvr_device *dev = video_drvdata(file); @@ -678,7 +678,7 @@ static int vidioc_g_dv_timings(struct file *file, void *_fh, return 0; } -static int vidioc_query_dv_timings(struct file *file, void *_fh, +static int vidioc_query_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct hdpvr_device *dev = video_drvdata(file); @@ -720,7 +720,7 @@ static int vidioc_query_dv_timings(struct file *file, void *_fh, return ret; } -static int vidioc_enum_dv_timings(struct file *file, void *_fh, +static int vidioc_enum_dv_timings(struct file *file, void *priv, struct v4l2_enum_dv_timings *timings) { struct hdpvr_device *dev = video_drvdata(file); @@ -736,7 +736,7 @@ static int vidioc_enum_dv_timings(struct file *file, void *_fh, return 0; } -static int vidioc_dv_timings_cap(struct file *file, void *_fh, +static int vidioc_dv_timings_cap(struct file *file, void *priv, struct v4l2_dv_timings_cap *cap) { struct hdpvr_device *dev = video_drvdata(file); @@ -763,7 +763,7 @@ static const char *iname[] = { [HDPVR_COMPOSITE] = "Composite", }; -static int vidioc_enum_input(struct file *file, void *_fh, struct v4l2_input *i) +static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *i) { unsigned int n; @@ -783,7 +783,7 @@ static int vidioc_enum_input(struct file *file, void *_fh, struct v4l2_input *i) return 0; } -static int vidioc_s_input(struct file *file, void *_fh, +static int vidioc_s_input(struct file *file, void *priv, unsigned int index) { struct hdpvr_device *dev = video_drvdata(file); @@ -817,7 +817,7 @@ static int vidioc_s_input(struct file *file, void *_fh, return retval; } -static int vidioc_g_input(struct file *file, void *private_data, +static int vidioc_g_input(struct file *file, void *priv, unsigned int *index) { struct hdpvr_device *dev = video_drvdata(file); @@ -849,7 +849,7 @@ static int vidioc_enumaudio(struct file *file, void *priv, return 0; } -static int vidioc_s_audio(struct file *file, void *private_data, +static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio *audio) { struct hdpvr_device *dev = video_drvdata(file); @@ -868,7 +868,7 @@ static int vidioc_s_audio(struct file *file, void *private_data, return retval; } -static int vidioc_g_audio(struct file *file, void *private_data, +static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *audio) { struct hdpvr_device *dev = video_drvdata(file); @@ -985,7 +985,7 @@ static int hdpvr_s_ctrl(struct v4l2_ctrl *ctrl) return ret; } -static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data, +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (f->index != 0) @@ -996,7 +996,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data, return 0; } -static int vidioc_g_fmt_vid_cap(struct file *file, void *_fh, +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct hdpvr_device *dev = video_drvdata(file); From 078f1a7eb48eef9b3cb78bcd2254356f3a332358 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Aug 2025 04:30:58 +0300 Subject: [PATCH 00576/11391] media: staging: Rename second ioctl handlers argument to 'void *priv' The second argument to the ioctl handlers is not a file handle any more. The standard practice is to name it 'void *priv' in drivers. Many drivers still name it 'void *fh', and a few use more exotic names. Replace those more exotic names with 'void *priv' in all media staging drivers. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- .../media/sunxi/sun6i-isp/sun6i_isp_capture.c | 16 ++++++++-------- .../media/sunxi/sun6i-isp/sun6i_isp_params.c | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_capture.c b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_capture.c index 24899f41dc1c..e7b99cee63d6 100644 --- a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_capture.c +++ b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_capture.c @@ -419,7 +419,7 @@ static void sun6i_isp_capture_format_prepare(struct v4l2_format *format) pix_format->xfer_func = V4L2_XFER_FUNC_DEFAULT; } -static int sun6i_isp_capture_querycap(struct file *file, void *private, +static int sun6i_isp_capture_querycap(struct file *file, void *priv, struct v4l2_capability *capability) { struct sun6i_isp_device *isp_dev = video_drvdata(file); @@ -433,7 +433,7 @@ static int sun6i_isp_capture_querycap(struct file *file, void *private, return 0; } -static int sun6i_isp_capture_enum_fmt(struct file *file, void *private, +static int sun6i_isp_capture_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *fmtdesc) { u32 index = fmtdesc->index; @@ -446,7 +446,7 @@ static int sun6i_isp_capture_enum_fmt(struct file *file, void *private, return 0; } -static int sun6i_isp_capture_g_fmt(struct file *file, void *private, +static int sun6i_isp_capture_g_fmt(struct file *file, void *priv, struct v4l2_format *format) { struct sun6i_isp_device *isp_dev = video_drvdata(file); @@ -456,7 +456,7 @@ static int sun6i_isp_capture_g_fmt(struct file *file, void *private, return 0; } -static int sun6i_isp_capture_s_fmt(struct file *file, void *private, +static int sun6i_isp_capture_s_fmt(struct file *file, void *priv, struct v4l2_format *format) { struct sun6i_isp_device *isp_dev = video_drvdata(file); @@ -471,7 +471,7 @@ static int sun6i_isp_capture_s_fmt(struct file *file, void *private, return 0; } -static int sun6i_isp_capture_try_fmt(struct file *file, void *private, +static int sun6i_isp_capture_try_fmt(struct file *file, void *priv, struct v4l2_format *format) { sun6i_isp_capture_format_prepare(format); @@ -479,7 +479,7 @@ static int sun6i_isp_capture_try_fmt(struct file *file, void *private, return 0; } -static int sun6i_isp_capture_enum_input(struct file *file, void *private, +static int sun6i_isp_capture_enum_input(struct file *file, void *priv, struct v4l2_input *input) { if (input->index != 0) @@ -491,7 +491,7 @@ static int sun6i_isp_capture_enum_input(struct file *file, void *private, return 0; } -static int sun6i_isp_capture_g_input(struct file *file, void *private, +static int sun6i_isp_capture_g_input(struct file *file, void *priv, unsigned int *index) { *index = 0; @@ -499,7 +499,7 @@ static int sun6i_isp_capture_g_input(struct file *file, void *private, return 0; } -static int sun6i_isp_capture_s_input(struct file *file, void *private, +static int sun6i_isp_capture_s_input(struct file *file, void *priv, unsigned int index) { if (index != 0) diff --git a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_params.c b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_params.c index 3d95ed0b023e..77c2d06c0436 100644 --- a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_params.c +++ b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_params.c @@ -383,7 +383,7 @@ static const struct vb2_ops sun6i_isp_params_queue_ops = { /* Video Device */ -static int sun6i_isp_params_querycap(struct file *file, void *private, +static int sun6i_isp_params_querycap(struct file *file, void *priv, struct v4l2_capability *capability) { struct sun6i_isp_device *isp_dev = video_drvdata(file); @@ -397,7 +397,7 @@ static int sun6i_isp_params_querycap(struct file *file, void *private, return 0; } -static int sun6i_isp_params_enum_fmt(struct file *file, void *private, +static int sun6i_isp_params_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *fmtdesc) { struct sun6i_isp_device *isp_dev = video_drvdata(file); @@ -412,7 +412,7 @@ static int sun6i_isp_params_enum_fmt(struct file *file, void *private, return 0; } -static int sun6i_isp_params_g_fmt(struct file *file, void *private, +static int sun6i_isp_params_g_fmt(struct file *file, void *priv, struct v4l2_format *format) { struct sun6i_isp_device *isp_dev = video_drvdata(file); From 689a54acb56858c85de8c7285db82b8ae6dbf683 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 23 Jul 2025 13:01:28 +0300 Subject: [PATCH 00577/11391] 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 00578/11391] 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 00579/11391] 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 00580/11391] 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 00581/11391] 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 00582/11391] 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 00583/11391] 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 00584/11391] 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 00585/11391] 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 00586/11391] 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 00587/11391] 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 00588/11391] 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 00589/11391] 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 00590/11391] 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 00591/11391] 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 00592/11391] 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 00593/11391] 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 00594/11391] 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 00595/11391] 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 00596/11391] 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 00597/11391] 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 00598/11391] 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 00599/11391] 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 00600/11391] 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 00601/11391] 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 1fd143c24fb621f063f913cb1e48cc688c7eca15 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 21 May 2024 23:08:31 -0400 Subject: [PATCH 00602/11391] scsi: switch scsi_bios_ptable() and scsi_partsize() to gendisk Both helpers are reading the partition table of the disk specified by block_device of some partition on it; result depends only upon the disk in question, so we might as well pass the struct gendisk instead. Reviewed-by: Martin K. Petersen Reviewed-by: Christoph Hellwig Acked-by: Jens Axboe Signed-off-by: Al Viro --- Documentation/scsi/scsi_mid_low_api.rst | 4 ++-- drivers/scsi/BusLogic.c | 2 +- drivers/scsi/aacraid/linit.c | 2 +- drivers/scsi/aic7xxx/aic79xx_osm.c | 2 +- drivers/scsi/aic7xxx/aic7xxx_osm.c | 2 +- drivers/scsi/arcmsr/arcmsr_hba.c | 2 +- drivers/scsi/fdomain.c | 2 +- drivers/scsi/megaraid.c | 2 +- drivers/scsi/scsicam.c | 12 ++++++------ include/scsi/scsicam.h | 5 +++-- 10 files changed, 18 insertions(+), 17 deletions(-) diff --git a/Documentation/scsi/scsi_mid_low_api.rst b/Documentation/scsi/scsi_mid_low_api.rst index 3ac4c7fafb55..96c8230d638e 100644 --- a/Documentation/scsi/scsi_mid_low_api.rst +++ b/Documentation/scsi/scsi_mid_low_api.rst @@ -380,7 +380,7 @@ Details:: /** * scsi_bios_ptable - return copy of block device's partition table - * @dev: pointer to block device + * @dev: pointer to gendisk * * Returns pointer to partition table, or NULL for failure * @@ -390,7 +390,7 @@ Details:: * * Defined in: drivers/scsi/scsicam.c **/ - unsigned char *scsi_bios_ptable(struct block_device *dev) + unsigned char *scsi_bios_ptable(struct gendisk *dev) /** diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index 1f100270cd38..743be2ef6d1a 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -3261,7 +3261,7 @@ static int blogic_diskparam(struct scsi_device *sdev, struct block_device *dev, diskparam->sectors = 32; } diskparam->cylinders = (unsigned long) capacity / (diskparam->heads * diskparam->sectors); - buf = scsi_bios_ptable(dev); + buf = scsi_bios_ptable(dev->bd_disk); if (buf == NULL) return 0; /* diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 4b12e6dd8f07..2264a97d91a0 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -324,7 +324,7 @@ static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev, * entry whose end_head matches one of the standard geometry * translations ( 64/32, 128/32, 255/63 ). */ - buf = scsi_bios_ptable(bdev); + buf = scsi_bios_ptable(bdev->bd_disk); if (!buf) return 0; if (*(__le16 *)(buf + 0x40) == cpu_to_le16(MSDOS_LABEL_MAGIC)) { diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 17dfc3c72110..2cff19e95fec 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -731,7 +731,7 @@ ahd_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev, ahd = *((struct ahd_softc **)sdev->host->hostdata); - if (scsi_partsize(bdev, capacity, geom)) + if (scsi_partsize(bdev->bd_disk, capacity, geom)) return 0; heads = 64; diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index cebf8c5d0caf..05bdb73d1157 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -696,7 +696,7 @@ ahc_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev, ahc = *((struct ahc_softc **)sdev->host->hostdata); channel = sdev_channel(sdev); - if (scsi_partsize(bdev, capacity, geom)) + if (scsi_partsize(bdev->bd_disk, capacity, geom)) return 0; heads = 64; diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index fb57343a97bd..6968da9fb67c 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -381,7 +381,7 @@ static int arcmsr_bios_param(struct scsi_device *sdev, { int heads, sectors, cylinders, total_capacity; - if (scsi_partsize(bdev, capacity, geom)) + if (scsi_partsize(bdev->bd_disk, capacity, geom)) return 0; total_capacity = capacity; diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c index 504c4e0c5d17..4a3716dc644c 100644 --- a/drivers/scsi/fdomain.c +++ b/drivers/scsi/fdomain.c @@ -472,7 +472,7 @@ static int fdomain_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]) { - unsigned char *p = scsi_bios_ptable(bdev); + unsigned char *p = scsi_bios_ptable(bdev->bd_disk); if (p && p[65] == 0xaa && p[64] == 0x55 /* Partition table valid */ && p[4]) { /* Partition type */ diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 2006094af418..c7581c7829af 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -2813,7 +2813,7 @@ megaraid_biosparam(struct scsi_device *sdev, struct block_device *bdev, geom[2] = cylinders; } else { - if (scsi_partsize(bdev, capacity, geom)) + if (scsi_partsize(bdev->bd_disk, capacity, geom)) return 0; dev_info(&adapter->dev->dev, diff --git a/drivers/scsi/scsicam.c b/drivers/scsi/scsicam.c index 19e6c3852d50..3ff2cf51d5b0 100644 --- a/drivers/scsi/scsicam.c +++ b/drivers/scsi/scsicam.c @@ -30,9 +30,9 @@ * starting at offset %0x1be. * Returns: partition table in kmalloc(GFP_KERNEL) memory, or NULL on error. */ -unsigned char *scsi_bios_ptable(struct block_device *dev) +unsigned char *scsi_bios_ptable(struct gendisk *dev) { - struct address_space *mapping = bdev_whole(dev)->bd_mapping; + struct address_space *mapping = dev->part0->bd_mapping; unsigned char *res = NULL; struct folio *folio; @@ -48,7 +48,7 @@ EXPORT_SYMBOL(scsi_bios_ptable); /** * scsi_partsize - Parse cylinders/heads/sectors from PC partition table - * @bdev: block device to parse + * @disk: gendisk of the disk to parse * @capacity: size of the disk in sectors * @geom: output in form of [hds, cylinders, sectors] * @@ -57,7 +57,7 @@ EXPORT_SYMBOL(scsi_bios_ptable); * * Returns: %false on failure, %true on success. */ -bool scsi_partsize(struct block_device *bdev, sector_t capacity, int geom[3]) +bool scsi_partsize(struct gendisk *disk, sector_t capacity, int geom[3]) { int cyl, ext_cyl, end_head, end_cyl, end_sector; unsigned int logical_end, physical_end, ext_physical_end; @@ -65,7 +65,7 @@ bool scsi_partsize(struct block_device *bdev, sector_t capacity, int geom[3]) void *buf; int ret = false; - buf = scsi_bios_ptable(bdev); + buf = scsi_bios_ptable(disk); if (!buf) return false; @@ -221,7 +221,7 @@ int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip) int ret = 0; /* try to infer mapping from partition table */ - if (scsi_partsize(bdev, capacity, ip)) + if (scsi_partsize(bdev->bd_disk, capacity, ip)) return 0; if (capacity64 < (1ULL << 32)) { diff --git a/include/scsi/scsicam.h b/include/scsi/scsicam.h index 08edd603e521..67f4e8835bc8 100644 --- a/include/scsi/scsicam.h +++ b/include/scsi/scsicam.h @@ -13,7 +13,8 @@ #ifndef SCSICAM_H #define SCSICAM_H +struct gendisk; int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip); -bool scsi_partsize(struct block_device *bdev, sector_t capacity, int geom[3]); -unsigned char *scsi_bios_ptable(struct block_device *bdev); +bool scsi_partsize(struct gendisk *disk, sector_t capacity, int geom[3]); +unsigned char *scsi_bios_ptable(struct gendisk *disk); #endif /* def SCSICAM_H */ From 3eb50369c09efb0f668a7f568a7e6f7cf4194cde Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 21 May 2024 23:22:01 -0400 Subject: [PATCH 00603/11391] scsi: switch ->bios_param() to passing gendisk Instances are passed struct block_device *bdev argument; the only thing it is used for (if it's used in the first place) is bdev->bd_disk. Might as well pass that in the first place... Reviewed-by: Martin K. Petersen Reviewed-by: Christoph Hellwig Acked-by: Jens Axboe Signed-off-by: Al Viro --- Documentation/scsi/scsi_mid_low_api.rst | 4 ++-- drivers/ata/libata-scsi.c | 4 ++-- drivers/message/fusion/mptscsih.c | 2 +- drivers/message/fusion/mptscsih.h | 2 +- drivers/scsi/3w-9xxx.c | 2 +- drivers/scsi/3w-sas.c | 2 +- drivers/scsi/3w-xxxx.c | 2 +- drivers/scsi/BusLogic.c | 4 ++-- drivers/scsi/BusLogic.h | 2 +- drivers/scsi/aacraid/linit.c | 6 +++--- drivers/scsi/advansys.c | 2 +- drivers/scsi/aha152x.c | 4 ++-- drivers/scsi/aha1542.c | 2 +- drivers/scsi/aha1740.c | 2 +- drivers/scsi/aic7xxx/aic79xx_osm.c | 4 ++-- drivers/scsi/aic7xxx/aic7xxx_osm.c | 4 ++-- drivers/scsi/arcmsr/arcmsr_hba.c | 6 +++--- drivers/scsi/atp870u.c | 2 +- drivers/scsi/fdomain.c | 4 ++-- drivers/scsi/imm.c | 2 +- drivers/scsi/initio.c | 4 ++-- drivers/scsi/ipr.c | 8 ++++---- drivers/scsi/ips.c | 2 +- drivers/scsi/ips.h | 2 +- drivers/scsi/libsas/sas_scsi_host.c | 2 +- drivers/scsi/megaraid.c | 4 ++-- drivers/scsi/megaraid.h | 2 +- drivers/scsi/megaraid/megaraid_sas_base.c | 4 ++-- drivers/scsi/mpi3mr/mpi3mr_os.c | 4 ++-- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 4 ++-- drivers/scsi/mvumi.c | 2 +- drivers/scsi/myrb.c | 2 +- drivers/scsi/pcmcia/sym53c500_cs.c | 2 +- drivers/scsi/ppa.c | 2 +- drivers/scsi/qla1280.c | 2 +- drivers/scsi/qlogicfas408.c | 2 +- drivers/scsi/qlogicfas408.h | 2 +- drivers/scsi/scsicam.c | 6 +++--- drivers/scsi/sd.c | 4 ++-- drivers/scsi/stex.c | 2 +- drivers/scsi/storvsc_drv.c | 2 +- drivers/scsi/wd719x.c | 2 +- include/linux/libata.h | 2 +- include/scsi/libsas.h | 2 +- include/scsi/scsi_host.h | 2 +- include/scsi/scsicam.h | 2 +- 46 files changed, 68 insertions(+), 68 deletions(-) diff --git a/Documentation/scsi/scsi_mid_low_api.rst b/Documentation/scsi/scsi_mid_low_api.rst index 96c8230d638e..634f5c28a849 100644 --- a/Documentation/scsi/scsi_mid_low_api.rst +++ b/Documentation/scsi/scsi_mid_low_api.rst @@ -623,7 +623,7 @@ Details:: * bios_param - fetch head, sector, cylinder info for a disk * @sdev: pointer to scsi device context (defined in * include/scsi/scsi_device.h) - * @bdev: pointer to block device context (defined in fs.h) + * @disk: pointer to gendisk (defined in blkdev.h) * @capacity: device size (in 512 byte sectors) * @params: three element array to place output: * params[0] number of heads (max 255) @@ -643,7 +643,7 @@ Details:: * * Optionally defined in: LLD **/ - int bios_param(struct scsi_device * sdev, struct block_device *bdev, + int bios_param(struct scsi_device * sdev, struct gendisk *disk, sector_t capacity, int params[3]) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 57f674f51b0c..3603b430724b 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -351,7 +351,7 @@ EXPORT_SYMBOL_GPL(ata_common_sdev_groups); /** * ata_std_bios_param - generic bios head/sector/cylinder calculator used by sd. * @sdev: SCSI device for which BIOS geometry is to be determined - * @bdev: block device associated with @sdev + * @unused: gendisk associated with @sdev * @capacity: capacity of SCSI device * @geom: location to which geometry will be output * @@ -366,7 +366,7 @@ EXPORT_SYMBOL_GPL(ata_common_sdev_groups); * RETURNS: * Zero. */ -int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev, +int ata_std_bios_param(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int geom[]) { geom[0] = 255; diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 3a64dc7a7e27..3304f8824cf7 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -2074,7 +2074,7 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, * This is anyones guess quite frankly. */ int -mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev, +mptscsih_bios_param(struct scsi_device * sdev, struct gendisk *unused, sector_t capacity, int geom[]) { int heads; diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h index 8c2bb2331fc1..f9678d48100c 100644 --- a/drivers/message/fusion/mptscsih.h +++ b/drivers/message/fusion/mptscsih.h @@ -123,7 +123,7 @@ extern int mptscsih_abort(struct scsi_cmnd * SCpnt); extern int mptscsih_dev_reset(struct scsi_cmnd * SCpnt); extern int mptscsih_bus_reset(struct scsi_cmnd * SCpnt); extern int mptscsih_host_reset(struct scsi_cmnd *SCpnt); -extern int mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev, sector_t capacity, int geom[]); +extern int mptscsih_bios_param(struct scsi_device * sdev, struct gendisk *unused, sector_t capacity, int geom[]); extern int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); extern int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); extern int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index 883d4a12a172..a377a6f6900a 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -1695,7 +1695,7 @@ static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset) } /* End twa_reset_sequence() */ /* This funciton returns unit geometry in cylinders/heads/sectors */ -static int twa_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]) +static int twa_scsi_biosparam(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int geom[]) { int heads, sectors, cylinders; diff --git a/drivers/scsi/3w-sas.c b/drivers/scsi/3w-sas.c index 8d4174c7107e..e319be7d369c 100644 --- a/drivers/scsi/3w-sas.c +++ b/drivers/scsi/3w-sas.c @@ -1404,7 +1404,7 @@ static int twl_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_res } /* End twl_reset_device_extension() */ /* This funciton returns unit geometry in cylinders/heads/sectors */ -static int twl_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]) +static int twl_scsi_biosparam(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int geom[]) { int heads, sectors; diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index 89bd56f78ef9..0306a228c702 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -1340,7 +1340,7 @@ static int tw_reset_device_extension(TW_Device_Extension *tw_dev) } /* End tw_reset_device_extension() */ /* This funciton returns unit geometry in cylinders/heads/sectors */ -static int tw_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev, +static int tw_scsi_biosparam(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int geom[]) { int heads, sectors, cylinders; diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index 743be2ef6d1a..8b17d8103e90 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -3240,7 +3240,7 @@ static int blogic_resetadapter(struct blogic_adapter *adapter, bool hard_reset) the BIOS, and a warning may be displayed. */ -static int blogic_diskparam(struct scsi_device *sdev, struct block_device *dev, +static int blogic_diskparam(struct scsi_device *sdev, struct gendisk *disk, sector_t capacity, int *params) { struct blogic_adapter *adapter = @@ -3261,7 +3261,7 @@ static int blogic_diskparam(struct scsi_device *sdev, struct block_device *dev, diskparam->sectors = 32; } diskparam->cylinders = (unsigned long) capacity / (diskparam->heads * diskparam->sectors); - buf = scsi_bios_ptable(dev->bd_disk); + buf = scsi_bios_ptable(disk); if (buf == NULL) return 0; /* diff --git a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h index 61bf26d4fc10..79de815e33b0 100644 --- a/drivers/scsi/BusLogic.h +++ b/drivers/scsi/BusLogic.h @@ -1273,7 +1273,7 @@ static inline void blogic_incszbucket(unsigned int *cmdsz_buckets, static const char *blogic_drvr_info(struct Scsi_Host *); static int blogic_qcmd(struct Scsi_Host *h, struct scsi_cmnd *); -static int blogic_diskparam(struct scsi_device *, struct block_device *, sector_t, int *); +static int blogic_diskparam(struct scsi_device *, struct gendisk *, sector_t, int *); static int blogic_sdev_configure(struct scsi_device *, struct queue_limits *lim); static void blogic_qcompleted_ccb(struct blogic_ccb *); diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 2264a97d91a0..ea66196ef7c7 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -273,7 +273,7 @@ struct aac_driver_ident* aac_get_driver_ident(int devtype) /** * aac_biosparm - return BIOS parameters for disk * @sdev: The scsi device corresponding to the disk - * @bdev: the block device corresponding to the disk + * @disk: the gendisk corresponding to the disk * @capacity: the sector capacity of the disk * @geom: geometry block to fill in * @@ -292,7 +292,7 @@ struct aac_driver_ident* aac_get_driver_ident(int devtype) * be displayed. */ -static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev, +static int aac_biosparm(struct scsi_device *sdev, struct gendisk *disk, sector_t capacity, int *geom) { struct diskparm *param = (struct diskparm *)geom; @@ -324,7 +324,7 @@ static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev, * entry whose end_head matches one of the standard geometry * translations ( 64/32, 128/32, 255/63 ). */ - buf = scsi_bios_ptable(bdev->bd_disk); + buf = scsi_bios_ptable(disk); if (!buf) return 0; if (*(__le16 *)(buf + 0x40) == cpu_to_le16(MSDOS_LABEL_MAGIC)) { diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 3a2c336307c0..063e1b5818d3 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -7096,7 +7096,7 @@ static int advansys_reset(struct scsi_cmnd *scp) * ip[2]: cylinders */ static int -advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev, +advansys_biosparam(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int ip[]) { struct asc_board *boardp = shost_priv(sdev->host); diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index e94c0a19c435..182aa80ec4c6 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -1246,7 +1246,7 @@ int aha152x_host_reset_host(struct Scsi_Host *shpnt) * Return the "logical geometry" * */ -static int aha152x_biosparam(struct scsi_device *sdev, struct block_device *bdev, +static int aha152x_biosparam(struct scsi_device *sdev, struct gendisk *disk, sector_t capacity, int *info_array) { struct Scsi_Host *shpnt = sdev->host; @@ -1261,7 +1261,7 @@ static int aha152x_biosparam(struct scsi_device *sdev, struct block_device *bdev int info[3]; /* try to figure out the geometry from the partition table */ - if (scsicam_bios_param(bdev, capacity, info) < 0 || + if (scsicam_bios_param(disk, capacity, info) < 0 || !((info[0] == 64 && info[1] == 32) || (info[0] == 255 && info[1] == 63))) { if (EXT_TRANS) { printk(KERN_NOTICE diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c index 389499d3e00a..371e8300f029 100644 --- a/drivers/scsi/aha1542.c +++ b/drivers/scsi/aha1542.c @@ -992,7 +992,7 @@ static int aha1542_host_reset(struct scsi_cmnd *cmd) } static int aha1542_biosparam(struct scsi_device *sdev, - struct block_device *bdev, sector_t capacity, int geom[]) + struct gendisk *unused, sector_t capacity, int geom[]) { struct aha1542_hostdata *aha1542 = shost_priv(sdev->host); diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c index be7ebbbb9ba8..b234621f6b37 100644 --- a/drivers/scsi/aha1740.c +++ b/drivers/scsi/aha1740.c @@ -510,7 +510,7 @@ static void aha1740_getconfig(unsigned int base, unsigned int *irq_level, } static int aha1740_biosparam(struct scsi_device *sdev, - struct block_device *dev, + struct gendisk *unused, sector_t capacity, int* ip) { int size = capacity; diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 2cff19e95fec..c3d1b9dd24ae 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -720,7 +720,7 @@ ahd_linux_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) * Return the disk geometry for the given SCSI device. */ static int -ahd_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev, +ahd_linux_biosparam(struct scsi_device *sdev, struct gendisk *disk, sector_t capacity, int geom[]) { int heads; @@ -731,7 +731,7 @@ ahd_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev, ahd = *((struct ahd_softc **)sdev->host->hostdata); - if (scsi_partsize(bdev->bd_disk, capacity, geom)) + if (scsi_partsize(disk, capacity, geom)) return 0; heads = 64; diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 05bdb73d1157..8b2b98666d61 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -683,7 +683,7 @@ ahc_linux_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) * Return the disk geometry for the given SCSI device. */ static int -ahc_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev, +ahc_linux_biosparam(struct scsi_device *sdev, struct gendisk *disk, sector_t capacity, int geom[]) { int heads; @@ -696,7 +696,7 @@ ahc_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev, ahc = *((struct ahc_softc **)sdev->host->hostdata); channel = sdev_channel(sdev); - if (scsi_partsize(bdev->bd_disk, capacity, geom)) + if (scsi_partsize(disk, capacity, geom)) return 0; heads = 64; diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 6968da9fb67c..f0c5a30ce51b 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -112,7 +112,7 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb); static int arcmsr_abort(struct scsi_cmnd *); static int arcmsr_bus_reset(struct scsi_cmnd *); static int arcmsr_bios_param(struct scsi_device *sdev, - struct block_device *bdev, sector_t capacity, int *info); + struct gendisk *disk, sector_t capacity, int *info); static int arcmsr_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd); static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id); @@ -377,11 +377,11 @@ static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id) } static int arcmsr_bios_param(struct scsi_device *sdev, - struct block_device *bdev, sector_t capacity, int *geom) + struct gendisk *disk, sector_t capacity, int *geom) { int heads, sectors, cylinders, total_capacity; - if (scsi_partsize(bdev->bd_disk, capacity, geom)) + if (scsi_partsize(disk, capacity, geom)) return 0; total_capacity = capacity; diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c index 401242912855..df6f40b51deb 100644 --- a/drivers/scsi/atp870u.c +++ b/drivers/scsi/atp870u.c @@ -1692,7 +1692,7 @@ static int atp870u_show_info(struct seq_file *m, struct Scsi_Host *HBAptr) } -static int atp870u_biosparam(struct scsi_device *disk, struct block_device *dev, +static int atp870u_biosparam(struct scsi_device *disk, struct gendisk *unused, sector_t capacity, int *ip) { int heads, sectors, cylinders; diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c index 4a3716dc644c..c0b2a980db34 100644 --- a/drivers/scsi/fdomain.c +++ b/drivers/scsi/fdomain.c @@ -469,10 +469,10 @@ static int fdomain_host_reset(struct scsi_cmnd *cmd) } static int fdomain_biosparam(struct scsi_device *sdev, - struct block_device *bdev, sector_t capacity, + struct gendisk *disk, sector_t capacity, int geom[]) { - unsigned char *p = scsi_bios_ptable(bdev->bd_disk); + unsigned char *p = scsi_bios_ptable(disk); if (p && p[65] == 0xaa && p[64] == 0x55 /* Partition table valid */ && p[4]) { /* Partition type */ diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c index 0821cf994b98..5c602c057798 100644 --- a/drivers/scsi/imm.c +++ b/drivers/scsi/imm.c @@ -954,7 +954,7 @@ static DEF_SCSI_QCMD(imm_queuecommand) * be done in sd.c. Even if it gets fixed there, this will still * work. */ -static int imm_biosparam(struct scsi_device *sdev, struct block_device *dev, +static int imm_biosparam(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int ip[]) { ip[0] = 0x40; diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c index 8648bd965287..ed34ad92c807 100644 --- a/drivers/scsi/initio.c +++ b/drivers/scsi/initio.c @@ -2645,7 +2645,7 @@ static int i91u_bus_reset(struct scsi_cmnd * cmnd) /** * i91u_biosparam - return the "logical geometry * @sdev: SCSI device - * @dev: Matching block device + * @unused: Matching gendisk * @capacity: Sector size of drive * @info_array: Return space for BIOS geometry * @@ -2655,7 +2655,7 @@ static int i91u_bus_reset(struct scsi_cmnd * cmnd) * FIXME: limited to 2^32 sector devices. */ -static int i91u_biosparam(struct scsi_device *sdev, struct block_device *dev, +static int i91u_biosparam(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int *info_array) { struct initio_host *host; /* Point to Host adapter control block */ diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index d06b79f03538..dd6754db7e4c 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -4644,10 +4644,10 @@ ATTRIBUTE_GROUPS(ipr_dev); /** * ipr_biosparam - Return the HSC mapping - * @sdev: scsi device struct - * @block_device: block device pointer + * @sdev: scsi device struct + * @unused: gendisk pointer * @capacity: capacity of the device - * @parm: Array containing returned HSC values. + * @parm: Array containing returned HSC values. * * This function generates the HSC parms that fdisk uses. * We want to make sure we return something that places partitions @@ -4657,7 +4657,7 @@ ATTRIBUTE_GROUPS(ipr_dev); * 0 on success **/ static int ipr_biosparam(struct scsi_device *sdev, - struct block_device *block_device, + struct gendisk *unused, sector_t capacity, int *parm) { int heads, sectors; diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index 94adb6ac02a4..3393a288fd23 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -1123,7 +1123,7 @@ static DEF_SCSI_QCMD(ips_queue) /* Set bios geometry for the controller */ /* */ /****************************************************************************/ -static int ips_biosparam(struct scsi_device *sdev, struct block_device *bdev, +static int ips_biosparam(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int geom[]) { ips_ha_t *ha = (ips_ha_t *) sdev->host->hostdata; diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h index 8ac932ec4444..30a4d4a580e9 100644 --- a/drivers/scsi/ips.h +++ b/drivers/scsi/ips.h @@ -398,7 +398,7 @@ /* * Scsi_Host Template */ - static int ips_biosparam(struct scsi_device *sdev, struct block_device *bdev, + static int ips_biosparam(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int geom[]); static int ips_sdev_configure(struct scsi_device *SDptr, struct queue_limits *lim); diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 928723c90b75..ffa5b49aaf08 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -845,7 +845,7 @@ int sas_change_queue_depth(struct scsi_device *sdev, int depth) EXPORT_SYMBOL_GPL(sas_change_queue_depth); int sas_bios_param(struct scsi_device *scsi_dev, - struct block_device *bdev, + struct gendisk *unused, sector_t capacity, int *hsc) { hsc[0] = 255; diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index c7581c7829af..a00622c0c526 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -2780,7 +2780,7 @@ static inline void mega_create_proc_entry(int index, struct proc_dir_entry *pare * Return the disk geometry for a particular disk */ static int -megaraid_biosparam(struct scsi_device *sdev, struct block_device *bdev, +megaraid_biosparam(struct scsi_device *sdev, struct gendisk *disk, sector_t capacity, int geom[]) { adapter_t *adapter; @@ -2813,7 +2813,7 @@ megaraid_biosparam(struct scsi_device *sdev, struct block_device *bdev, geom[2] = cylinders; } else { - if (scsi_partsize(bdev->bd_disk, capacity, geom)) + if (scsi_partsize(disk, capacity, geom)) return 0; dev_info(&adapter->dev->dev, diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h index 013fbfb911b9..d6bfd26a8843 100644 --- a/drivers/scsi/megaraid.h +++ b/drivers/scsi/megaraid.h @@ -975,7 +975,7 @@ static void mega_free_scb(adapter_t *, scb_t *); static int megaraid_abort(struct scsi_cmnd *); static int megaraid_reset(struct scsi_cmnd *); static int megaraid_abort_and_reset(adapter_t *, struct scsi_cmnd *, int); -static int megaraid_biosparam(struct scsi_device *, struct block_device *, +static int megaraid_biosparam(struct scsi_device *, struct gendisk *, sector_t, int []); static int mega_build_sglist (adapter_t *adapter, scb_t *scb, diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 615e06fd4ee8..abbbc4b36cd1 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -3137,12 +3137,12 @@ static int megasas_reset_target(struct scsi_cmnd *scmd) /** * megasas_bios_param - Returns disk geometry for a disk * @sdev: device handle - * @bdev: block device + * @unused: gendisk * @capacity: drive capacity * @geom: geometry parameters */ static int -megasas_bios_param(struct scsi_device *sdev, struct block_device *bdev, +megasas_bios_param(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int geom[]) { int heads; diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index e467b56949e9..3df52a3b435b 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -4031,7 +4031,7 @@ int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type, /** * mpi3mr_bios_param - BIOS param callback * @sdev: SCSI device reference - * @bdev: Block device reference + * @unused: gendisk reference * @capacity: Capacity in logical sectors * @params: Parameter array * @@ -4040,7 +4040,7 @@ int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type, * Return: 0 always */ static int mpi3mr_bios_param(struct scsi_device *sdev, - struct block_device *bdev, sector_t capacity, int params[]) + struct gendisk *unused, sector_t capacity, int params[]) { int heads; int sectors; diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 967af259118e..7092d0debef3 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -2754,7 +2754,7 @@ scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) /** * scsih_bios_param - fetch head, sector, cylinder info for a disk * @sdev: scsi device struct - * @bdev: pointer to block device context + * @unused: pointer to gendisk * @capacity: device size (in 512 byte sectors) * @params: three element array to place output: * params[0] number of heads (max 255) @@ -2762,7 +2762,7 @@ scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) * params[2] number of cylinders */ static int -scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev, +scsih_bios_param(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int params[]) { int heads; diff --git a/drivers/scsi/mvumi.c b/drivers/scsi/mvumi.c index 96549e7f5705..bdc2f2f17753 100644 --- a/drivers/scsi/mvumi.c +++ b/drivers/scsi/mvumi.c @@ -2142,7 +2142,7 @@ static enum scsi_timeout_action mvumi_timed_out(struct scsi_cmnd *scmd) } static int -mvumi_bios_param(struct scsi_device *sdev, struct block_device *bdev, +mvumi_bios_param(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int geom[]) { int heads, sectors; diff --git a/drivers/scsi/myrb.c b/drivers/scsi/myrb.c index 486db5b2f05d..b8453c0333dc 100644 --- a/drivers/scsi/myrb.c +++ b/drivers/scsi/myrb.c @@ -1745,7 +1745,7 @@ static void myrb_sdev_destroy(struct scsi_device *sdev) kfree(sdev->hostdata); } -static int myrb_biosparam(struct scsi_device *sdev, struct block_device *bdev, +static int myrb_biosparam(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int geom[]) { struct myrb_hba *cb = shost_priv(sdev->host); diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c index 278c78d066c4..a3b505240351 100644 --- a/drivers/scsi/pcmcia/sym53c500_cs.c +++ b/drivers/scsi/pcmcia/sym53c500_cs.c @@ -597,7 +597,7 @@ SYM53C500_host_reset(struct scsi_cmnd *SCpnt) static int SYM53C500_biosparm(struct scsi_device *disk, - struct block_device *dev, + struct gendisk *unused, sector_t capacity, int *info_array) { int size; diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c index 1ed3171f1797..ea682f3044b6 100644 --- a/drivers/scsi/ppa.c +++ b/drivers/scsi/ppa.c @@ -845,7 +845,7 @@ static DEF_SCSI_QCMD(ppa_queuecommand) * be done in sd.c. Even if it gets fixed there, this will still * work. */ -static int ppa_biosparam(struct scsi_device *sdev, struct block_device *dev, +static int ppa_biosparam(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int ip[]) { ip[0] = 0x40; diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 6af018f1ca22..ef841f643171 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -1023,7 +1023,7 @@ qla1280_eh_adapter_reset(struct scsi_cmnd *cmd) } static int -qla1280_biosparam(struct scsi_device *sdev, struct block_device *bdev, +qla1280_biosparam(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int geom[]) { int heads, sectors, cylinders; diff --git a/drivers/scsi/qlogicfas408.c b/drivers/scsi/qlogicfas408.c index 3e065d5fc80c..1ce469b7db99 100644 --- a/drivers/scsi/qlogicfas408.c +++ b/drivers/scsi/qlogicfas408.c @@ -492,7 +492,7 @@ DEF_SCSI_QCMD(qlogicfas408_queuecommand) * Return bios parameters */ -int qlogicfas408_biosparam(struct scsi_device *disk, struct block_device *dev, +int qlogicfas408_biosparam(struct scsi_device *disk, struct gendisk *unused, sector_t capacity, int ip[]) { /* This should mimic the DOS Qlogic driver's behavior exactly */ diff --git a/drivers/scsi/qlogicfas408.h b/drivers/scsi/qlogicfas408.h index a971db11d293..83ef86c71f2f 100644 --- a/drivers/scsi/qlogicfas408.h +++ b/drivers/scsi/qlogicfas408.h @@ -106,7 +106,7 @@ struct qlogicfas408_priv { irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id); int qlogicfas408_queuecommand(struct Scsi_Host *h, struct scsi_cmnd * cmd); int qlogicfas408_biosparam(struct scsi_device * disk, - struct block_device *dev, + struct gendisk *unused, sector_t capacity, int ip[]); int qlogicfas408_abort(struct scsi_cmnd * cmd); extern int qlogicfas408_host_reset(struct scsi_cmnd *cmd); diff --git a/drivers/scsi/scsicam.c b/drivers/scsi/scsicam.c index 3ff2cf51d5b0..887de505bcf9 100644 --- a/drivers/scsi/scsicam.c +++ b/drivers/scsi/scsicam.c @@ -205,7 +205,7 @@ static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds /** * scsicam_bios_param - Determine geometry of a disk in cylinders/heads/sectors. - * @bdev: which device + * @disk: which device * @capacity: size of the disk in sectors * @ip: return value: ip[0]=heads, ip[1]=sectors, ip[2]=cylinders * @@ -215,13 +215,13 @@ static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds * * Returns : -1 on failure, 0 on success. */ -int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip) +int scsicam_bios_param(struct gendisk *disk, sector_t capacity, int *ip) { u64 capacity64 = capacity; /* Suppress gcc warning */ int ret = 0; /* try to infer mapping from partition table */ - if (scsi_partsize(bdev->bd_disk, capacity, ip)) + if (scsi_partsize(disk, capacity, ip)) return 0; if (capacity64 < (1ULL << 32)) { diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 5b8668accf8e..3edcc43f180b 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1614,9 +1614,9 @@ static int sd_getgeo(struct block_device *bdev, struct hd_geometry *geo) /* override with calculated, extended default, or driver values */ if (host->hostt->bios_param) - host->hostt->bios_param(sdp, bdev, capacity, diskinfo); + host->hostt->bios_param(sdp, bdev->bd_disk, capacity, diskinfo); else - scsicam_bios_param(bdev, capacity, diskinfo); + scsicam_bios_param(bdev->bd_disk, capacity, diskinfo); geo->heads = diskinfo[0]; geo->sectors = diskinfo[1]; diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index 63ed7f9aaa93..d8ad02c29320 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -1457,7 +1457,7 @@ static void stex_reset_work(struct work_struct *work) } static int stex_biosparam(struct scsi_device *sdev, - struct block_device *bdev, sector_t capacity, int geom[]) + struct gendisk *unused, sector_t capacity, int geom[]) { int heads = 255, sectors = 63; diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index d9e59204a9c3..dc51ea352198 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -1615,7 +1615,7 @@ static int storvsc_sdev_configure(struct scsi_device *sdevice, return 0; } -static int storvsc_get_chs(struct scsi_device *sdev, struct block_device * bdev, +static int storvsc_get_chs(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int *info) { sector_t nsect = capacity; diff --git a/drivers/scsi/wd719x.c b/drivers/scsi/wd719x.c index 5a380eecfc75..0c9987828774 100644 --- a/drivers/scsi/wd719x.c +++ b/drivers/scsi/wd719x.c @@ -544,7 +544,7 @@ static int wd719x_host_reset(struct scsi_cmnd *cmd) return wd719x_chip_init(wd) == 0 ? SUCCESS : FAILED; } -static int wd719x_biosparam(struct scsi_device *sdev, struct block_device *bdev, +static int wd719x_biosparam(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int geom[]) { if (capacity >= 0x200000) { diff --git a/include/linux/libata.h b/include/linux/libata.h index 0620dd67369f..21de0935775d 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1203,7 +1203,7 @@ extern void ata_qc_complete(struct ata_queued_cmd *qc); extern u64 ata_qc_get_active(struct ata_port *ap); extern void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd); extern int ata_std_bios_param(struct scsi_device *sdev, - struct block_device *bdev, + struct gendisk *unused, sector_t capacity, int geom[]); extern void ata_scsi_unlock_native_capacity(struct scsi_device *sdev); extern int ata_scsi_sdev_init(struct scsi_device *sdev); diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index ba460b6c0374..9c6e90829dbd 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -685,7 +685,7 @@ extern int sas_queuecommand(struct Scsi_Host *, struct scsi_cmnd *); extern int sas_target_alloc(struct scsi_target *); int sas_sdev_configure(struct scsi_device *dev, struct queue_limits *lim); extern int sas_change_queue_depth(struct scsi_device *, int new_depth); -extern int sas_bios_param(struct scsi_device *, struct block_device *, +extern int sas_bios_param(struct scsi_device *, struct gendisk *, sector_t capacity, int *hsc); int sas_execute_internal_abort_single(struct domain_device *device, u16 tag, unsigned int qid, diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index c53812b9026f..f5a243261236 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -318,7 +318,7 @@ struct scsi_host_template { * * Status: OPTIONAL */ - int (* bios_param)(struct scsi_device *, struct block_device *, + int (* bios_param)(struct scsi_device *, struct gendisk *, sector_t, int []); /* diff --git a/include/scsi/scsicam.h b/include/scsi/scsicam.h index 67f4e8835bc8..1131f51ed2c8 100644 --- a/include/scsi/scsicam.h +++ b/include/scsi/scsicam.h @@ -14,7 +14,7 @@ #ifndef SCSICAM_H #define SCSICAM_H struct gendisk; -int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip); +int scsicam_bios_param(struct gendisk *disk, sector_t capacity, int *ip); bool scsi_partsize(struct gendisk *disk, sector_t capacity, int geom[3]); unsigned char *scsi_bios_ptable(struct gendisk *disk); #endif /* def SCSICAM_H */ From 4fc8728aa34f54835b72e4db0f3db76a72948b65 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 21 May 2024 22:19:55 -0400 Subject: [PATCH 00604/11391] block: switch ->getgeo() to struct gendisk Instances are happier that way and it makes more sense anyway - the only part of the result that is related to partition we are given is the start sector, and that has been filled in by the caller. Everything else is a function of the disk. Only one instance (DASD) is ever looking at anything other than bdev->bd_disk and that one is trivial to adjust. Reviewed-by: Martin K. Petersen Reviewed-by: Christoph Hellwig Acked-by: Jens Axboe Signed-off-by: Al Viro --- Documentation/filesystems/locking.rst | 2 +- arch/m68k/emu/nfblock.c | 4 ++-- arch/um/drivers/ubd_kern.c | 6 +++--- block/ioctl.c | 4 ++-- block/partitions/ibm.c | 2 +- drivers/block/amiflop.c | 10 +++++----- drivers/block/aoe/aoeblk.c | 4 ++-- drivers/block/floppy.c | 4 ++-- drivers/block/mtip32xx/mtip32xx.c | 6 +++--- drivers/block/rnbd/rnbd-clt.c | 4 ++-- drivers/block/sunvdc.c | 3 +-- drivers/block/swim.c | 4 ++-- drivers/block/virtio_blk.c | 6 +++--- drivers/block/xen-blkfront.c | 4 ++-- drivers/md/dm.c | 4 ++-- drivers/md/md.c | 4 ++-- drivers/memstick/core/ms_block.c | 4 ++-- drivers/memstick/core/mspro_block.c | 4 ++-- drivers/mmc/core/block.c | 4 ++-- drivers/mtd/mtd_blkdevs.c | 4 ++-- drivers/mtd/ubi/block.c | 4 ++-- drivers/nvdimm/btt.c | 4 ++-- drivers/nvme/host/core.c | 4 ++-- drivers/nvme/host/nvme.h | 2 +- drivers/s390/block/dasd.c | 7 ++++--- drivers/scsi/sd.c | 8 ++++---- include/linux/blkdev.h | 2 +- 27 files changed, 59 insertions(+), 59 deletions(-) diff --git a/Documentation/filesystems/locking.rst b/Documentation/filesystems/locking.rst index aa287ccdac2f..77704fde9845 100644 --- a/Documentation/filesystems/locking.rst +++ b/Documentation/filesystems/locking.rst @@ -443,7 +443,7 @@ prototypes:: int (*direct_access) (struct block_device *, sector_t, void **, unsigned long *); void (*unlock_native_capacity) (struct gendisk *); - int (*getgeo)(struct block_device *, struct hd_geometry *); + int (*getgeo)(struct gendisk *, struct hd_geometry *); void (*swap_slot_free_notify) (struct block_device *, unsigned long); locking rules: diff --git a/arch/m68k/emu/nfblock.c b/arch/m68k/emu/nfblock.c index 83410f8184ec..94a4fadc651a 100644 --- a/arch/m68k/emu/nfblock.c +++ b/arch/m68k/emu/nfblock.c @@ -77,9 +77,9 @@ static void nfhd_submit_bio(struct bio *bio) bio_endio(bio); } -static int nfhd_getgeo(struct block_device *bdev, struct hd_geometry *geo) +static int nfhd_getgeo(struct gendisk *disk, struct hd_geometry *geo) { - struct nfhd_device *dev = bdev->bd_disk->private_data; + struct nfhd_device *dev = disk->private_data; geo->cylinders = dev->blocks >> (6 - dev->bshift); geo->heads = 4; diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 4de6613e7468..f2b2feeeb455 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -108,7 +108,7 @@ static DEFINE_MUTEX(ubd_lock); static int ubd_ioctl(struct block_device *bdev, blk_mode_t mode, unsigned int cmd, unsigned long arg); -static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo); +static int ubd_getgeo(struct gendisk *disk, struct hd_geometry *geo); #define MAX_DEV (16) @@ -1324,9 +1324,9 @@ static blk_status_t ubd_queue_rq(struct blk_mq_hw_ctx *hctx, return res; } -static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo) +static int ubd_getgeo(struct gendisk *disk, struct hd_geometry *geo) { - struct ubd *ubd_dev = bdev->bd_disk->private_data; + struct ubd *ubd_dev = disk->private_data; geo->heads = 128; geo->sectors = 32; diff --git a/block/ioctl.c b/block/ioctl.c index f7b0006ca45d..a14304f737c5 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -481,7 +481,7 @@ static int blkdev_getgeo(struct block_device *bdev, */ memset(&geo, 0, sizeof(geo)); geo.start = get_start_sect(bdev); - ret = disk->fops->getgeo(bdev, &geo); + ret = disk->fops->getgeo(disk, &geo); if (ret) return ret; if (copy_to_user(argp, &geo, sizeof(geo))) @@ -515,7 +515,7 @@ static int compat_hdio_getgeo(struct block_device *bdev, * want to override it. */ geo.start = get_start_sect(bdev); - ret = disk->fops->getgeo(bdev, &geo); + ret = disk->fops->getgeo(disk, &geo); if (ret) return ret; diff --git a/block/partitions/ibm.c b/block/partitions/ibm.c index 82d9c4c3fb41..631291fbb356 100644 --- a/block/partitions/ibm.c +++ b/block/partitions/ibm.c @@ -358,7 +358,7 @@ int ibm_partition(struct parsed_partitions *state) goto out_nolab; /* set start if not filled by getgeo function e.g. virtblk */ geo->start = get_start_sect(bdev); - if (disk->fops->getgeo(bdev, geo)) + if (disk->fops->getgeo(disk, geo)) goto out_freeall; if (!fn || fn(disk, info)) { kfree(info); diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 6357d86eafdc..2932b6653b6f 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -1523,13 +1523,13 @@ static blk_status_t amiflop_queue_rq(struct blk_mq_hw_ctx *hctx, return BLK_STS_OK; } -static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo) +static int fd_getgeo(struct gendisk *disk, struct hd_geometry *geo) { - int drive = MINOR(bdev->bd_dev) & 3; + struct amiga_floppy_struct *p = disk->private_data; - geo->heads = unit[drive].type->heads; - geo->sectors = unit[drive].dtype->sects * unit[drive].type->sect_mult; - geo->cylinders = unit[drive].type->tracks; + geo->heads = p->type->heads; + geo->sectors = p->dtype->sects * p->type->sect_mult; + geo->cylinders = p->type->tracks; return 0; } diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index 00b74a845328..34ead75e7e02 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -269,9 +269,9 @@ static blk_status_t aoeblk_queue_rq(struct blk_mq_hw_ctx *hctx, } static int -aoeblk_getgeo(struct block_device *bdev, struct hd_geometry *geo) +aoeblk_getgeo(struct gendisk *disk, struct hd_geometry *geo) { - struct aoedev *d = bdev->bd_disk->private_data; + struct aoedev *d = disk->private_data; if ((d->flags & DEVFL_UP) == 0) { printk(KERN_ERR "aoe: disk not up\n"); diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 24be0c2c4075..eb125a36ec24 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -3363,9 +3363,9 @@ static int get_floppy_geometry(int drive, int type, struct floppy_struct **g) return 0; } -static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo) +static int fd_getgeo(struct gendisk *disk, struct hd_geometry *geo) { - int drive = (long)bdev->bd_disk->private_data; + int drive = (long)disk->private_data; int type = ITYPE(drive_state[drive].fd_device); struct floppy_struct *g; int ret; diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 8fc7761397bd..567192e371a8 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -3148,17 +3148,17 @@ static int mtip_block_compat_ioctl(struct block_device *dev, * that each partition is also 4KB aligned. Non-aligned partitions adversely * affects performance. * - * @dev Pointer to the block_device strucutre. + * @disk Pointer to the gendisk strucutre. * @geo Pointer to a hd_geometry structure. * * return value * 0 Operation completed successfully. * -ENOTTY An error occurred while reading the drive capacity. */ -static int mtip_block_getgeo(struct block_device *dev, +static int mtip_block_getgeo(struct gendisk *disk, struct hd_geometry *geo) { - struct driver_data *dd = dev->bd_disk->private_data; + struct driver_data *dd = disk->private_data; sector_t capacity; if (!dd) diff --git a/drivers/block/rnbd/rnbd-clt.c b/drivers/block/rnbd/rnbd-clt.c index 15627417f12e..119b7e27023f 100644 --- a/drivers/block/rnbd/rnbd-clt.c +++ b/drivers/block/rnbd/rnbd-clt.c @@ -942,11 +942,11 @@ static void rnbd_client_release(struct gendisk *gen) rnbd_clt_put_dev(dev); } -static int rnbd_client_getgeo(struct block_device *block_device, +static int rnbd_client_getgeo(struct gendisk *disk, struct hd_geometry *geo) { u64 size; - struct rnbd_clt_dev *dev = block_device->bd_disk->private_data; + struct rnbd_clt_dev *dev = disk->private_data; struct queue_limits *limit = &dev->queue->limits; size = dev->size * (limit->logical_block_size / SECTOR_SIZE); diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c index 7af21fe67671..107751721178 100644 --- a/drivers/block/sunvdc.c +++ b/drivers/block/sunvdc.c @@ -119,9 +119,8 @@ static inline u32 vdc_tx_dring_avail(struct vio_dring_state *dr) return vio_dring_avail(dr, VDC_TX_RING_SIZE); } -static int vdc_getgeo(struct block_device *bdev, struct hd_geometry *geo) +static int vdc_getgeo(struct gendisk *disk, struct hd_geometry *geo) { - struct gendisk *disk = bdev->bd_disk; sector_t nsect = get_capacity(disk); sector_t cylinders = nsect; diff --git a/drivers/block/swim.c b/drivers/block/swim.c index eda33c5eb5e2..416015947ae6 100644 --- a/drivers/block/swim.c +++ b/drivers/block/swim.c @@ -711,9 +711,9 @@ static int floppy_ioctl(struct block_device *bdev, blk_mode_t mode, return -ENOTTY; } -static int floppy_getgeo(struct block_device *bdev, struct hd_geometry *geo) +static int floppy_getgeo(struct gendisk *disk, struct hd_geometry *geo) { - struct floppy_state *fs = bdev->bd_disk->private_data; + struct floppy_state *fs = disk->private_data; struct floppy_struct *g; int ret; diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index e649fa67bac1..85efa7e535f8 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -829,9 +829,9 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str) } /* We provide getgeo only to please some old bootloader/partitioning tools */ -static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo) +static int virtblk_getgeo(struct gendisk *disk, struct hd_geometry *geo) { - struct virtio_blk *vblk = bd->bd_disk->private_data; + struct virtio_blk *vblk = disk->private_data; int ret = 0; mutex_lock(&vblk->vdev_mutex); @@ -853,7 +853,7 @@ static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo) /* some standard values, similar to sd */ geo->heads = 1 << 6; geo->sectors = 1 << 5; - geo->cylinders = get_capacity(bd->bd_disk) >> 11; + geo->cylinders = get_capacity(disk) >> 11; } out: mutex_unlock(&vblk->vdev_mutex); diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 5babe575c288..04fc6b552c04 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -493,11 +493,11 @@ static void blkif_restart_queue_callback(void *arg) schedule_work(&rinfo->work); } -static int blkif_getgeo(struct block_device *bd, struct hd_geometry *hg) +static int blkif_getgeo(struct gendisk *disk, struct hd_geometry *hg) { /* We don't have real geometry info, but let's at least return values consistent with the size of the device */ - sector_t nsect = get_capacity(bd->bd_disk); + sector_t nsect = get_capacity(disk); sector_t cylinders = nsect; hg->heads = 0xff; diff --git a/drivers/md/dm.c b/drivers/md/dm.c index a44e8c2dccee..7bd6fa05b00a 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -403,9 +403,9 @@ static void do_deferred_remove(struct work_struct *w) dm_deferred_remove(); } -static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo) +static int dm_blk_getgeo(struct gendisk *disk, struct hd_geometry *geo) { - struct mapped_device *md = bdev->bd_disk->private_data; + struct mapped_device *md = disk->private_data; return dm_get_geometry(md, geo); } diff --git a/drivers/md/md.c b/drivers/md/md.c index ac85ec73a409..236bb04f3e54 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -7678,9 +7678,9 @@ static int set_disk_faulty(struct mddev *mddev, dev_t dev) * 4 sectors (with a BIG number of cylinders...). This drives * dosfs just mad... ;-) */ -static int md_getgeo(struct block_device *bdev, struct hd_geometry *geo) +static int md_getgeo(struct gendisk *disk, struct hd_geometry *geo) { - struct mddev *mddev = bdev->bd_disk->private_data; + struct mddev *mddev = disk->private_data; geo->heads = 2; geo->sectors = 4; diff --git a/drivers/memstick/core/ms_block.c b/drivers/memstick/core/ms_block.c index d34892782f6e..1af157ce0a63 100644 --- a/drivers/memstick/core/ms_block.c +++ b/drivers/memstick/core/ms_block.c @@ -1953,10 +1953,10 @@ static void msb_data_clear(struct msb_data *msb) msb->card = NULL; } -static int msb_bd_getgeo(struct block_device *bdev, +static int msb_bd_getgeo(struct gendisk *disk, struct hd_geometry *geo) { - struct msb_data *msb = bdev->bd_disk->private_data; + struct msb_data *msb = disk->private_data; *geo = msb->geometry; return 0; } diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index c9853d887d28..075519caa547 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c @@ -189,10 +189,10 @@ static void mspro_block_bd_free_disk(struct gendisk *disk) kfree(msb); } -static int mspro_block_bd_getgeo(struct block_device *bdev, +static int mspro_block_bd_getgeo(struct gendisk *disk, struct hd_geometry *geo) { - struct mspro_block_data *msb = bdev->bd_disk->private_data; + struct mspro_block_data *msb = disk->private_data; geo->heads = msb->heads; geo->sectors = msb->sectors_per_track; diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 9cc47bf94804..d1f295af9713 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -435,9 +435,9 @@ static void mmc_blk_release(struct gendisk *disk) } static int -mmc_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo) +mmc_blk_getgeo(struct gendisk *disk, struct hd_geometry *geo) { - geo->cylinders = get_capacity(bdev->bd_disk) / (4 * 16); + geo->cylinders = get_capacity(disk) / (4 * 16); geo->heads = 4; geo->sectors = 16; return 0; diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 847c11542f02..28e09d080440 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -246,9 +246,9 @@ static void blktrans_release(struct gendisk *disk) blktrans_dev_put(dev); } -static int blktrans_getgeo(struct block_device *bdev, struct hd_geometry *geo) +static int blktrans_getgeo(struct gendisk *disk, struct hd_geometry *geo) { - struct mtd_blktrans_dev *dev = bdev->bd_disk->private_data; + struct mtd_blktrans_dev *dev = disk->private_data; int ret = -ENXIO; mutex_lock(&dev->lock); diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c index 39cc0a6a4d37..b53fd147fa65 100644 --- a/drivers/mtd/ubi/block.c +++ b/drivers/mtd/ubi/block.c @@ -282,12 +282,12 @@ static void ubiblock_release(struct gendisk *gd) mutex_unlock(&dev->dev_mutex); } -static int ubiblock_getgeo(struct block_device *bdev, struct hd_geometry *geo) +static int ubiblock_getgeo(struct gendisk *disk, struct hd_geometry *geo) { /* Some tools might require this information */ geo->heads = 1; geo->cylinders = 1; - geo->sectors = get_capacity(bdev->bd_disk); + geo->sectors = get_capacity(disk); geo->start = 0; return 0; } diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c index 2a1aa32e6693..a933db961ed7 100644 --- a/drivers/nvdimm/btt.c +++ b/drivers/nvdimm/btt.c @@ -1478,12 +1478,12 @@ static void btt_submit_bio(struct bio *bio) bio_endio(bio); } -static int btt_getgeo(struct block_device *bd, struct hd_geometry *geo) +static int btt_getgeo(struct gendisk *disk, struct hd_geometry *geo) { /* some standard values */ geo->heads = 1 << 6; geo->sectors = 1 << 5; - geo->cylinders = get_capacity(bd->bd_disk) >> 11; + geo->cylinders = get_capacity(disk) >> 11; return 0; } diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 812c1565114f..f96f74bff6ad 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -1803,12 +1803,12 @@ static void nvme_release(struct gendisk *disk) nvme_ns_release(disk->private_data); } -int nvme_getgeo(struct block_device *bdev, struct hd_geometry *geo) +int nvme_getgeo(struct gendisk *disk, struct hd_geometry *geo) { /* some standard values */ geo->heads = 1 << 6; geo->sectors = 1 << 5; - geo->cylinders = get_capacity(bdev->bd_disk) >> 11; + geo->cylinders = get_capacity(disk) >> 11; return 0; } diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index cfd2b5b90b91..102fae6a231c 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -936,7 +936,7 @@ int nvme_ns_head_chr_uring_cmd(struct io_uring_cmd *ioucmd, unsigned int issue_flags); int nvme_identify_ns(struct nvme_ctrl *ctrl, unsigned nsid, struct nvme_id_ns **id); -int nvme_getgeo(struct block_device *bdev, struct hd_geometry *geo); +int nvme_getgeo(struct gendisk *disk, struct hd_geometry *geo); int nvme_dev_uring_cmd(struct io_uring_cmd *ioucmd, unsigned int issue_flags); extern const struct attribute_group *nvme_ns_attr_groups[]; diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 506a947d00a5..582ac7e61b24 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -3317,11 +3317,11 @@ static void dasd_release(struct gendisk *disk) /* * Return disk geometry. */ -static int dasd_getgeo(struct block_device *bdev, struct hd_geometry *geo) +static int dasd_getgeo(struct gendisk *disk, struct hd_geometry *geo) { struct dasd_device *base; - base = dasd_device_from_gendisk(bdev->bd_disk); + base = dasd_device_from_gendisk(disk); if (!base) return -ENODEV; @@ -3331,7 +3331,8 @@ static int dasd_getgeo(struct block_device *bdev, struct hd_geometry *geo) return -EINVAL; } base->discipline->fill_geometry(base->block, geo); - geo->start = get_start_sect(bdev) >> base->block->s2b_shift; + // geo->start is left unchanged by the above + geo->start >>= base->block->s2b_shift; dasd_put_device(base); return 0; } diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 3edcc43f180b..00ad574ce61c 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1599,9 +1599,9 @@ static void sd_release(struct gendisk *disk) scsi_device_put(sdev); } -static int sd_getgeo(struct block_device *bdev, struct hd_geometry *geo) +static int sd_getgeo(struct gendisk *disk, struct hd_geometry *geo) { - struct scsi_disk *sdkp = scsi_disk(bdev->bd_disk); + struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_device *sdp = sdkp->device; struct Scsi_Host *host = sdp->host; sector_t capacity = logical_to_sectors(sdp, sdkp->capacity); @@ -1614,9 +1614,9 @@ static int sd_getgeo(struct block_device *bdev, struct hd_geometry *geo) /* override with calculated, extended default, or driver values */ if (host->hostt->bios_param) - host->hostt->bios_param(sdp, bdev->bd_disk, capacity, diskinfo); + host->hostt->bios_param(sdp, disk, capacity, diskinfo); else - scsicam_bios_param(bdev->bd_disk, capacity, diskinfo); + scsicam_bios_param(disk, capacity, diskinfo); geo->heads = diskinfo[0]; geo->sectors = diskinfo[1]; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 95886b404b16..fbc45121cd4f 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -1659,7 +1659,7 @@ struct block_device_operations { unsigned int (*check_events) (struct gendisk *disk, unsigned int clearing); void (*unlock_native_capacity) (struct gendisk *); - int (*getgeo)(struct block_device *, struct hd_geometry *); + int (*getgeo)(struct gendisk *, struct hd_geometry *); int (*set_read_only)(struct block_device *bdev, bool ro); void (*free_disk)(struct gendisk *disk); /* this callback is with swap_lock and sometimes page table lock held */ From 148547000cfc1ba8cec02857268333d08724b9cc Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 13 Aug 2025 08:38:27 +0300 Subject: [PATCH 00605/11391] gpio: aggregator: Fix off by one in gpiochip_fwd_desc_add() The "> chip->ngpio" comparison here needs to be ">= chip->ngpio", otherwise it leads to an out of bounds access. The fwd->valid_mask bitmap only has chip->ngpio bits and the fwd->descs[] array has that same number of elements. These values are set in devm_gpiochip_fwd_alloc(). Fixes: c44ce91b8ada ("gpio: aggregator: refactor the code to add GPIO desc in the forwarder") Signed-off-by: Dan Carpenter Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/aJwk0yBSCccGCjX3@stanley.mountain Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-aggregator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index 0ef6556f98b1..37600faf4a4b 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -744,7 +744,7 @@ int gpiochip_fwd_desc_add(struct gpiochip_fwd *fwd, struct gpio_desc *desc, { struct gpio_chip *chip = &fwd->chip; - if (offset > chip->ngpio) + if (offset >= chip->ngpio) return -EINVAL; if (test_and_set_bit(offset, fwd->valid_mask)) From 6744085079e785dae5f7a2239456135407c58b25 Mon Sep 17 00:00:00 2001 From: Zhen Ni Date: Wed, 6 Aug 2025 10:55:38 +0800 Subject: [PATCH 00606/11391] memory: samsung: exynos-srom: Fix of_iomap leak in exynos_srom_probe The of_platform_populate() call at the end of the function has a possible failure path, causing a resource leak. Replace of_iomap() with devm_platform_ioremap_resource() to ensure automatic cleanup of srom->reg_base. This issue was detected by smatch static analysis: drivers/memory/samsung/exynos-srom.c:155 exynos_srom_probe()warn: 'srom->reg_base' from of_iomap() not released on lines: 155. Fixes: 8ac2266d8831 ("memory: samsung: exynos-srom: Add support for bank configuration") Cc: stable@vger.kernel.org Signed-off-by: Zhen Ni Link: https://lore.kernel.org/r/20250806025538.306593-1-zhen.ni@easystack.cn Signed-off-by: Krzysztof Kozlowski --- drivers/memory/samsung/exynos-srom.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/memory/samsung/exynos-srom.c b/drivers/memory/samsung/exynos-srom.c index e73dd330af47..d913fb901973 100644 --- a/drivers/memory/samsung/exynos-srom.c +++ b/drivers/memory/samsung/exynos-srom.c @@ -121,20 +121,18 @@ static int exynos_srom_probe(struct platform_device *pdev) return -ENOMEM; srom->dev = dev; - srom->reg_base = of_iomap(np, 0); - if (!srom->reg_base) { + srom->reg_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(srom->reg_base)) { dev_err(&pdev->dev, "iomap of exynos srom controller failed\n"); - return -ENOMEM; + return PTR_ERR(srom->reg_base); } platform_set_drvdata(pdev, srom); srom->reg_offset = exynos_srom_alloc_reg_dump(exynos_srom_offsets, ARRAY_SIZE(exynos_srom_offsets)); - if (!srom->reg_offset) { - iounmap(srom->reg_base); + if (!srom->reg_offset) return -ENOMEM; - } for_each_child_of_node(np, child) { if (exynos_srom_configure_bank(srom, child)) { From 3b745d0b3dc18cd1e6344c97d61b3b1872c57219 Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Thu, 31 Jul 2025 18:45:32 -0500 Subject: [PATCH 00607/11391] arm64: dts: exynos: Add Ethernet node for E850-96 board The E850-96 board has a hard-wired LAN9514 chip which acts as a USB hub and Ethernet bridge. It's being discovered dynamically when the USB bus gets enumerated, but the corresponding Ethernet device tree node is still needed for the bootloader to pass the MAC address through. Add LAN9514 nodes as described in [1]. 'local-mac-address' property (in the 'ethernet' node) is used for MAC address handover from the bootloader to Linux. [1] Documentation/devicetree/bindings/net/microchip,lan95xx.yaml Signed-off-by: Sam Protsenko Link: https://lore.kernel.org/r/20250731234532.12903-1-semen.protsenko@linaro.org Signed-off-by: Krzysztof Kozlowski --- arch/arm64/boot/dts/exynos/exynos850-e850-96.dts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/arm64/boot/dts/exynos/exynos850-e850-96.dts b/arch/arm64/boot/dts/exynos/exynos850-e850-96.dts index 7d70a32e75b2..ab076d326a49 100644 --- a/arch/arm64/boot/dts/exynos/exynos850-e850-96.dts +++ b/arch/arm64/boot/dts/exynos/exynos850-e850-96.dts @@ -21,6 +21,7 @@ / { compatible = "winlink,e850-96", "samsung,exynos850"; aliases { + ethernet0 = ðernet; mmc0 = &mmc_0; serial0 = &serial_0; }; @@ -241,10 +242,24 @@ &usbdrd { }; &usbdrd_dwc3 { + #address-cells = <1>; + #size-cells = <0>; dr_mode = "otg"; usb-role-switch; role-switch-default-mode = "host"; + hub@1 { + compatible = "usb424,9514"; + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + ethernet: ethernet@1 { + compatible = "usb424,ec00"; + reg = <1>; + }; + }; + port { usb1_drd_sw: endpoint { remote-endpoint = <&usb_dr_connector>; From 1aba1eab0bd896928ae20dbf1f60a175a6e1ad0f Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 29 Jul 2025 13:52:12 -0700 Subject: [PATCH 00608/11391] dt-bindings: memory: Update brcmstb-memc-ddr binding with older chips The older MIPS-based chips incorporated a memory controller with the revision A.0.0, update the binding to list that compatible. Signed-off-by: Florian Fainelli Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250729205213.3392481-2-florian.fainelli@broadcom.com Signed-off-by: Krzysztof Kozlowski --- .../bindings/memory-controllers/brcm,brcmstb-memc-ddr.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/memory-controllers/brcm,brcmstb-memc-ddr.yaml b/Documentation/devicetree/bindings/memory-controllers/brcm,brcmstb-memc-ddr.yaml index b935894bd4fc..3328c8df8190 100644 --- a/Documentation/devicetree/bindings/memory-controllers/brcm,brcmstb-memc-ddr.yaml +++ b/Documentation/devicetree/bindings/memory-controllers/brcm,brcmstb-memc-ddr.yaml @@ -42,6 +42,10 @@ properties: items: - const: brcm,brcmstb-memc-ddr-rev-b.1.x - const: brcm,brcmstb-memc-ddr + - description: Revision 0.x controllers + items: + - const: brcm,brcmstb-memc-ddr-rev-a.0.0 + - const: brcm,brcmstb-memc-ddr reg: maxItems: 1 From ad211501fff48d0cda35dd187aa7e356a4fb5581 Mon Sep 17 00:00:00 2001 From: Igor Belwon Date: Thu, 10 Jul 2025 18:50:05 +0200 Subject: [PATCH 00609/11391] arm64: dts: exynos990: Enable watchdog timer Enable the two watchdog timer clusters (cl0, cl2) present on the Exynos990 SoC. Signed-off-by: Igor Belwon Link: https://lore.kernel.org/r/20250710-resends-july-exynos990-dt-v2-1-55033f73d1b0@mentallysanemainliners.org Signed-off-by: Krzysztof Kozlowski --- arch/arm64/boot/dts/exynos/exynos990.dtsi | 24 +++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/arm64/boot/dts/exynos/exynos990.dtsi b/arch/arm64/boot/dts/exynos/exynos990.dtsi index dd7f99f51a75..4446a1a54ba2 100644 --- a/arch/arm64/boot/dts/exynos/exynos990.dtsi +++ b/arch/arm64/boot/dts/exynos/exynos990.dtsi @@ -211,6 +211,30 @@ timer@10040000 { ; }; + watchdog_cl0: watchdog@10050000 { + compatible = "samsung,exynos990-wdt"; + reg = <0x10050000 0x100>; + interrupts = ; + clocks = <&cmu_peris CLK_GOUT_PERIS_WDT_CLUSTER0_PCLK>, + <&oscclk>; + clock-names = "watchdog", + "watchdog_src"; + samsung,syscon-phandle = <&pmu_system_controller>; + samsung,cluster-index = <0>; + }; + + watchdog_cl2: watchdog@10060000 { + compatible = "samsung,exynos990-wdt"; + reg = <0x10060000 0x100>; + interrupts = ; + clocks = <&cmu_peris CLK_GOUT_PERIS_WDT_CLUSTER2_PCLK>, + <&oscclk>; + clock-names = "watchdog", + "watchdog_src"; + samsung,syscon-phandle = <&pmu_system_controller>; + samsung,cluster-index = <2>; + }; + gic: interrupt-controller@10101000 { compatible = "arm,gic-400"; reg = <0x10101000 0x1000>, From d3830b5b0db59d0b8e33083462e4c0dd021ed300 Mon Sep 17 00:00:00 2001 From: Igor Belwon Date: Thu, 10 Jul 2025 18:50:06 +0200 Subject: [PATCH 00610/11391] arm64: dts: exynos990: Add USB nodes Add USB controller and USB PHY controller nodes for use in the Exynos990 SoC. This SoC supports USB full-speed, high-speed and super-speed modes. Due to the inability to test PIPE3, USB super-speed is not enabled, and the USB PHY is only configured for UTMI+ operation for now. Signed-off-by: Igor Belwon Link: https://lore.kernel.org/r/20250710-resends-july-exynos990-dt-v2-2-55033f73d1b0@mentallysanemainliners.org Signed-off-by: Krzysztof Kozlowski --- arch/arm64/boot/dts/exynos/exynos990.dtsi | 31 +++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/arch/arm64/boot/dts/exynos/exynos990.dtsi b/arch/arm64/boot/dts/exynos/exynos990.dtsi index 4446a1a54ba2..bd5e086ac46d 100644 --- a/arch/arm64/boot/dts/exynos/exynos990.dtsi +++ b/arch/arm64/boot/dts/exynos/exynos990.dtsi @@ -278,6 +278,37 @@ cmu_hsi0: clock-controller@10a00000 { "dpgtc"; }; + usbdrd_phy: phy@10c00000 { + compatible = "samsung,exynos990-usbdrd-phy"; + reg = <0x10c00000 0x100>; + clocks = <&cmu_hsi0 CLK_GOUT_HSI0_USB31DRD_ACLK_PHYCTRL>, + <&oscclk>; + clock-names = "phy", "ref"; + samsung,pmu-syscon = <&pmu_system_controller>; + #phy-cells = <1>; + status = "disabled"; + }; + + usbdrd: usb@10e00000 { + compatible = "samsung,exynos990-dwusb3", + "samsung,exynos850-dwusb3"; + ranges = <0x0 0x10e00000 0x10000>; + clocks = <&cmu_hsi0 CLK_GOUT_HSI0_USB31DRD_BUS_CLK_EARLY>, + <&cmu_hsi0 CLK_GOUT_HSI0_USB31DRD_USB31DRD_REF_CLK_40>; + clock-names = "bus_early", "ref"; + #address-cells = <1>; + #size-cells = <1>; + status = "disabled"; + + usbdrd_dwc3: usb@0 { + compatible = "snps,dwc3"; + reg = <0x0 0x10000>; + interrupts = ; + phys = <&usbdrd_phy 0>; + phy-names = "usb2-phy"; + }; + }; + pinctrl_hsi1: pinctrl@13040000 { compatible = "samsung,exynos990-pinctrl"; reg = <0x13040000 0x1000>; From 707181264badf4f82c78c18348684cd06db31ce0 Mon Sep 17 00:00:00 2001 From: Igor Belwon Date: Thu, 10 Jul 2025 18:50:07 +0200 Subject: [PATCH 00611/11391] arm64: dts: exynos990-x1s-common: Enable USB The x1s family uses a shared USB configuration. Enable both the USB PHY as well as the DWC3 controller. Since we do not have any PMIC for USB implemented yet, use dummy regulators until we do. Signed-off-by: Igor Belwon Link: https://lore.kernel.org/r/20250710-resends-july-exynos990-dt-v2-3-55033f73d1b0@mentallysanemainliners.org Signed-off-by: Krzysztof Kozlowski --- .../boot/dts/exynos/exynos990-x1s-common.dtsi | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/arm64/boot/dts/exynos/exynos990-x1s-common.dtsi b/arch/arm64/boot/dts/exynos/exynos990-x1s-common.dtsi index 55fa8e9e05db..7b97220cccb7 100644 --- a/arch/arm64/boot/dts/exynos/exynos990-x1s-common.dtsi +++ b/arch/arm64/boot/dts/exynos/exynos990-x1s-common.dtsi @@ -27,6 +27,12 @@ framebuffer0: framebuffer@f1000000 { }; }; + /* TODO: Remove this once PMIC is implemented */ + reg_dummy: regulator-0 { + compatible = "regulator-fixed"; + regulator-name = "dummy_reg"; + }; + reserved-memory { #address-cells = <2>; #size-cells = <2>; @@ -96,3 +102,13 @@ key_volup: key-volup-pins { samsung,pin-drv = ; }; }; + +&usbdrd { + status = "okay"; + vdd10-supply = <®_dummy>; + vdd33-supply = <®_dummy>; +}; + +&usbdrd_phy { + status = "okay"; +}; From 32532687a9ce2f1c5556e082f957200a81ba0ad7 Mon Sep 17 00:00:00 2001 From: Igor Belwon Date: Thu, 10 Jul 2025 18:50:08 +0200 Subject: [PATCH 00612/11391] arm64: dts: exynos990-c1s: Enable USB Enable both the USB PHY as well as the DWC3 controller nodes. Since we do not have any PMIC for USB implemented yet, use dummy regulators until we do. Signed-off-by: Igor Belwon Link: https://lore.kernel.org/r/20250710-resends-july-exynos990-dt-v2-4-55033f73d1b0@mentallysanemainliners.org Signed-off-by: Krzysztof Kozlowski --- arch/arm64/boot/dts/exynos/exynos990-c1s.dts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/arm64/boot/dts/exynos/exynos990-c1s.dts b/arch/arm64/boot/dts/exynos/exynos990-c1s.dts index 36a6f1377e92..9f0ad4f9673a 100644 --- a/arch/arm64/boot/dts/exynos/exynos990-c1s.dts +++ b/arch/arm64/boot/dts/exynos/exynos990-c1s.dts @@ -44,6 +44,12 @@ memory@80000000 { <0x8 0x80000000 0x1 0x7ec00000>; }; + /* TODO: Remove this once PMIC is implemented */ + reg_dummy: regulator-0 { + compatible = "regulator-fixed"; + regulator-name = "dummy_reg"; + }; + reserved-memory { #address-cells = <2>; #size-cells = <2>; @@ -113,3 +119,13 @@ key_volup: key-volup-pins { samsung,pin-drv = ; }; }; + +&usbdrd { + status = "okay"; + vdd10-supply = <®_dummy>; + vdd33-supply = <®_dummy>; +}; + +&usbdrd_phy { + status = "okay"; +}; From e28c1117deda5a80df14b579170c1a90fc82bf5f Mon Sep 17 00:00:00 2001 From: Igor Belwon Date: Thu, 10 Jul 2025 18:50:09 +0200 Subject: [PATCH 00613/11391] arm64: dts: exynos990-r8s: Enable USB Enable both the USB PHY as well as the DWC3 controller nodes. Since we do not have any PMIC for USB implemented yet, use dummy regulators until we do. Signed-off-by: Igor Belwon Link: https://lore.kernel.org/r/20250710-resends-july-exynos990-dt-v2-5-55033f73d1b0@mentallysanemainliners.org Signed-off-by: Krzysztof Kozlowski --- arch/arm64/boot/dts/exynos/exynos990-r8s.dts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/arm64/boot/dts/exynos/exynos990-r8s.dts b/arch/arm64/boot/dts/exynos/exynos990-r8s.dts index 6bae3c0ecc1c..55342db61979 100644 --- a/arch/arm64/boot/dts/exynos/exynos990-r8s.dts +++ b/arch/arm64/boot/dts/exynos/exynos990-r8s.dts @@ -44,6 +44,12 @@ memory@80000000 { <0x8 0x80000000 0x0 0xc0000000>; }; + /* TODO: Remove this once PMIC is implemented */ + reg_dummy: regulator-0 { + compatible = "regulator-fixed"; + regulator-name = "dummy_reg"; + }; + reserved-memory { #address-cells = <2>; #size-cells = <2>; @@ -113,3 +119,13 @@ key_volup: key-volup-pins { samsung,pin-drv = ; }; }; + +&usbdrd { + status = "okay"; + vdd10-supply = <®_dummy>; + vdd33-supply = <®_dummy>; +}; + +&usbdrd_phy { + status = "okay"; +}; From aaa76d1cbd73a7e8ddb9d92423b017eb98d2b335 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 11 Aug 2025 10:02:34 +0300 Subject: [PATCH 00614/11391] 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 8abbbbb588f1f1bf95ae56c1531a17520ce487e2 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 11 Aug 2025 22:27:22 +0900 Subject: [PATCH 00615/11391] platform/chrome: cros_ec: Avoid -Wflex-array-member-not-at-end warning -Wflex-array-member-not-at-end was introduced in GCC-14, and we are getting ready to enable it, globally. Use the new TRAILING_OVERLAP() helper to fix the following warning: drivers/platform/chrome/cros_ec.c:106:40: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end] This helper creates a union between a flexible-array member (FAM) and a set of members that would otherwise follow it. This overlays the trailing members onto the FAM while preserving the original memory layout. Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/aJnvuv334M7TljoB@kspp Signed-off-by: Tzung-Bi Shih --- drivers/platform/chrome/cros_ec.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/platform/chrome/cros_ec.c b/drivers/platform/chrome/cros_ec.c index fd58781a2fb7..b1730362e399 100644 --- a/drivers/platform/chrome/cros_ec.c +++ b/drivers/platform/chrome/cros_ec.c @@ -102,14 +102,13 @@ EXPORT_SYMBOL(cros_ec_irq_thread); static int cros_ec_sleep_event(struct cros_ec_device *ec_dev, u8 sleep_event) { int ret; - struct { - struct cros_ec_command msg; + TRAILING_OVERLAP(struct cros_ec_command, msg, data, union { struct ec_params_host_sleep_event req0; struct ec_params_host_sleep_event_v1 req1; struct ec_response_host_sleep_event_v1 resp1; } u; - } __packed buf; + ) __packed buf; memset(&buf, 0, sizeof(buf)); From f7439a723e5aa5b35c76355e1b9b2cd1108f656e Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Wed, 13 Aug 2025 17:48:55 +0800 Subject: [PATCH 00616/11391] platform/chrome: wilco_ec: Remove redundant semicolons Remove unnecessary semicolons. Signed-off-by: Liao Yuanhong Link: https://lore.kernel.org/r/20250813094858.557742-1-liaoyuanhong@vivo.com Signed-off-by: Tzung-Bi Shih --- drivers/platform/chrome/wilco_ec/telemetry.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/chrome/wilco_ec/telemetry.c b/drivers/platform/chrome/wilco_ec/telemetry.c index 7d8ae2cbf72f..b18043e31ae4 100644 --- a/drivers/platform/chrome/wilco_ec/telemetry.c +++ b/drivers/platform/chrome/wilco_ec/telemetry.c @@ -388,7 +388,7 @@ static int telem_device_probe(struct platform_device *pdev) dev_set_name(&dev_data->dev, TELEM_DEV_NAME_FMT, minor); device_initialize(&dev_data->dev); - /* Initialize the character device and add it to userspace */; + /* Initialize the character device and add it to userspace */ cdev_init(&dev_data->cdev, &telem_fops); error = cdev_device_add(&dev_data->cdev, &dev_data->dev); if (error) { From d0de6895095356f1cc2d5f9825df220f10d34cee Mon Sep 17 00:00:00 2001 From: Jeff Chang Date: Wed, 13 Aug 2025 10:08:50 +0800 Subject: [PATCH 00617/11391] regulator: dt-bindings: Add Richtek RT5133 Support Add bindings for Richtek RT5133 IC Controlled PMIC Signed-off-by: Jeff Chang Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250813020910.2977555-1-jeff_chang@richtek.com Signed-off-by: Mark Brown --- .../bindings/regulator/richtek,rt5133.yaml | 178 ++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/richtek,rt5133.yaml diff --git a/Documentation/devicetree/bindings/regulator/richtek,rt5133.yaml b/Documentation/devicetree/bindings/regulator/richtek,rt5133.yaml new file mode 100644 index 000000000000..d2e007fee6ba --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/richtek,rt5133.yaml @@ -0,0 +1,178 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/richtek,rt5133.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Richtek RT5133 PMIC Regulator + +maintainers: + - ShihChia Chang + +description: + The RT5133 is an integrated Power Management IC for portable devices, + featuring 8 LDOs and 3 GPOs. It allows programmable output voltages, + soft-start times, and protections via I2C. GPO operation depends on LDO1 + voltage. + +properties: + compatible: + enum: + - richtek,rt5133 + + reg: + maxItems: 1 + + enable-gpios: + maxItems: 1 + + wakeup-source: true + + interrupts: + maxItems: 1 + + gpio-controller: true + + "#gpio-cells": + const: 2 + + richtek,oc-shutdown-all: + type: boolean + description: + Controls the behavior when any LDO (Low Dropout Regulator) enters an + Over Current state. + If set to true, all LDO channels will be shut down. + If set to false, only the affected LDO channel will shut down itself. + + richtek,pgb-shutdown-all: + type: boolean + description: + Controls the behavior when any LDO enters a Power Good Bad state. + If set to true, all LDO channels will be shut down. + If set to false, only the affected LDO channel will shut down itself. + + regulators: + type: object + additionalProperties: false + + properties: + base: + type: object + $ref: regulator.yaml# + unevaluatedProperties: false + description: + Properties for the base regulator, which is the top-level supply for + LDO1 to LDO6. It functions merely as an on/off switch rather than + regulating voltages. If none of LDO1 to LDO6 are in use, switching + off the base will reduce the quiescent current. + + required: + - regulator-name + + patternProperties: + "^ldo([1-6])$": + type: object + $ref: regulator.yaml# + unevaluatedProperties: false + description: + Properties for single LDO regulator + + required: + - regulator-name + + "^ldo([7-8])$": + type: object + $ref: regulator.yaml# + unevaluatedProperties: false + description: + Properties for single LDO regulator + + properties: + vin-supply: true + + required: + - regulator-name + - vin-supply + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - | + #include + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + pmic@18 { + compatible = "richtek,rt5133"; + reg = <0x18>; + wakeup-source; + interrupts-extended = <&gpio 0 IRQ_TYPE_EDGE_FALLING>; + enable-gpios = <&gpio 2 GPIO_ACTIVE_HIGH>; + gpio-controller; + #gpio-cells = <2>; + richtek,oc-shutdown-all; + richtek,pgb-shutdown-all; + regulators { + base { + regulator-name = "base"; + }; + pvin78: ldo1 { + regulator-name = "ldo1"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3199998>; + regulator-active-discharge = <1>; + }; + ldo2 { + regulator-name = "ldo2"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3200000>; + regulator-active-discharge = <1>; + }; + ldo3 { + regulator-name = "ldo3"; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <3000000>; + regulator-active-discharge = <1>; + }; + ldo4 { + regulator-name = "ldo4"; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <3000000>; + regulator-active-discharge = <1>; + }; + ldo5 { + regulator-name = "ldo5"; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <3000000>; + regulator-active-discharge = <1>; + }; + ldo6 { + regulator-name = "ldo6"; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <3000000>; + regulator-active-discharge = <1>; + }; + ldo7 { + regulator-name = "ldo7"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1200000>; + regulator-active-discharge = <1>; + vin-supply = <&pvin78>; + }; + ldo8 { + regulator-name = "ldo8"; + regulator-min-microvolt = <855000>; + regulator-max-microvolt = <1200000>; + regulator-active-discharge = <1>; + vin-supply = <&pvin78>; + }; + }; + }; + }; From 714165e1c4b0d5b8c6d095fe07f65e6e7047aaeb Mon Sep 17 00:00:00 2001 From: Jeff Chang Date: Wed, 13 Aug 2025 10:08:51 +0800 Subject: [PATCH 00618/11391] regulator: rt5133: Add RT5133 PMIC regulator Support RT5133 is a highly-integrated chip. It includes 8 LDOs and 3 GPOs that can be used to drive output high/low purpose. The dependency of the GPO block is internally LDO1 Voltage. Signed-off-by: Jeff Chang Link: https://patch.msgid.link/20250813020910.2977555-2-jeff_chang@richtek.com Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 12 + drivers/regulator/Makefile | 1 + drivers/regulator/rt5133-regulator.c | 642 +++++++++++++++++++++++++++ 3 files changed, 655 insertions(+) create mode 100644 drivers/regulator/rt5133-regulator.c diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index e511174be7bf..223a500370d0 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -1248,6 +1248,18 @@ config REGULATOR_RT5120 600mV to 1395mV, per step 6.250mV. The others are all fixed voltage by external hardware circuit. +config REGULATOR_RT5133 + tristate "Richtek RT5133 PMIC Regulators" + depends on I2C && GPIOLIB && OF + select REGMAP + select CRC8 + select OF_GPIO + help + This driver adds support for RT5133 PMIC regulators. + RT5133 is an integrated chip. It includes 8 LDOs and 3 GPOs that + can be used to drive output high/low purpose. The dependency of the + GPO block is internally LDO1 Voltage. + config REGULATOR_RT5190A tristate "Richtek RT5190A PMIC" depends on I2C diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 80f820ed22a3..54e67e1c0c67 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -147,6 +147,7 @@ obj-$(CONFIG_REGULATOR_RT4803) += rt4803.o obj-$(CONFIG_REGULATOR_RT4831) += rt4831-regulator.o obj-$(CONFIG_REGULATOR_RT5033) += rt5033-regulator.o obj-$(CONFIG_REGULATOR_RT5120) += rt5120-regulator.o +obj-$(CONFIG_REGULATOR_RT5133) += rt5133-regulator.o obj-$(CONFIG_REGULATOR_RT5190A) += rt5190a-regulator.o obj-$(CONFIG_REGULATOR_RT5739) += rt5739.o obj-$(CONFIG_REGULATOR_RT5759) += rt5759-regulator.o diff --git a/drivers/regulator/rt5133-regulator.c b/drivers/regulator/rt5133-regulator.c new file mode 100644 index 000000000000..d0f367381fbb --- /dev/null +++ b/drivers/regulator/rt5133-regulator.c @@ -0,0 +1,642 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2025 Richtek Technology Corp. +// Author: ChiYuan Huang +// Author: ShihChia Chang + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RT5133_REG_CHIP_INFO 0x00 +#define RT5133_REG_RST_CTRL 0x06 +#define RT5133_REG_BASE_CTRL 0x09 +#define RT5133_REG_GPIO_CTRL 0x0B +#define RT5133_REG_BASE_EVT 0x10 +#define RT5133_REG_LDO_PGB_STAT 0x15 +#define RT5133_REG_BASE_MASK 0x16 +#define RT5133_REG_LDO_SHDN 0x19 +#define RT5133_REG_LDO_ON 0x1A +#define RT5133_REG_LDO_OFF 0x1B +#define RT5133_REG_LDO1_CTRL1 0x20 +#define RT5133_REG_LDO1_CTRL2 0x21 +#define RT5133_REG_LDO1_CTRL3 0x22 +#define RT5133_REG_LDO2_CTRL1 0x24 +#define RT5133_REG_LDO2_CTRL2 0x25 +#define RT5133_REG_LDO2_CTRL3 0x26 +#define RT5133_REG_LDO3_CTRL1 0x28 +#define RT5133_REG_LDO3_CTRL2 0x29 +#define RT5133_REG_LDO3_CTRL3 0x2A +#define RT5133_REG_LDO4_CTRL1 0x2C +#define RT5133_REG_LDO4_CTRL2 0x2D +#define RT5133_REG_LDO4_CTRL3 0x2E +#define RT5133_REG_LDO5_CTRL1 0x30 +#define RT5133_REG_LDO5_CTRL2 0x31 +#define RT5133_REG_LDO5_CTRL3 0x32 +#define RT5133_REG_LDO6_CTRL1 0x34 +#define RT5133_REG_LDO6_CTRL2 0x35 +#define RT5133_REG_LDO6_CTRL3 0x36 +#define RT5133_REG_LDO7_CTRL1 0x38 +#define RT5133_REG_LDO7_CTRL2 0x39 +#define RT5133_REG_LDO7_CTRL3 0x3A +#define RT5133_REG_LDO8_CTRL1 0x3C +#define RT5133_REG_LDO8_CTRL2 0x3D +#define RT5133_REG_LDO8_CTRL3 0x3E +#define RT5133_REG_LDO8_CTRL4 0x3F + +#define RT5133_LDO_REG_BASE(_id) (0x20 + ((_id) - 1) * 4) + +#define RT5133_VENDOR_ID_MASK GENMASK(7, 4) +#define RT5133_RESET_CODE 0xB1 + +#define RT5133_FOFF_BASE_MASK BIT(1) +#define RT5133_OCSHDN_ALL_MASK BIT(7) +#define RT5133_OCSHDN_ALL_SHIFT (7) +#define RT5133_PGBSHDN_ALL_MASK BIT(6) +#define RT5133_PGBSHDN_ALL_SHIFT (6) + +#define RT5133_OCPTSEL_MASK BIT(5) +#define RT5133_PGBPTSEL_MASK BIT(4) +#define RT5133_STBTDSEL_MASK GENMASK(1, 0) + +#define RT5133_LDO_ENABLE_MASK BIT(7) +#define RT5133_LDO_VSEL_MASK GENMASK(7, 5) +#define RT5133_LDO_AD_MASK BIT(2) +#define RT5133_LDO_SOFT_START_MASK GENMASK(1, 0) + +#define RT5133_GPIO_NR 3 + +#define RT5133_LDO_PGB_EVT_MASK GENMASK(23, 16) +#define RT5133_LDO_PGB_EVT_SHIFT 16 +#define RT5133_LDO_OC_EVT_MASK GENMASK(15, 8) +#define RT5133_LDO_OC_EVT_SHIFT 8 +#define RT5133_VREF_EVT_MASK BIT(6) +#define RT5133_BASE_EVT_MASK GENMASK(7, 0) +#define RT5133_INTR_CLR_MASK GENMASK(23, 0) +#define RT5133_INTR_BYTE_NR 3 + +#define RT5133_MAX_I2C_BLOCK_SIZE 1 + +#define RT5133_CRC8_POLYNOMIAL 0x7 + +#define RT5133_I2C_ADDR_LEN 1 +#define RT5133_PREDATA_LEN 2 +#define RT5133_I2C_CRC_LEN 1 +#define RT5133_REG_ADDR_LEN 1 +#define RT5133_I2C_DUMMY_LEN 1 + +#define I2C_ADDR_XLATE_8BIT(_addr, _rw) ((((_addr) & 0x7F) << 1) | (_rw)) + +enum { + RT5133_REGULATOR_BASE = 0, + RT5133_REGULATOR_LDO1, + RT5133_REGULATOR_LDO2, + RT5133_REGULATOR_LDO3, + RT5133_REGULATOR_LDO4, + RT5133_REGULATOR_LDO5, + RT5133_REGULATOR_LDO6, + RT5133_REGULATOR_LDO7, + RT5133_REGULATOR_LDO8, + RT5133_REGULATOR_MAX +}; + +struct chip_data { + const struct regulator_desc *regulators; + const u8 vendor_id; +}; + +struct rt5133_priv { + struct device *dev; + struct regmap *regmap; + struct gpio_desc *enable_gpio; + struct regulator_dev *rdev[RT5133_REGULATOR_MAX]; + struct gpio_chip gc; + const struct chip_data *cdata; + unsigned int gpio_output_flag; + u8 crc8_tbls[CRC8_TABLE_SIZE]; +}; + +static const unsigned int vout_type1_tables[] = { + 1800000, 2500000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000 +}; + +static const unsigned int vout_type2_tables[] = { + 1700000, 1800000, 1900000, 2500000, 2700000, 2800000, 2900000, 3000000 +}; + +static const unsigned int vout_type3_tables[] = { + 900000, 950000, 1000000, 1050000, 1100000, 1150000, 1200000, 1800000 +}; + +static const unsigned int vout_type4_tables[] = { + 855000, 900000, 950000, 1000000, 1040000, 1090000, 1140000, 1710000 +}; + +static const struct regulator_ops rt5133_regulator_ops = { + .list_voltage = regulator_list_voltage_table, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_active_discharge = regulator_set_active_discharge_regmap, +}; + +static const struct regulator_ops rt5133_base_regulator_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +#define RT5133_REGULATOR_DESC(_name, _node_name, vtables, _supply) \ +{\ + .name = #_name,\ + .id = RT5133_REGULATOR_##_name,\ + .of_match = of_match_ptr(#_node_name),\ + .regulators_node = of_match_ptr("regulators"),\ + .supply_name = _supply,\ + .type = REGULATOR_VOLTAGE,\ + .owner = THIS_MODULE,\ + .ops = &rt5133_regulator_ops,\ + .n_voltages = ARRAY_SIZE(vtables),\ + .volt_table = vtables,\ + .enable_reg = RT5133_REG_##_name##_CTRL1,\ + .enable_mask = RT5133_LDO_ENABLE_MASK,\ + .vsel_reg = RT5133_REG_##_name##_CTRL2,\ + .vsel_mask = RT5133_LDO_VSEL_MASK,\ + .active_discharge_reg = RT5133_REG_##_name##_CTRL3,\ + .active_discharge_mask = RT5133_LDO_AD_MASK,\ +} + +static const struct regulator_desc rt5133_regulators[] = { + /* For digital part, base current control */ + { + .name = "base", + .id = RT5133_REGULATOR_BASE, + .of_match = of_match_ptr("base"), + .regulators_node = of_match_ptr("regulators"), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .ops = &rt5133_base_regulator_ops, + .enable_reg = RT5133_REG_BASE_CTRL, + .enable_mask = RT5133_FOFF_BASE_MASK, + .enable_is_inverted = true, + }, + RT5133_REGULATOR_DESC(LDO1, ldo1, vout_type1_tables, "base"), + RT5133_REGULATOR_DESC(LDO2, ldo2, vout_type1_tables, "base"), + RT5133_REGULATOR_DESC(LDO3, ldo3, vout_type2_tables, "base"), + RT5133_REGULATOR_DESC(LDO4, ldo4, vout_type2_tables, "base"), + RT5133_REGULATOR_DESC(LDO5, ldo5, vout_type2_tables, "base"), + RT5133_REGULATOR_DESC(LDO6, ldo6, vout_type2_tables, "base"), + RT5133_REGULATOR_DESC(LDO7, ldo7, vout_type3_tables, "vin"), + RT5133_REGULATOR_DESC(LDO8, ldo8, vout_type3_tables, "vin"), +}; + +static const struct regulator_desc rt5133a_regulators[] = { + /* For digital part, base current control */ + { + .name = "base", + .id = RT5133_REGULATOR_BASE, + .of_match = of_match_ptr("base"), + .regulators_node = of_match_ptr("regulators"), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .ops = &rt5133_base_regulator_ops, + .enable_reg = RT5133_REG_BASE_CTRL, + .enable_mask = RT5133_FOFF_BASE_MASK, + .enable_is_inverted = true, + }, + RT5133_REGULATOR_DESC(LDO1, ldo1, vout_type1_tables, "base"), + RT5133_REGULATOR_DESC(LDO2, ldo2, vout_type1_tables, "base"), + RT5133_REGULATOR_DESC(LDO3, ldo3, vout_type2_tables, "base"), + RT5133_REGULATOR_DESC(LDO4, ldo4, vout_type2_tables, "base"), + RT5133_REGULATOR_DESC(LDO5, ldo5, vout_type2_tables, "base"), + RT5133_REGULATOR_DESC(LDO6, ldo6, vout_type2_tables, "base"), + RT5133_REGULATOR_DESC(LDO7, ldo7, vout_type3_tables, "vin"), + RT5133_REGULATOR_DESC(LDO8, ldo8, vout_type4_tables, "vin"), +}; + +static const struct chip_data regulator_data[] = { + { rt5133_regulators, 0x70}, + { rt5133a_regulators, 0x80}, +}; + +static int rt5133_gpio_direction_output(struct gpio_chip *gpio, + unsigned int offset, int value) +{ + struct rt5133_priv *priv = gpiochip_get_data(gpio); + + if (offset >= RT5133_GPIO_NR) + return -EINVAL; + + return regmap_update_bits(priv->regmap, RT5133_REG_GPIO_CTRL, + BIT(7 - offset) | BIT(3 - offset), + value ? BIT(7 - offset) | BIT(3 - offset) : 0); +} + +static int rt5133_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct rt5133_priv *priv = gpiochip_get_data(chip); + + return !!(priv->gpio_output_flag & BIT(offset)); +} + +static int rt5133_get_gpioen_mask(unsigned int offset, unsigned int *mask) +{ + if (offset >= RT5133_GPIO_NR) + return -EINVAL; + + *mask = (BIT(7 - offset) | BIT(3 - offset)); + + return 0; +} + +static int rt5133_gpio_set(struct gpio_chip *chip, unsigned int offset, int set_val) +{ + struct rt5133_priv *priv = gpiochip_get_data(chip); + unsigned int mask = 0, val = 0, next_flag = priv->gpio_output_flag; + int ret = 0; + + ret = rt5133_get_gpioen_mask(offset, &mask); + if (ret) { + dev_err(priv->dev, "%s get gpion en mask failed, offset(%d)\n", __func__, offset); + return ret; + } + + val = set_val ? mask : 0; + + if (set_val) + next_flag |= BIT(offset); + else + next_flag &= ~BIT(offset); + + ret = regmap_update_bits(priv->regmap, RT5133_REG_GPIO_CTRL, mask, val); + if (ret) { + dev_err(priv->dev, "Failed to set gpio [%d] val %d\n", offset, + set_val); + return ret; + } + + priv->gpio_output_flag = next_flag; + return 0; +} + +static irqreturn_t rt5133_intr_handler(int irq_number, void *data) +{ + struct rt5133_priv *priv = data; + u32 intr_evts = 0, handle_evts; + int i, ret; + + ret = regmap_bulk_read(priv->regmap, RT5133_REG_BASE_EVT, &intr_evts, + RT5133_INTR_BYTE_NR); + if (ret) { + dev_err(priv->dev, "%s, read event failed\n", __func__); + return IRQ_NONE; + } + + handle_evts = intr_evts & RT5133_BASE_EVT_MASK; + /* + * VREF_EVT is a special case, if base off + * this event will also be trigger. Skip it + */ + if (handle_evts & ~RT5133_VREF_EVT_MASK) + dev_dbg(priv->dev, "base event occurred [0x%02x]\n", + handle_evts); + + handle_evts = (intr_evts & RT5133_LDO_OC_EVT_MASK) >> + RT5133_LDO_OC_EVT_SHIFT; + + for (i = RT5133_REGULATOR_LDO1; i < RT5133_REGULATOR_MAX && handle_evts; i++) { + if (!(handle_evts & BIT(i - 1))) + continue; + regulator_notifier_call_chain(priv->rdev[i], + REGULATOR_EVENT_OVER_CURRENT, + &i); + } + + handle_evts = (intr_evts & RT5133_LDO_PGB_EVT_MASK) >> + RT5133_LDO_PGB_EVT_SHIFT; + for (i = RT5133_REGULATOR_LDO1; i < RT5133_REGULATOR_MAX && handle_evts; i++) { + if (!(handle_evts & BIT(i - 1))) + continue; + regulator_notifier_call_chain(priv->rdev[i], + REGULATOR_EVENT_FAIL, &i); + } + + ret = regmap_bulk_write(priv->regmap, RT5133_REG_BASE_EVT, &intr_evts, + RT5133_INTR_BYTE_NR); + if (ret) + dev_err(priv->dev, "%s, clear event failed\n", __func__); + + return IRQ_HANDLED; +} + +static int rt5133_enable_interrupts(int irq_no, struct rt5133_priv *priv) +{ + u32 mask = RT5133_INTR_CLR_MASK; + int ret; + + /* Force to write clear all events */ + ret = regmap_bulk_write(priv->regmap, RT5133_REG_BASE_EVT, &mask, + RT5133_INTR_BYTE_NR); + if (ret) { + dev_err(priv->dev, "Failed to clear all interrupts\n"); + return ret; + } + + /* Unmask all interrupts */ + mask = 0; + ret = regmap_bulk_write(priv->regmap, RT5133_REG_BASE_MASK, &mask, + RT5133_INTR_BYTE_NR); + if (ret) { + dev_err(priv->dev, "Failed to unmask all interrupts\n"); + return ret; + } + + return devm_request_threaded_irq(priv->dev, irq_no, NULL, + rt5133_intr_handler, IRQF_ONESHOT, + dev_name(priv->dev), priv); +} + +static int rt5133_regmap_hw_read(void *context, const void *reg_buf, + size_t reg_size, void *val_buf, + size_t val_size) +{ + struct rt5133_priv *priv = context; + struct i2c_client *client = to_i2c_client(priv->dev); + u8 reg = *(u8 *)reg_buf, crc; + u8 *buf; + int buf_len = RT5133_PREDATA_LEN + val_size + RT5133_I2C_CRC_LEN; + int read_len, ret; + + buf = kzalloc(buf_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + buf[0] = I2C_ADDR_XLATE_8BIT(client->addr, I2C_SMBUS_READ); + buf[1] = reg; + + read_len = val_size + RT5133_I2C_CRC_LEN; + ret = i2c_smbus_read_i2c_block_data(client, reg, read_len, + buf + RT5133_PREDATA_LEN); + + if (ret < 0) + goto out_read_err; + + if (ret != read_len) { + ret = -EIO; + goto out_read_err; + } + + crc = crc8(priv->crc8_tbls, buf, RT5133_PREDATA_LEN + val_size, 0); + if (crc != buf[RT5133_PREDATA_LEN + val_size]) { + ret = -EIO; + goto out_read_err; + } + + memcpy(val_buf, buf + RT5133_PREDATA_LEN, val_size); + dev_dbg(priv->dev, "%s, reg = 0x%02x, data = 0x%02x\n", __func__, reg, *(u8 *)val_buf); + +out_read_err: + kfree(buf); + return (ret < 0) ? ret : 0; +} + +static int rt5133_regmap_hw_write(void *context, const void *data, size_t count) +{ + struct rt5133_priv *priv = context; + struct i2c_client *client = to_i2c_client(priv->dev); + u8 reg = *(u8 *)data, crc; + u8 *buf; + int buf_len = RT5133_I2C_ADDR_LEN + count + RT5133_I2C_CRC_LEN + + RT5133_I2C_DUMMY_LEN; + int write_len, ret; + + buf = kzalloc(buf_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + buf[0] = I2C_ADDR_XLATE_8BIT(client->addr, I2C_SMBUS_WRITE); + buf[1] = reg; + memcpy(buf + RT5133_PREDATA_LEN, data + RT5133_REG_ADDR_LEN, + count - RT5133_REG_ADDR_LEN); + + crc = crc8(priv->crc8_tbls, buf, RT5133_I2C_ADDR_LEN + count, 0); + buf[RT5133_I2C_ADDR_LEN + count] = crc; + + write_len = count - RT5133_REG_ADDR_LEN + RT5133_I2C_CRC_LEN + + RT5133_I2C_DUMMY_LEN; + ret = i2c_smbus_write_i2c_block_data(client, reg, write_len, + buf + RT5133_PREDATA_LEN); + + dev_dbg(priv->dev, "%s, reg = 0x%02x, data = 0x%02x\n", __func__, reg, + *(u8 *)(buf + RT5133_PREDATA_LEN)); + kfree(buf); + return ret; +} + +static const struct regmap_bus rt5133_regmap_bus = { + .read = rt5133_regmap_hw_read, + .write = rt5133_regmap_hw_write, + /* Due to crc, the block read/write length has the limit */ + .max_raw_read = RT5133_MAX_I2C_BLOCK_SIZE, + .max_raw_write = RT5133_MAX_I2C_BLOCK_SIZE, +}; + +static bool rt5133_is_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RT5133_REG_CHIP_INFO: + case RT5133_REG_BASE_EVT...RT5133_REG_LDO_PGB_STAT: + case RT5133_REG_LDO_ON...RT5133_REG_LDO_OFF: + case RT5133_REG_LDO1_CTRL1: + case RT5133_REG_LDO2_CTRL1: + case RT5133_REG_LDO3_CTRL1: + case RT5133_REG_LDO4_CTRL1: + case RT5133_REG_LDO5_CTRL1: + case RT5133_REG_LDO6_CTRL1: + case RT5133_REG_LDO7_CTRL1: + case RT5133_REG_LDO8_CTRL1: + return true; + default: + return false; + }; +} + +static const struct regmap_config rt5133_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = RT5133_REG_LDO8_CTRL4, + .cache_type = REGCACHE_FLAT, + .num_reg_defaults_raw = RT5133_REG_LDO8_CTRL4 + 1, + .volatile_reg = rt5133_is_volatile_reg, +}; + +static int rt5133_chip_reset(struct rt5133_priv *priv) +{ + int ret; + + ret = regmap_write(priv->regmap, RT5133_REG_RST_CTRL, + RT5133_RESET_CODE); + if (ret) + return ret; + + /* Wait for register reset to take effect */ + udelay(2); + + return 0; +} + +static int rt5133_validate_vendor_info(struct rt5133_priv *priv) +{ + unsigned int val = 0; + int i, ret; + + ret = regmap_read(priv->regmap, RT5133_REG_CHIP_INFO, &val); + if (ret) + return ret; + + for (i = 0; i < ARRAY_SIZE(regulator_data); i++) { + if ((val & RT5133_VENDOR_ID_MASK) == + regulator_data[i].vendor_id){ + priv->cdata = ®ulator_data[i]; + break; + } + } + if (IS_ERR(priv->cdata)) { + dev_err(priv->dev, "Failed to find regualtor match version\n"); + return -ENODEV; + } + + return 0; +} + +static int rt5133_parse_dt(struct rt5133_priv *priv) +{ + unsigned int val = 0; + int ret = 0; + + if (!device_property_read_bool(priv->dev, "richtek,oc-shutdown-all")) + val = 0; + else + val = 1 << RT5133_OCSHDN_ALL_SHIFT; + ret = regmap_update_bits(priv->regmap, RT5133_REG_LDO_SHDN, + RT5133_OCSHDN_ALL_MASK, val); + if (ret) + return ret; + + if (!device_property_read_bool(priv->dev, "richtek,pgb-shutdown-all")) + val = 0; + else + val = 1 << RT5133_PGBSHDN_ALL_SHIFT; + return regmap_update_bits(priv->regmap, RT5133_REG_LDO_SHDN, + RT5133_PGBSHDN_ALL_MASK, val); +} + +static int rt5133_probe(struct i2c_client *i2c) +{ + struct rt5133_priv *priv; + struct regulator_config config = {0}; + int i, ret; + + priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = &i2c->dev; + crc8_populate_msb(priv->crc8_tbls, RT5133_CRC8_POLYNOMIAL); + + priv->enable_gpio = devm_gpiod_get_optional(&i2c->dev, "enable", + GPIOD_OUT_HIGH); + if (IS_ERR(priv->enable_gpio)) + dev_err(&i2c->dev, "Failed to request HWEN gpio, check if default en=high\n"); + + priv->regmap = devm_regmap_init(&i2c->dev, &rt5133_regmap_bus, priv, + &rt5133_regmap_config); + if (IS_ERR(priv->regmap)) { + dev_err(&i2c->dev, "Failed to register regmap\n"); + return PTR_ERR(priv->regmap); + } + + ret = rt5133_validate_vendor_info(priv); + if (ret) { + dev_err(&i2c->dev, "Failed to check vendor info [%d]\n", ret); + return ret; + } + + ret = rt5133_chip_reset(priv); + if (ret) { + dev_err(&i2c->dev, "Failed to execute sw reset\n"); + return ret; + } + + config.dev = &i2c->dev; + config.driver_data = priv; + config.regmap = priv->regmap; + + for (i = 0; i < RT5133_REGULATOR_MAX; i++) { + priv->rdev[i] = devm_regulator_register(&i2c->dev, + priv->cdata->regulators + i, + &config); + if (IS_ERR(priv->rdev[i])) { + dev_err(&i2c->dev, + "Failed to register [%d] regulator\n", i); + return PTR_ERR(priv->rdev[i]); + } + } + + ret = rt5133_parse_dt(priv); + if (ret) { + dev_err(&i2c->dev, "%s, Failed to parse dt\n", __func__); + return ret; + } + + priv->gc.label = dev_name(&i2c->dev); + priv->gc.parent = &i2c->dev; + priv->gc.base = -1; + priv->gc.ngpio = RT5133_GPIO_NR; + priv->gc.set = rt5133_gpio_set; + priv->gc.get = rt5133_gpio_get; + priv->gc.direction_output = rt5133_gpio_direction_output; + priv->gc.can_sleep = true; + + ret = devm_gpiochip_add_data(&i2c->dev, &priv->gc, priv); + if (ret) + return ret; + + ret = rt5133_enable_interrupts(i2c->irq, priv); + if (ret) { + dev_err(&i2c->dev, "enable interrupt failed\n"); + return ret; + } + + i2c_set_clientdata(i2c, priv); + + return ret; +} + +static const struct of_device_id __maybe_unused rt5133_of_match_table[] = { + { .compatible = "richtek,rt5133", }, + { } +}; +MODULE_DEVICE_TABLE(of, rt5133_of_match_table); + +static struct i2c_driver rt5133_driver = { + .driver = { + .name = "rt5133", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .of_match_table = rt5133_of_match_table, + }, + .probe = rt5133_probe, +}; +module_i2c_driver(rt5133_driver); + +MODULE_DESCRIPTION("RT5133 Regulator Driver"); +MODULE_LICENSE("GPL v2"); From ef5fcdb7300abafd610fd8f815e77dd687eced65 Mon Sep 17 00:00:00 2001 From: Mark Zhang Date: Mon, 30 Jun 2025 13:52:31 +0300 Subject: [PATCH 00619/11391] RDMA/sa_query: Add RMPP support for SA queries Register GSI mad agent with RMPP support and add rmpp_callback for SA queries. This is needed for querying more than one service record in one query. Signed-off-by: Or Har-Toov Signed-off-by: Mark Zhang Reviewed-by: Vlad Dumitrescu Link: https://patch.msgid.link/81dbcb48682e1838dc40f381cdcc0dc63f25f0f1.1751279793.git.leonro@nvidia.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/core/sa_query.c | 39 +++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index 53571e6b3162..770e9f18349b 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -107,6 +107,8 @@ struct ib_sa_device { struct ib_sa_query { void (*callback)(struct ib_sa_query *sa_query, int status, struct ib_sa_mad *mad); + void (*rmpp_callback)(struct ib_sa_query *sa_query, int status, + struct ib_mad_recv_wc *mad); void (*release)(struct ib_sa_query *); struct ib_sa_client *client; struct ib_sa_port *port; @@ -1987,23 +1989,29 @@ static void send_handler(struct ib_mad_agent *agent, { struct ib_sa_query *query = mad_send_wc->send_buf->context[0]; unsigned long flags; + int status = 0; - if (query->callback) + if (query->callback || query->rmpp_callback) { switch (mad_send_wc->status) { case IB_WC_SUCCESS: /* No callback -- already got recv */ break; case IB_WC_RESP_TIMEOUT_ERR: - query->callback(query, -ETIMEDOUT, NULL); + status = -ETIMEDOUT; break; case IB_WC_WR_FLUSH_ERR: - query->callback(query, -EINTR, NULL); + status = -EINTR; break; default: - query->callback(query, -EIO, NULL); + status = -EIO; break; } + if (status) + query->callback ? query->callback(query, status, NULL) : + query->rmpp_callback(query, status, NULL); + } + xa_lock_irqsave(&queries, flags); __xa_erase(&queries, query->id); xa_unlock_irqrestore(&queries, flags); @@ -2019,17 +2027,25 @@ static void recv_handler(struct ib_mad_agent *mad_agent, struct ib_mad_recv_wc *mad_recv_wc) { struct ib_sa_query *query; + struct ib_mad *mad; + if (!send_buf) return; query = send_buf->context[0]; - if (query->callback) { + mad = mad_recv_wc->recv_buf.mad; + + if (query->rmpp_callback) { if (mad_recv_wc->wc->status == IB_WC_SUCCESS) - query->callback(query, - mad_recv_wc->recv_buf.mad->mad_hdr.status ? - -EINVAL : 0, - (struct ib_sa_mad *) mad_recv_wc->recv_buf.mad); + query->rmpp_callback(query, mad->mad_hdr.status ? + -EINVAL : 0, mad_recv_wc); + else + query->rmpp_callback(query, -EIO, NULL); + } else if (query->callback) { + if (mad_recv_wc->wc->status == IB_WC_SUCCESS) + query->callback(query, mad->mad_hdr.status ? + -EINVAL : 0, (struct ib_sa_mad *)mad); else query->callback(query, -EIO, NULL); } @@ -2181,8 +2197,9 @@ static int ib_sa_add_one(struct ib_device *device) sa_dev->port[i].agent = ib_register_mad_agent(device, i + s, IB_QPT_GSI, - NULL, 0, send_handler, - recv_handler, sa_dev, 0); + NULL, IB_MGMT_RMPP_VERSION, + send_handler, recv_handler, + sa_dev, 0); if (IS_ERR(sa_dev->port[i].agent)) { ret = PTR_ERR(sa_dev->port[i].agent); goto err; From a892a3e74fb4f6ef040659297603abf11ccf29a7 Mon Sep 17 00:00:00 2001 From: Mark Zhang Date: Mon, 30 Jun 2025 13:52:32 +0300 Subject: [PATCH 00620/11391] RDMA/sa_query: Support IB service records resolution Add an SA query API ib_sa_service_rec_get() to support building and sending SA query MADs that ask for service records with a specific name or ID, and receiving and parsing responses from the SM. Signed-off-by: Or Har-Toov Signed-off-by: Mark Zhang Reviewed-by: Vlad Dumitrescu Link: https://patch.msgid.link/9af6c82f3a3a9d975115a33235fb4ffc7c8edb21.1751279793.git.leonro@nvidia.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/core/sa_query.c | 238 +++++++++++++++++++++++++++++ include/rdma/ib_mad.h | 1 + include/rdma/ib_sa.h | 37 +++++ 3 files changed, 276 insertions(+) diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index 770e9f18349b..c0a7af1b4fe4 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -152,6 +152,13 @@ struct ib_sa_mcmember_query { struct ib_sa_query sa_query; }; +struct ib_sa_service_query { + void (*callback)(int status, struct sa_service_rec *rec, + unsigned int num_services, void *context); + void *context; + struct ib_sa_query sa_query; +}; + static LIST_HEAD(ib_nl_request_list); static DEFINE_SPINLOCK(ib_nl_request_lock); static atomic_t ib_nl_sa_request_seq; @@ -686,6 +693,58 @@ static const struct ib_field guidinfo_rec_table[] = { .size_bits = 512 }, }; +#define SERVICE_REC_FIELD(field) \ + .struct_offset_bytes = offsetof(struct sa_service_rec, field), \ + .struct_size_bytes = sizeof_field(struct sa_service_rec, field), \ + .field_name = "sa_service_rec:" #field + +static const struct ib_field service_rec_table[] = { + { SERVICE_REC_FIELD(id), + .offset_words = 0, + .offset_bits = 0, + .size_bits = 64 }, + { SERVICE_REC_FIELD(gid), + .offset_words = 2, + .offset_bits = 0, + .size_bits = 128 }, + { SERVICE_REC_FIELD(pkey), + .offset_words = 6, + .offset_bits = 0, + .size_bits = 16 }, + { RESERVED, + .offset_words = 6, + .offset_bits = 16, + .size_bits = 16 }, + { SERVICE_REC_FIELD(lease), + .offset_words = 7, + .offset_bits = 0, + .size_bits = 32 }, + { SERVICE_REC_FIELD(key), + .offset_words = 8, + .offset_bits = 0, + .size_bits = 128 }, + { SERVICE_REC_FIELD(name), + .offset_words = 12, + .offset_bits = 0, + .size_bits = 512 }, + { SERVICE_REC_FIELD(data_8), + .offset_words = 28, + .offset_bits = 0, + .size_bits = 128 }, + { SERVICE_REC_FIELD(data_16), + .offset_words = 32, + .offset_bits = 0, + .size_bits = 128 }, + { SERVICE_REC_FIELD(data_32), + .offset_words = 36, + .offset_bits = 0, + .size_bits = 128 }, + { SERVICE_REC_FIELD(data_64), + .offset_words = 40, + .offset_bits = 0, + .size_bits = 128 }, +}; + #define RDMA_PRIMARY_PATH_MAX_REC_NUM 3 static inline void ib_sa_disable_local_svc(struct ib_sa_query *query) @@ -1392,6 +1451,20 @@ void ib_sa_pack_path(struct sa_path_rec *rec, void *attribute) } EXPORT_SYMBOL(ib_sa_pack_path); +void ib_sa_pack_service(struct sa_service_rec *rec, void *attribute) +{ + ib_pack(service_rec_table, ARRAY_SIZE(service_rec_table), rec, + attribute); +} +EXPORT_SYMBOL(ib_sa_pack_service); + +void ib_sa_unpack_service(void *attribute, struct sa_service_rec *rec) +{ + ib_unpack(service_rec_table, ARRAY_SIZE(service_rec_table), attribute, + rec); +} +EXPORT_SYMBOL(ib_sa_unpack_service); + static bool ib_sa_opa_pathrecord_support(struct ib_sa_client *client, struct ib_sa_device *sa_dev, u32 port_num) @@ -1481,6 +1554,68 @@ static void ib_sa_path_rec_callback(struct ib_sa_query *sa_query, } } +#define IB_SA_DATA_OFFS 56 +#define IB_SERVICE_REC_SZ 176 + +static void ib_unpack_service_rmpp(struct sa_service_rec *rec, + struct ib_mad_recv_wc *mad_wc, + int num_services) +{ + unsigned int cp_sz, data_i, data_size, rec_i = 0, buf_i = 0; + struct ib_mad_recv_buf *mad_buf; + u8 buf[IB_SERVICE_REC_SZ]; + u8 *data; + + data_size = sizeof(((struct ib_sa_mad *) mad_buf->mad)->data); + + list_for_each_entry(mad_buf, &mad_wc->rmpp_list, list) { + data = ((struct ib_sa_mad *) mad_buf->mad)->data; + data_i = 0; + while (data_i < data_size && rec_i < num_services) { + cp_sz = min(IB_SERVICE_REC_SZ - buf_i, + data_size - data_i); + memcpy(buf + buf_i, data + data_i, cp_sz); + data_i += cp_sz; + buf_i += cp_sz; + if (buf_i == IB_SERVICE_REC_SZ) { + ib_sa_unpack_service(buf, rec + rec_i); + buf_i = 0; + rec_i++; + } + } + } +} + +static void ib_sa_service_rec_callback(struct ib_sa_query *sa_query, int status, + struct ib_mad_recv_wc *mad_wc) +{ + struct ib_sa_service_query *query = + container_of(sa_query, struct ib_sa_service_query, sa_query); + struct sa_service_rec *rec; + int num_services; + + if (!mad_wc || !mad_wc->recv_buf.mad) { + query->callback(status, NULL, 0, query->context); + return; + } + + num_services = (mad_wc->mad_len - IB_SA_DATA_OFFS) / IB_SERVICE_REC_SZ; + if (!num_services) { + query->callback(-ENODATA, NULL, 0, query->context); + return; + } + + rec = kmalloc_array(num_services, sizeof(*rec), GFP_KERNEL); + if (!rec) { + query->callback(-ENOMEM, NULL, 0, query->context); + return; + } + + ib_unpack_service_rmpp(rec, mad_wc, num_services); + query->callback(status, rec, num_services, query->context); + kfree(rec); +} + static void ib_sa_path_rec_release(struct ib_sa_query *sa_query) { struct ib_sa_path_query *query = @@ -1490,6 +1625,14 @@ static void ib_sa_path_rec_release(struct ib_sa_query *sa_query) kfree(query); } +static void ib_sa_service_rec_release(struct ib_sa_query *sa_query) +{ + struct ib_sa_service_query *query = + container_of(sa_query, struct ib_sa_service_query, sa_query); + + kfree(query); +} + /** * ib_sa_path_rec_get - Start a Path get query * @client:SA client @@ -1620,6 +1763,101 @@ int ib_sa_path_rec_get(struct ib_sa_client *client, } EXPORT_SYMBOL(ib_sa_path_rec_get); +/** + * ib_sa_service_rec_get - Start a Service get query + * @client: SA client + * @device: device to send query on + * @port_num: port number to send query on + * @rec: Service Record to send in query + * @comp_mask: component mask to send in query + * @timeout_ms: time to wait for response + * @gfp_mask: GFP mask to use for internal allocations + * @callback: function called when query completes, times out or is + * canceled + * @context: opaque user context passed to callback + * @sa_query: query context, used to cancel query + * + * Send a Service Record Get query to the SA to look up a path. The + * callback function will be called when the query completes (or + * fails); status is 0 for a successful response, -EINTR if the query + * is canceled, -ETIMEDOUT is the query timed out, or -EIO if an error + * occurred sending the query. The resp parameter of the callback is + * only valid if status is 0. + * + * If the return value of ib_sa_service_rec_get() is negative, it is an + * error code. Otherwise it is a query ID that can be used to cancel + * the query. + */ +int ib_sa_service_rec_get(struct ib_sa_client *client, + struct ib_device *device, u32 port_num, + struct sa_service_rec *rec, + ib_sa_comp_mask comp_mask, + unsigned long timeout_ms, gfp_t gfp_mask, + void (*callback)(int status, + struct sa_service_rec *resp, + unsigned int num_services, + void *context), + void *context, struct ib_sa_query **sa_query) +{ + struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client); + struct ib_sa_service_query *query; + struct ib_mad_agent *agent; + struct ib_sa_port *port; + struct ib_sa_mad *mad; + int ret; + + if (!sa_dev) + return -ENODEV; + + port = &sa_dev->port[port_num - sa_dev->start_port]; + agent = port->agent; + + query = kzalloc(sizeof(*query), gfp_mask); + if (!query) + return -ENOMEM; + + query->sa_query.port = port; + + ret = alloc_mad(&query->sa_query, gfp_mask); + if (ret) + goto err1; + + ib_sa_client_get(client); + query->sa_query.client = client; + query->callback = callback; + query->context = context; + + mad = query->sa_query.mad_buf->mad; + init_mad(&query->sa_query, agent); + + query->sa_query.rmpp_callback = callback ? ib_sa_service_rec_callback : + NULL; + query->sa_query.release = ib_sa_service_rec_release; + mad->mad_hdr.method = IB_MGMT_METHOD_GET_TABLE; + mad->mad_hdr.attr_id = cpu_to_be16(IB_SA_ATTR_SERVICE_REC); + mad->sa_hdr.comp_mask = comp_mask; + + ib_sa_pack_service(rec, mad->data); + + *sa_query = &query->sa_query; + query->sa_query.mad_buf->context[1] = rec; + + ret = send_mad(&query->sa_query, timeout_ms, gfp_mask); + if (ret < 0) + goto err2; + + return ret; + +err2: + *sa_query = NULL; + ib_sa_client_put(query->sa_query.client); + free_mad(&query->sa_query); +err1: + kfree(query); + return ret; +} +EXPORT_SYMBOL(ib_sa_service_rec_get); + static void ib_sa_mcmember_rec_callback(struct ib_sa_query *sa_query, int status, struct ib_sa_mad *mad) { diff --git a/include/rdma/ib_mad.h b/include/rdma/ib_mad.h index 3f1b58d8b4bf..8bd0e1eb393b 100644 --- a/include/rdma/ib_mad.h +++ b/include/rdma/ib_mad.h @@ -48,6 +48,7 @@ #define IB_MGMT_METHOD_REPORT 0x06 #define IB_MGMT_METHOD_REPORT_RESP 0x86 #define IB_MGMT_METHOD_TRAP_REPRESS 0x07 +#define IB_MGMT_METHOD_GET_TABLE 0x12 #define IB_MGMT_METHOD_RESP 0x80 #define IB_BM_ATTR_MOD_RESP cpu_to_be32(1) diff --git a/include/rdma/ib_sa.h b/include/rdma/ib_sa.h index b46353fc53bf..95e8924ad563 100644 --- a/include/rdma/ib_sa.h +++ b/include/rdma/ib_sa.h @@ -189,6 +189,20 @@ struct sa_path_rec { u32 flags; }; +struct sa_service_rec { + __be64 id; + __u8 gid[16]; + __be16 pkey; + __u8 reserved[2]; + __be32 lease; + __u8 key[16]; + __u8 name[64]; + __u8 data_8[16]; + __be16 data_16[8]; + __be32 data_32[4]; + __be64 data_64[2]; +}; + static inline enum ib_gid_type sa_conv_pathrec_to_gid_type(struct sa_path_rec *rec) { @@ -417,6 +431,17 @@ int ib_sa_path_rec_get(struct ib_sa_client *client, struct ib_device *device, unsigned int num_prs, void *context), void *context, struct ib_sa_query **query); +int ib_sa_service_rec_get(struct ib_sa_client *client, + struct ib_device *device, u32 port_num, + struct sa_service_rec *rec, + ib_sa_comp_mask comp_mask, + unsigned long timeout_ms, gfp_t gfp_mask, + void (*callback)(int status, + struct sa_service_rec *resp, + unsigned int num_services, + void *context), + void *context, struct ib_sa_query **sa_query); + struct ib_sa_multicast { struct ib_sa_mcmember_rec rec; ib_sa_comp_mask comp_mask; @@ -508,6 +533,18 @@ int ib_init_ah_attr_from_path(struct ib_device *device, u32 port_num, */ void ib_sa_pack_path(struct sa_path_rec *rec, void *attribute); +/** + * ib_sa_pack_service - Convert a service record from struct ib_sa_service_rec + * to IB MAD wire format. + */ +void ib_sa_pack_service(struct sa_service_rec *rec, void *attribute); + +/** + * ib_sa_unpack_service - Convert a service record from MAD format to struct + * ib_sa_service_rec. + */ +void ib_sa_unpack_service(void *attribute, struct sa_service_rec *rec); + /** * ib_sa_unpack_path - Convert a path record from MAD format to struct * ib_sa_path_rec. From a6404823fe20e06d4061bc63e0295b7165af4c14 Mon Sep 17 00:00:00 2001 From: Mark Zhang Date: Mon, 30 Jun 2025 13:52:33 +0300 Subject: [PATCH 00621/11391] RDMA/cma: Support IB service record resolution Add new UCMA command and the corresponding CMA implementation. Userspace can send this command to request service resolution based on service name or ID. On a successful resolution, one or multiple service records are returned, the first one will be used as destination address by default. Two new CM events are added and returned to caller accordingly: - RDMA_CM_EVENT_ADDRINFO_RESOLVED: Resolve succeeded; - RDMA_CM_EVENT_ADDRINFO_ERROR: Resolve failed. Internally two new CM states are added: - RDMA_CM_ADDRINFO_QUERY: CM is in the process of IB service resolution; - RDMA_CM_ADDRINFO_RESOLVED: CM has finished the resolve process. With these new states, beside existing state transfer processes, 2 new processes are supported: 1. The default address is used: RDMA_CM_ADDR_BOUND -> RDMA_CM_ADDRINFO_QUERY -> RDMA_CM_ADDRINFO_RESOLVED -> RDMA_CM_ROUTE_QUERY 2. To use a different address: RDMA_CM_ADDR_BOUND -> RDMA_CM_ADDRINFO_QUERY-> RDMA_CM_ADDRINFO_RESOLVED -> RDMA_CM_ADDR_QUERY -> RDMA_CM_ADDR_RESOLVED -> RDMA_CM_ROUTE_QUERY In the 2nd case, resolve_addrinfo returns multiple records, a user could call rdma_resolve_addr() with the one that is not the first. Signed-off-by: Or Har-Toov Signed-off-by: Mark Zhang Reviewed-by: Vlad Dumitrescu Link: https://patch.msgid.link/b6e82ad75522a13b5efe4ff86da0e465aab04cc2.1751279794.git.leonro@nvidia.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/core/cma.c | 136 ++++++++++++++++++++++++++++- drivers/infiniband/core/cma_priv.h | 4 +- drivers/infiniband/core/ucma.c | 30 ++++++- include/rdma/rdma_cm.h | 18 +++- include/uapi/rdma/rdma_user_cm.h | 20 ++++- 5 files changed, 202 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 9b471548e7ae..5b2d3ae3f9fc 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -2076,6 +2076,7 @@ static void _destroy_id(struct rdma_id_private *id_priv, kfree(id_priv->id.route.path_rec); kfree(id_priv->id.route.path_rec_inbound); kfree(id_priv->id.route.path_rec_outbound); + kfree(id_priv->id.route.service_recs); put_net(id_priv->id.route.addr.dev_addr.net); kfree(id_priv); @@ -3382,13 +3383,18 @@ static int cma_resolve_iboe_route(struct rdma_id_private *id_priv) int rdma_resolve_route(struct rdma_cm_id *id, unsigned long timeout_ms) { struct rdma_id_private *id_priv; + enum rdma_cm_state state; int ret; if (!timeout_ms) return -EINVAL; id_priv = container_of(id, struct rdma_id_private, id); - if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED, RDMA_CM_ROUTE_QUERY)) + state = id_priv->state; + if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED, + RDMA_CM_ROUTE_QUERY) && + !cma_comp_exch(id_priv, RDMA_CM_ADDRINFO_RESOLVED, + RDMA_CM_ROUTE_QUERY)) return -EINVAL; cma_id_get(id_priv); @@ -3409,7 +3415,7 @@ int rdma_resolve_route(struct rdma_cm_id *id, unsigned long timeout_ms) return 0; err: - cma_comp_exch(id_priv, RDMA_CM_ROUTE_QUERY, RDMA_CM_ADDR_RESOLVED); + cma_comp_exch(id_priv, RDMA_CM_ROUTE_QUERY, state); cma_id_put(id_priv); return ret; } @@ -5506,3 +5512,129 @@ static void __exit cma_cleanup(void) module_init(cma_init); module_exit(cma_cleanup); + +static void cma_query_ib_service_handler(int status, + struct sa_service_rec *recs, + unsigned int num_recs, void *context) +{ + struct cma_work *work = context; + struct rdma_id_private *id_priv = work->id; + struct sockaddr_ib *addr; + + if (status) + goto fail; + + if (!num_recs) { + status = -ENOENT; + goto fail; + } + + if (id_priv->id.route.service_recs) { + status = -EALREADY; + goto fail; + } + + id_priv->id.route.service_recs = + kmalloc_array(num_recs, sizeof(*recs), GFP_KERNEL); + if (!id_priv->id.route.service_recs) { + status = -ENOMEM; + goto fail; + } + + id_priv->id.route.num_service_recs = num_recs; + memcpy(id_priv->id.route.service_recs, recs, sizeof(*recs) * num_recs); + + addr = (struct sockaddr_ib *)&id_priv->id.route.addr.dst_addr; + addr->sib_family = AF_IB; + addr->sib_addr = *(struct ib_addr *)&recs->gid; + addr->sib_pkey = recs->pkey; + addr->sib_sid = recs->id; + rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr, + (union ib_gid *)&addr->sib_addr); + ib_addr_set_pkey(&id_priv->id.route.addr.dev_addr, + ntohs(addr->sib_pkey)); + + queue_work(cma_wq, &work->work); + return; + +fail: + work->old_state = RDMA_CM_ADDRINFO_QUERY; + work->new_state = RDMA_CM_ADDR_BOUND; + work->event.event = RDMA_CM_EVENT_ADDRINFO_ERROR; + work->event.status = status; + pr_debug_ratelimited( + "RDMA CM: SERVICE_ERROR: failed to query service record. status %d\n", + status); + queue_work(cma_wq, &work->work); +} + +static int cma_resolve_ib_service(struct rdma_id_private *id_priv, + struct rdma_ucm_ib_service *ibs) +{ + struct sa_service_rec sr = {}; + ib_sa_comp_mask mask = 0; + struct cma_work *work; + + work = kzalloc(sizeof(*work), GFP_KERNEL); + if (!work) + return -ENOMEM; + + cma_id_get(id_priv); + + work->id = id_priv; + INIT_WORK(&work->work, cma_work_handler); + work->old_state = RDMA_CM_ADDRINFO_QUERY; + work->new_state = RDMA_CM_ADDRINFO_RESOLVED; + work->event.event = RDMA_CM_EVENT_ADDRINFO_RESOLVED; + + if (ibs->flags & RDMA_USER_CM_IB_SERVICE_FLAG_ID) { + sr.id = cpu_to_be64(ibs->service_id); + mask |= IB_SA_SERVICE_REC_SERVICE_ID; + } + if (ibs->flags & RDMA_USER_CM_IB_SERVICE_FLAG_NAME) { + strscpy(sr.name, ibs->service_name, sizeof(sr.name)); + mask |= IB_SA_SERVICE_REC_SERVICE_NAME; + } + + id_priv->query_id = ib_sa_service_rec_get(&sa_client, + id_priv->id.device, + id_priv->id.port_num, + &sr, mask, + 2000, GFP_KERNEL, + cma_query_ib_service_handler, + work, &id_priv->query); + + if (id_priv->query_id < 0) { + cma_id_put(id_priv); + kfree(work); + return id_priv->query_id; + } + + return 0; +} + +int rdma_resolve_ib_service(struct rdma_cm_id *id, + struct rdma_ucm_ib_service *ibs) +{ + struct rdma_id_private *id_priv; + int ret; + + id_priv = container_of(id, struct rdma_id_private, id); + if (!id_priv->cma_dev || + !cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_ADDRINFO_QUERY)) + return -EINVAL; + + if (rdma_cap_ib_sa(id->device, id->port_num)) + ret = cma_resolve_ib_service(id_priv, ibs); + else + ret = -EOPNOTSUPP; + + if (ret) + goto err; + + return 0; +err: + cma_comp_exch(id_priv, RDMA_CM_ADDRINFO_QUERY, RDMA_CM_ADDR_BOUND); + return ret; +} +EXPORT_SYMBOL(rdma_resolve_ib_service); diff --git a/drivers/infiniband/core/cma_priv.h b/drivers/infiniband/core/cma_priv.h index b7354c94cf1b..c604b601f4d9 100644 --- a/drivers/infiniband/core/cma_priv.h +++ b/drivers/infiniband/core/cma_priv.h @@ -47,7 +47,9 @@ enum rdma_cm_state { RDMA_CM_ADDR_BOUND, RDMA_CM_LISTEN, RDMA_CM_DEVICE_REMOVAL, - RDMA_CM_DESTROYING + RDMA_CM_DESTROYING, + RDMA_CM_ADDRINFO_QUERY, + RDMA_CM_ADDRINFO_RESOLVED }; struct rdma_id_private { diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 6e700b974033..1915f4e68308 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -282,6 +282,10 @@ static struct ucma_event *ucma_create_uevent(struct ucma_context *ctx, } uevent->resp.event = event->event; uevent->resp.status = event->status; + + if (event->event == RDMA_CM_EVENT_ADDRINFO_RESOLVED) + goto out; + if (ctx->cm_id->qp_type == IB_QPT_UD) ucma_copy_ud_event(ctx->cm_id->device, &uevent->resp.param.ud, &event->param.ud); @@ -289,6 +293,7 @@ static struct ucma_event *ucma_create_uevent(struct ucma_context *ctx, ucma_copy_conn_event(&uevent->resp.param.conn, &event->param.conn); +out: uevent->resp.ece.vendor_id = event->ece.vendor_id; uevent->resp.ece.attr_mod = event->ece.attr_mod; return uevent; @@ -728,6 +733,28 @@ static ssize_t ucma_resolve_addr(struct ucma_file *file, return ret; } +static ssize_t ucma_resolve_ib_service(struct ucma_file *file, + const char __user *inbuf, int in_len, + int out_len) +{ + struct rdma_ucm_resolve_ib_service cmd; + struct ucma_context *ctx; + int ret; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + ctx = ucma_get_ctx(file, cmd.id); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + mutex_lock(&ctx->mutex); + ret = rdma_resolve_ib_service(ctx->cm_id, &cmd.ibs); + mutex_unlock(&ctx->mutex); + ucma_put_ctx(ctx); + return ret; +} + static ssize_t ucma_resolve_route(struct ucma_file *file, const char __user *inbuf, int in_len, int out_len) @@ -1703,7 +1730,8 @@ static ssize_t (*ucma_cmd_table[])(struct ucma_file *file, [RDMA_USER_CM_CMD_QUERY] = ucma_query, [RDMA_USER_CM_CMD_BIND] = ucma_bind, [RDMA_USER_CM_CMD_RESOLVE_ADDR] = ucma_resolve_addr, - [RDMA_USER_CM_CMD_JOIN_MCAST] = ucma_join_multicast + [RDMA_USER_CM_CMD_JOIN_MCAST] = ucma_join_multicast, + [RDMA_USER_CM_CMD_RESOLVE_IB_SERVICE] = ucma_resolve_ib_service }; static ssize_t ucma_write(struct file *filp, const char __user *buf, diff --git a/include/rdma/rdma_cm.h b/include/rdma/rdma_cm.h index d1593ad47e28..72d1568e4cfb 100644 --- a/include/rdma/rdma_cm.h +++ b/include/rdma/rdma_cm.h @@ -33,7 +33,9 @@ enum rdma_cm_event_type { RDMA_CM_EVENT_MULTICAST_JOIN, RDMA_CM_EVENT_MULTICAST_ERROR, RDMA_CM_EVENT_ADDR_CHANGE, - RDMA_CM_EVENT_TIMEWAIT_EXIT + RDMA_CM_EVENT_TIMEWAIT_EXIT, + RDMA_CM_EVENT_ADDRINFO_RESOLVED, + RDMA_CM_EVENT_ADDRINFO_ERROR }; const char *__attribute_const__ rdma_event_msg(enum rdma_cm_event_type event); @@ -63,6 +65,9 @@ struct rdma_route { * 2 - Both primary and alternate path are available */ int num_pri_alt_paths; + + unsigned int num_service_recs; + struct sa_service_rec *service_recs; }; struct rdma_conn_param { @@ -197,6 +202,17 @@ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, */ int rdma_resolve_route(struct rdma_cm_id *id, unsigned long timeout_ms); +/** + * rdma_resolve_ib_service - Resolve the IB service record of the + * service with the given service ID or name. + * + * This function is optional in the rdma cm flow. It is called on the client + * side of a connection, before calling rdma_resolve_route. The resolution + * can be done once per rdma_cm_id. + */ +int rdma_resolve_ib_service(struct rdma_cm_id *id, + struct rdma_ucm_ib_service *ibs); + /** * rdma_create_qp - Allocate a QP and associate it with the specified RDMA * identifier. diff --git a/include/uapi/rdma/rdma_user_cm.h b/include/uapi/rdma/rdma_user_cm.h index 7cea03581f79..8799623bcba0 100644 --- a/include/uapi/rdma/rdma_user_cm.h +++ b/include/uapi/rdma/rdma_user_cm.h @@ -67,7 +67,8 @@ enum { RDMA_USER_CM_CMD_QUERY, RDMA_USER_CM_CMD_BIND, RDMA_USER_CM_CMD_RESOLVE_ADDR, - RDMA_USER_CM_CMD_JOIN_MCAST + RDMA_USER_CM_CMD_JOIN_MCAST, + RDMA_USER_CM_CMD_RESOLVE_IB_SERVICE }; /* See IBTA Annex A11, servies ID bytes 4 & 5 */ @@ -338,4 +339,21 @@ struct rdma_ucm_migrate_resp { __u32 events_reported; }; +enum { + RDMA_USER_CM_IB_SERVICE_FLAG_ID = 1 << 0, + RDMA_USER_CM_IB_SERVICE_FLAG_NAME = 1 << 1, +}; + +#define RDMA_USER_CM_IB_SERVICE_NAME_SIZE 64 +struct rdma_ucm_ib_service { + __u64 service_id; + __u8 service_name[RDMA_USER_CM_IB_SERVICE_NAME_SIZE]; + __u32 flags; + __u32 reserved; +}; + +struct rdma_ucm_resolve_ib_service { + __u32 id; + struct rdma_ucm_ib_service ibs; +}; #endif /* RDMA_USER_CM_H */ From 810f874eda8e492701ba3623aa298caad61bb47c Mon Sep 17 00:00:00 2001 From: Mark Zhang Date: Mon, 30 Jun 2025 13:52:34 +0300 Subject: [PATCH 00622/11391] RDMA/ucma: Support query resolved service records Enable user-space to query resolved service records through a ucma command when a RDMA_CM_EVENT_ADDRINFO_RESOLVED event is received. Signed-off-by: Or Har-Toov Signed-off-by: Mark Zhang Reviewed-by: Vlad Dumitrescu Link: https://patch.msgid.link/1090ee7c00c3f8058c4f9e7557de983504a16715.1751279794.git.leonro@nvidia.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/core/ucma.c | 40 ++++++++++++++++++++++++++++++++ include/uapi/rdma/ib_user_sa.h | 14 +++++++++++ include/uapi/rdma/rdma_user_cm.h | 8 ++++++- 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 1915f4e68308..3b9ca6d7a21b 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -1021,6 +1021,43 @@ static ssize_t ucma_query_gid(struct ucma_context *ctx, return ret; } +static ssize_t ucma_query_ib_service(struct ucma_context *ctx, + void __user *response, int out_len) +{ + struct rdma_ucm_query_ib_service_resp *resp; + int n, ret = 0; + + if (out_len < sizeof(struct rdma_ucm_query_ib_service_resp)) + return -ENOSPC; + + if (!ctx->cm_id->route.service_recs) + return -ENODATA; + + resp = kzalloc(out_len, GFP_KERNEL); + if (!resp) + return -ENOMEM; + + resp->num_service_recs = ctx->cm_id->route.num_service_recs; + + n = (out_len - sizeof(struct rdma_ucm_query_ib_service_resp)) / + sizeof(struct ib_user_service_rec); + + if (!n) + goto out; + + if (n > ctx->cm_id->route.num_service_recs) + n = ctx->cm_id->route.num_service_recs; + + memcpy(resp->recs, ctx->cm_id->route.service_recs, + sizeof(*resp->recs) * n); + if (copy_to_user(response, resp, struct_size(resp, recs, n))) + ret = -EFAULT; + +out: + kfree(resp); + return ret; +} + static ssize_t ucma_query(struct ucma_file *file, const char __user *inbuf, int in_len, int out_len) @@ -1049,6 +1086,9 @@ static ssize_t ucma_query(struct ucma_file *file, case RDMA_USER_CM_QUERY_GID: ret = ucma_query_gid(ctx, response, out_len); break; + case RDMA_USER_CM_QUERY_IB_SERVICE: + ret = ucma_query_ib_service(ctx, response, out_len); + break; default: ret = -ENOSYS; break; diff --git a/include/uapi/rdma/ib_user_sa.h b/include/uapi/rdma/ib_user_sa.h index 435155d6e1c6..acfa20816bc6 100644 --- a/include/uapi/rdma/ib_user_sa.h +++ b/include/uapi/rdma/ib_user_sa.h @@ -74,4 +74,18 @@ struct ib_user_path_rec { __u8 preference; }; +struct ib_user_service_rec { + __be64 id; + __u8 gid[16]; + __be16 pkey; + __u8 reserved[2]; + __be32 lease; + __u8 key[16]; + __u8 name[64]; + __u8 data_8[16]; + __be16 data_16[8]; + __be32 data_32[4]; + __be64 data_64[2]; +}; + #endif /* IB_USER_SA_H */ diff --git a/include/uapi/rdma/rdma_user_cm.h b/include/uapi/rdma/rdma_user_cm.h index 8799623bcba0..00501da0567e 100644 --- a/include/uapi/rdma/rdma_user_cm.h +++ b/include/uapi/rdma/rdma_user_cm.h @@ -148,7 +148,8 @@ struct rdma_ucm_resolve_route { enum { RDMA_USER_CM_QUERY_ADDR, RDMA_USER_CM_QUERY_PATH, - RDMA_USER_CM_QUERY_GID + RDMA_USER_CM_QUERY_GID, + RDMA_USER_CM_QUERY_IB_SERVICE }; struct rdma_ucm_query { @@ -188,6 +189,11 @@ struct rdma_ucm_query_path_resp { struct ib_path_rec_data path_data[]; }; +struct rdma_ucm_query_ib_service_resp { + __u32 num_service_recs; + struct ib_user_service_rec recs[]; +}; + struct rdma_ucm_conn_param { __u32 qp_num; __u32 qkey; From a3c9d0fcd3715541bbf97da2ddde9d032e2fe6d5 Mon Sep 17 00:00:00 2001 From: Mark Zhang Date: Mon, 30 Jun 2025 13:52:35 +0300 Subject: [PATCH 00623/11391] RDMA/ucma: Support write an event into a CM Enable user-space to inject an event into a CM through it's event channel. Two new events are added and supported: RDMA_CM_EVENT_USER and RDMA_CM_EVENT_INTERNAL. With these 2 events a new event parameter "arg" is supported, which is passed from sender to receiver transparently. With this feature an application is able to write an event into a CM channel with a new user-space rdmacm API. For example thread T1 could write an event with the API: rdma_write_cm_event(cm_id, RDMA_CM_EVENT_USER, status, arg); and thread T2 could receive the event with rdma_get_cm_event(). Signed-off-by: Mark Zhang Reviewed-by: Vlad Dumitrescu Link: https://patch.msgid.link/fdf49d0b17a45933c5d8c1d90605c9447d9a3c73.1751279794.git.leonro@nvidia.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/core/ucma.c | 52 +++++++++++++++++++++++++++++++- include/rdma/rdma_cm.h | 5 ++- include/uapi/rdma/rdma_user_cm.h | 16 +++++++++- 3 files changed, 70 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 3b9ca6d7a21b..f86ece701db6 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -1745,6 +1745,55 @@ static ssize_t ucma_migrate_id(struct ucma_file *new_file, return ret; } +static ssize_t ucma_write_cm_event(struct ucma_file *file, + const char __user *inbuf, int in_len, + int out_len) +{ + struct rdma_ucm_write_cm_event cmd; + struct rdma_cm_event event = {}; + struct ucma_event *uevent; + struct ucma_context *ctx; + int ret = 0; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + if ((cmd.event != RDMA_CM_EVENT_USER) && + (cmd.event != RDMA_CM_EVENT_INTERNAL)) + return -EINVAL; + + ctx = ucma_get_ctx(file, cmd.id); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + event.event = cmd.event; + event.status = cmd.status; + event.param.arg = cmd.param.arg; + + uevent = kzalloc(sizeof(*uevent), GFP_KERNEL); + if (!uevent) { + ret = -ENOMEM; + goto out; + } + + uevent->ctx = ctx; + uevent->resp.uid = ctx->uid; + uevent->resp.id = ctx->id; + uevent->resp.event = event.event; + uevent->resp.status = event.status; + memcpy(uevent->resp.param.arg32, &event.param.arg, + sizeof(event.param.arg)); + + mutex_lock(&ctx->file->mut); + list_add_tail(&uevent->list, &ctx->file->event_list); + mutex_unlock(&ctx->file->mut); + wake_up_interruptible(&ctx->file->poll_wait); + +out: + ucma_put_ctx(ctx); + return ret; +} + static ssize_t (*ucma_cmd_table[])(struct ucma_file *file, const char __user *inbuf, int in_len, int out_len) = { @@ -1771,7 +1820,8 @@ static ssize_t (*ucma_cmd_table[])(struct ucma_file *file, [RDMA_USER_CM_CMD_BIND] = ucma_bind, [RDMA_USER_CM_CMD_RESOLVE_ADDR] = ucma_resolve_addr, [RDMA_USER_CM_CMD_JOIN_MCAST] = ucma_join_multicast, - [RDMA_USER_CM_CMD_RESOLVE_IB_SERVICE] = ucma_resolve_ib_service + [RDMA_USER_CM_CMD_RESOLVE_IB_SERVICE] = ucma_resolve_ib_service, + [RDMA_USER_CM_CMD_WRITE_CM_EVENT] = ucma_write_cm_event, }; static ssize_t ucma_write(struct file *filp, const char __user *buf, diff --git a/include/rdma/rdma_cm.h b/include/rdma/rdma_cm.h index 72d1568e4cfb..9bd930a83e6e 100644 --- a/include/rdma/rdma_cm.h +++ b/include/rdma/rdma_cm.h @@ -35,7 +35,9 @@ enum rdma_cm_event_type { RDMA_CM_EVENT_ADDR_CHANGE, RDMA_CM_EVENT_TIMEWAIT_EXIT, RDMA_CM_EVENT_ADDRINFO_RESOLVED, - RDMA_CM_EVENT_ADDRINFO_ERROR + RDMA_CM_EVENT_ADDRINFO_ERROR, + RDMA_CM_EVENT_USER, + RDMA_CM_EVENT_INTERNAL, }; const char *__attribute_const__ rdma_event_msg(enum rdma_cm_event_type event); @@ -98,6 +100,7 @@ struct rdma_cm_event { union { struct rdma_conn_param conn; struct rdma_ud_param ud; + u64 arg; } param; struct rdma_ucm_ece ece; }; diff --git a/include/uapi/rdma/rdma_user_cm.h b/include/uapi/rdma/rdma_user_cm.h index 00501da0567e..5ded174687ee 100644 --- a/include/uapi/rdma/rdma_user_cm.h +++ b/include/uapi/rdma/rdma_user_cm.h @@ -68,7 +68,8 @@ enum { RDMA_USER_CM_CMD_BIND, RDMA_USER_CM_CMD_RESOLVE_ADDR, RDMA_USER_CM_CMD_JOIN_MCAST, - RDMA_USER_CM_CMD_RESOLVE_IB_SERVICE + RDMA_USER_CM_CMD_RESOLVE_IB_SERVICE, + RDMA_USER_CM_CMD_WRITE_CM_EVENT, }; /* See IBTA Annex A11, servies ID bytes 4 & 5 */ @@ -304,6 +305,7 @@ struct rdma_ucm_event_resp { union { struct rdma_ucm_conn_param conn; struct rdma_ucm_ud_param ud; + __u32 arg32[2]; } param; __u32 reserved; struct rdma_ucm_ece ece; @@ -362,4 +364,16 @@ struct rdma_ucm_resolve_ib_service { __u32 id; struct rdma_ucm_ib_service ibs; }; + +struct rdma_ucm_write_cm_event { + __u32 id; + __u32 reserved; + __u32 event; + __u32 status; + union { + struct rdma_ucm_conn_param conn; + struct rdma_ucm_ud_param ud; + __u64 arg; + } param; +}; #endif /* RDMA_USER_CM_H */ From 4d674c478dc51fe241376e215861d15f1a3a9dc4 Mon Sep 17 00:00:00 2001 From: Boshi Yu Date: Fri, 25 Jul 2025 13:53:54 +0800 Subject: [PATCH 00624/11391] RDMA/erdma: Use dma_map_page to map scatter MTT buffer Each high-level indirect MTT entry is assumed to point to exactly one page of the low-level MTT buffer, but dma_map_sg may merge contiguous physical pages when mapping. To avoid extra overhead from splitting merged regions, use dma_map_page to map the scatter MTT buffer page by page. Reviewed-by: Cheng Xu Signed-off-by: Boshi Yu Link: https://patch.msgid.link/20250725055410.67520-2-boshiyu@linux.alibaba.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/erdma/erdma_verbs.c | 110 ++++++++++++++-------- drivers/infiniband/hw/erdma/erdma_verbs.h | 4 +- 2 files changed, 71 insertions(+), 43 deletions(-) diff --git a/drivers/infiniband/hw/erdma/erdma_verbs.c b/drivers/infiniband/hw/erdma/erdma_verbs.c index 94c211df09d8..b4dadd306837 100644 --- a/drivers/infiniband/hw/erdma/erdma_verbs.c +++ b/drivers/infiniband/hw/erdma/erdma_verbs.c @@ -149,7 +149,7 @@ static int regmr_cmd(struct erdma_dev *dev, struct erdma_mr *mr) req.phy_addr[0] = mr->mem.mtt->buf_dma; mtt_level = ERDMA_MR_MTT_1LEVEL; } else { - req.phy_addr[0] = sg_dma_address(mr->mem.mtt->sglist); + req.phy_addr[0] = mr->mem.mtt->dma_addrs[0]; mtt_level = mr->mem.mtt->level; } } else if (mr->type != ERDMA_MR_TYPE_DMA) { @@ -626,18 +626,27 @@ static struct erdma_mtt *erdma_create_cont_mtt(struct erdma_dev *dev, return ERR_PTR(-ENOMEM); } -static void erdma_destroy_mtt_buf_sg(struct erdma_dev *dev, - struct erdma_mtt *mtt) +static void erdma_unmap_page_list(struct erdma_dev *dev, dma_addr_t *pg_dma, + u32 npages) { - dma_unmap_sg(&dev->pdev->dev, mtt->sglist, - DIV_ROUND_UP(mtt->size, PAGE_SIZE), DMA_TO_DEVICE); - vfree(mtt->sglist); + u32 i; + + for (i = 0; i < npages; i++) + dma_unmap_page(&dev->pdev->dev, pg_dma[i], PAGE_SIZE, + DMA_TO_DEVICE); +} + +static void erdma_destroy_mtt_buf_dma_addrs(struct erdma_dev *dev, + struct erdma_mtt *mtt) +{ + erdma_unmap_page_list(dev, mtt->dma_addrs, mtt->npages); + vfree(mtt->dma_addrs); } static void erdma_destroy_scatter_mtt(struct erdma_dev *dev, struct erdma_mtt *mtt) { - erdma_destroy_mtt_buf_sg(dev, mtt); + erdma_destroy_mtt_buf_dma_addrs(dev, mtt); vfree(mtt->buf); kfree(mtt); } @@ -645,50 +654,69 @@ static void erdma_destroy_scatter_mtt(struct erdma_dev *dev, static void erdma_init_middle_mtt(struct erdma_mtt *mtt, struct erdma_mtt *low_mtt) { - struct scatterlist *sg; - u32 idx = 0, i; + dma_addr_t *pg_addr = mtt->buf; + u32 i; - for_each_sg(low_mtt->sglist, sg, low_mtt->nsg, i) - mtt->buf[idx++] = sg_dma_address(sg); + for (i = 0; i < low_mtt->npages; i++) + pg_addr[i] = low_mtt->dma_addrs[i]; } -static int erdma_create_mtt_buf_sg(struct erdma_dev *dev, struct erdma_mtt *mtt) +static u32 vmalloc_to_dma_addrs(struct erdma_dev *dev, dma_addr_t **dma_addrs, + void *buf, u64 len) { - struct scatterlist *sglist; - void *buf = mtt->buf; - u32 npages, i, nsg; + dma_addr_t *pg_dma; struct page *pg; + u32 npages, i; + void *addr; - /* Failed if buf is not page aligned */ - if ((uintptr_t)buf & ~PAGE_MASK) - return -EINVAL; + npages = (PAGE_ALIGN((u64)buf + len) - PAGE_ALIGN_DOWN((u64)buf)) >> + PAGE_SHIFT; + pg_dma = vzalloc(npages * sizeof(dma_addr_t)); + if (!pg_dma) + return 0; - npages = DIV_ROUND_UP(mtt->size, PAGE_SIZE); - sglist = vzalloc(npages * sizeof(*sglist)); - if (!sglist) - return -ENOMEM; - - sg_init_table(sglist, npages); + addr = buf; for (i = 0; i < npages; i++) { - pg = vmalloc_to_page(buf); + pg = vmalloc_to_page(addr); if (!pg) goto err; - sg_set_page(&sglist[i], pg, PAGE_SIZE, 0); - buf += PAGE_SIZE; + + pg_dma[i] = dma_map_page(&dev->pdev->dev, pg, 0, PAGE_SIZE, + DMA_TO_DEVICE); + if (dma_mapping_error(&dev->pdev->dev, pg_dma[i])) + goto err; + + addr += PAGE_SIZE; } - nsg = dma_map_sg(&dev->pdev->dev, sglist, npages, DMA_TO_DEVICE); - if (!nsg) - goto err; + *dma_addrs = pg_dma; - mtt->sglist = sglist; - mtt->nsg = nsg; + return npages; +err: + erdma_unmap_page_list(dev, pg_dma, i); + vfree(pg_dma); return 0; -err: - vfree(sglist); +} - return -ENOMEM; +static int erdma_create_mtt_buf_dma_addrs(struct erdma_dev *dev, + struct erdma_mtt *mtt) +{ + dma_addr_t *addrs; + u32 npages; + + /* Failed if buf is not page aligned */ + if ((uintptr_t)mtt->buf & ~PAGE_MASK) + return -EINVAL; + + npages = vmalloc_to_dma_addrs(dev, &addrs, mtt->buf, mtt->size); + if (!npages) + return -ENOMEM; + + mtt->dma_addrs = addrs; + mtt->npages = npages; + + return 0; } static struct erdma_mtt *erdma_create_scatter_mtt(struct erdma_dev *dev, @@ -707,12 +735,12 @@ static struct erdma_mtt *erdma_create_scatter_mtt(struct erdma_dev *dev, if (!mtt->buf) goto err_free_mtt; - ret = erdma_create_mtt_buf_sg(dev, mtt); + ret = erdma_create_mtt_buf_dma_addrs(dev, mtt); if (ret) goto err_free_mtt_buf; - ibdev_dbg(&dev->ibdev, "create scatter mtt, size:%lu, nsg:%u\n", - mtt->size, mtt->nsg); + ibdev_dbg(&dev->ibdev, "create scatter mtt, size:%lu, npages:%u\n", + mtt->size, mtt->npages); return mtt; @@ -746,8 +774,8 @@ static struct erdma_mtt *erdma_create_mtt(struct erdma_dev *dev, size_t size, level = 1; /* convergence the mtt table. */ - while (mtt->nsg != 1 && level <= 3) { - tmp_mtt = erdma_create_scatter_mtt(dev, MTT_SIZE(mtt->nsg)); + while (mtt->npages != 1 && level <= 3) { + tmp_mtt = erdma_create_scatter_mtt(dev, MTT_SIZE(mtt->npages)); if (IS_ERR(tmp_mtt)) { ret = PTR_ERR(tmp_mtt); goto err_free_mtt; @@ -765,7 +793,7 @@ static struct erdma_mtt *erdma_create_mtt(struct erdma_dev *dev, size_t size, mtt->level = level; ibdev_dbg(&dev->ibdev, "top mtt: level:%d, dma_addr 0x%llx\n", - mtt->level, mtt->sglist[0].dma_address); + mtt->level, mtt->dma_addrs[0]); return mtt; err_free_mtt: diff --git a/drivers/infiniband/hw/erdma/erdma_verbs.h b/drivers/infiniband/hw/erdma/erdma_verbs.h index ef411b81fbd7..7d8d3fe501d5 100644 --- a/drivers/infiniband/hw/erdma/erdma_verbs.h +++ b/drivers/infiniband/hw/erdma/erdma_verbs.h @@ -99,8 +99,8 @@ struct erdma_mtt { union { dma_addr_t buf_dma; struct { - struct scatterlist *sglist; - u32 nsg; + dma_addr_t *dma_addrs; + u32 npages; u32 level; }; }; From 44d69d3cf2e8047c279cbb9708f05e2c43e33234 Mon Sep 17 00:00:00 2001 From: Konstantin Taranov Date: Tue, 29 Jul 2025 02:00:18 -0700 Subject: [PATCH 00625/11391] RDMA/mana_ib: Drain send wrs of GSI QP Drain send WRs of the GSI QP on device removal. In rare servicing scenarios, the hardware may delete the state of the GSI QP, preventing it from generating CQEs for pending send WRs. Since WRs submitted to the GSI QP hold CM resources, the device cannot be removed until those WRs are completed. This patch marks all pending send WRs as failed, allowing the GSI QP to release the CM resources and enabling safe device removal. Signed-off-by: Konstantin Taranov Link: https://patch.msgid.link/1753779618-23629-1-git-send-email-kotaranov@linux.microsoft.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/mana/cq.c | 26 ++++++++++++++++++++++++++ drivers/infiniband/hw/mana/device.c | 3 +++ drivers/infiniband/hw/mana/mana_ib.h | 3 +++ 3 files changed, 32 insertions(+) diff --git a/drivers/infiniband/hw/mana/cq.c b/drivers/infiniband/hw/mana/cq.c index 28e154bbb50f..1becc8779123 100644 --- a/drivers/infiniband/hw/mana/cq.c +++ b/drivers/infiniband/hw/mana/cq.c @@ -291,6 +291,32 @@ static int mana_process_completions(struct mana_ib_cq *cq, int nwc, struct ib_wc return wc_index; } +void mana_drain_gsi_sqs(struct mana_ib_dev *mdev) +{ + struct mana_ib_qp *qp = mana_get_qp_ref(mdev, MANA_GSI_QPN, false); + struct ud_sq_shadow_wqe *shadow_wqe; + struct mana_ib_cq *cq; + unsigned long flags; + + if (!qp) + return; + + cq = container_of(qp->ibqp.send_cq, struct mana_ib_cq, ibcq); + + spin_lock_irqsave(&cq->cq_lock, flags); + while ((shadow_wqe = shadow_queue_get_next_to_complete(&qp->shadow_sq)) + != NULL) { + shadow_wqe->header.error_code = IB_WC_GENERAL_ERR; + shadow_queue_advance_next_to_complete(&qp->shadow_sq); + } + spin_unlock_irqrestore(&cq->cq_lock, flags); + + if (cq->ibcq.comp_handler) + cq->ibcq.comp_handler(&cq->ibcq, cq->ibcq.cq_context); + + mana_put_qp_ref(qp); +} + int mana_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) { struct mana_ib_cq *cq = container_of(ibcq, struct mana_ib_cq, ibcq); diff --git a/drivers/infiniband/hw/mana/device.c b/drivers/infiniband/hw/mana/device.c index fa60872f169f..bdeddb642b87 100644 --- a/drivers/infiniband/hw/mana/device.c +++ b/drivers/infiniband/hw/mana/device.c @@ -230,6 +230,9 @@ static void mana_ib_remove(struct auxiliary_device *adev) { struct mana_ib_dev *dev = dev_get_drvdata(&adev->dev); + if (mana_ib_is_rnic(dev)) + mana_drain_gsi_sqs(dev); + ib_unregister_device(&dev->ib_dev); dma_pool_destroy(dev->av_pool); if (mana_ib_is_rnic(dev)) { diff --git a/drivers/infiniband/hw/mana/mana_ib.h b/drivers/infiniband/hw/mana/mana_ib.h index 5d31034ac7fb..af09a3e6ccb7 100644 --- a/drivers/infiniband/hw/mana/mana_ib.h +++ b/drivers/infiniband/hw/mana/mana_ib.h @@ -43,6 +43,8 @@ */ #define MANA_AV_BUFFER_SIZE 64 +#define MANA_GSI_QPN (1) + struct mana_ib_adapter_caps { u32 max_sq_id; u32 max_rq_id; @@ -718,6 +720,7 @@ int mana_ib_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr, int mana_ib_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr, const struct ib_send_wr **bad_wr); +void mana_drain_gsi_sqs(struct mana_ib_dev *mdev); int mana_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc); int mana_ib_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags); From 211dc59b7bb5ea0a6ea29072f04a4498c7ab046b Mon Sep 17 00:00:00 2001 From: Fushuai Wang Date: Mon, 11 Aug 2025 14:25:34 +0800 Subject: [PATCH 00626/11391] IB/hfi1: 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. Signed-off-by: Fushuai Wang Link: https://patch.msgid.link/20250811062534.1041-1-wangfushuai@baidu.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/hfi1/sdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/hfi1/sdma.c b/drivers/infiniband/hw/hfi1/sdma.c index 719b7c34e238..5cfa4f8fbf3d 100644 --- a/drivers/infiniband/hw/hfi1/sdma.c +++ b/drivers/infiniband/hw/hfi1/sdma.c @@ -990,7 +990,7 @@ ssize_t sdma_set_cpu_to_sde_map(struct sdma_engine *sde, const char *buf, } /* Clean up old mappings */ - for_each_cpu(cpu, cpu_online_mask) { + for_each_online_cpu(cpu) { struct sdma_rht_node *rht_node; /* Don't cleanup sdes that are set in the new mask */ From 9c45f95222beecd6a284fd1284d54dd7a772cf59 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 8 Aug 2025 19:15:01 +0200 Subject: [PATCH 00627/11391] spi: spi-qpic-snand: handle 'use_ecc' parameter of qcom_spi_config_cw_read() During raw read, neither the status of the ECC correction nor the erased state of the codeword gets checked by the qcom_spi_read_cw_raw() function, so in case of raw access reading the corresponding registers via DMA is superfluous. Extend the qcom_spi_config_cw_read() function to evaluate the existing (but actually unused) 'use_ecc' parameter, and configure reading only the flash status register when ECC is not used. With the change, the code gets in line with the corresponding part of the config_nand_cw_read() function in the qcom_nandc driver. Signed-off-by: Gabor Juhos Reviewed-by: Konrad Dybcio Link: https://patch.msgid.link/20250808-qpic-snand-handle-use_ecc-v1-1-67289fbb5e2f@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-qpic-snand.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c index 1f065d990710..2812ffc421d2 100644 --- a/drivers/spi/spi-qpic-snand.c +++ b/drivers/spi/spi-qpic-snand.c @@ -491,9 +491,14 @@ qcom_spi_config_cw_read(struct qcom_nand_controller *snandc, bool use_ecc, int c qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); - qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 2, 0); - qcom_read_reg_dma(snandc, NAND_ERASED_CW_DETECT_STATUS, 1, - NAND_BAM_NEXT_SGL); + if (use_ecc) { + qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 2, 0); + qcom_read_reg_dma(snandc, NAND_ERASED_CW_DETECT_STATUS, 1, + NAND_BAM_NEXT_SGL); + } else { + qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 1, + NAND_BAM_NEXT_SGL); + } } static int qcom_spi_block_erase(struct qcom_nand_controller *snandc) From dfb2a4f76ff7f60d6e2a55b6a973dd42930adf50 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 1 Aug 2025 16:55:41 -0700 Subject: [PATCH 00628/11391] tee: Use SHA-1 library instead of crypto_shash Use the SHA-1 library functions instead of crypto_shash. This is simpler and faster. Change uuid_v5() to return void, since it can no longer fail. Signed-off-by: Eric Biggers Reviewed-by: Sumit Garg Signed-off-by: Jens Wiklander --- drivers/tee/Kconfig | 3 +-- drivers/tee/tee_core.c | 55 +++++++----------------------------------- 2 files changed, 10 insertions(+), 48 deletions(-) diff --git a/drivers/tee/Kconfig b/drivers/tee/Kconfig index 61b507c18780..a84767940fbf 100644 --- a/drivers/tee/Kconfig +++ b/drivers/tee/Kconfig @@ -3,8 +3,7 @@ menuconfig TEE tristate "Trusted Execution Environment support" depends on HAVE_ARM_SMCCC || COMPILE_TEST || CPU_SUP_AMD - select CRYPTO - select CRYPTO_SHA1 + select CRYPTO_LIB_SHA1 select DMA_SHARED_BUFFER select GENERIC_ALLOCATOR help diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c index acc7998758ad..d079aeee0690 100644 --- a/drivers/tee/tee_core.c +++ b/drivers/tee/tee_core.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include "tee_private.h" @@ -142,58 +141,22 @@ static int tee_release(struct inode *inode, struct file *filp) * This implements section (for SHA-1): * 4.3. Algorithm for Creating a Name-Based UUID */ -static int uuid_v5(uuid_t *uuid, const uuid_t *ns, const void *name, - size_t size) +static void uuid_v5(uuid_t *uuid, const uuid_t *ns, const void *name, + size_t size) { unsigned char hash[SHA1_DIGEST_SIZE]; - struct crypto_shash *shash = NULL; - struct shash_desc *desc = NULL; - int rc; + struct sha1_ctx ctx; - shash = crypto_alloc_shash("sha1", 0, 0); - if (IS_ERR(shash)) { - rc = PTR_ERR(shash); - pr_err("shash(sha1) allocation failed\n"); - return rc; - } - - desc = kzalloc(sizeof(*desc) + crypto_shash_descsize(shash), - GFP_KERNEL); - if (!desc) { - rc = -ENOMEM; - goto out_free_shash; - } - - desc->tfm = shash; - - rc = crypto_shash_init(desc); - if (rc < 0) - goto out_free_desc; - - rc = crypto_shash_update(desc, (const u8 *)ns, sizeof(*ns)); - if (rc < 0) - goto out_free_desc; - - rc = crypto_shash_update(desc, (const u8 *)name, size); - if (rc < 0) - goto out_free_desc; - - rc = crypto_shash_final(desc, hash); - if (rc < 0) - goto out_free_desc; + sha1_init(&ctx); + sha1_update(&ctx, (const u8 *)ns, sizeof(*ns)); + sha1_update(&ctx, (const u8 *)name, size); + sha1_final(&ctx, hash); memcpy(uuid->b, hash, UUID_SIZE); /* Tag for version 5 */ uuid->b[6] = (hash[6] & 0x0F) | 0x50; uuid->b[8] = (hash[8] & 0x3F) | 0x80; - -out_free_desc: - kfree(desc); - -out_free_shash: - crypto_free_shash(shash); - return rc; } int tee_session_calc_client_uuid(uuid_t *uuid, u32 connection_method, @@ -203,7 +166,7 @@ int tee_session_calc_client_uuid(uuid_t *uuid, u32 connection_method, kgid_t grp = INVALID_GID; char *name = NULL; int name_len; - int rc; + int rc = 0; if (connection_method == TEE_IOCTL_LOGIN_PUBLIC || connection_method == TEE_IOCTL_LOGIN_REE_KERNEL) { @@ -260,7 +223,7 @@ int tee_session_calc_client_uuid(uuid_t *uuid, u32 connection_method, goto out_free_name; } - rc = uuid_v5(uuid, &tee_client_uuid_ns, name, name_len); + uuid_v5(uuid, &tee_client_uuid_ns, name, name_len); out_free_name: kfree(name); From 7ecb662b717a34305beacf71e9fadd1559b4b9ee Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Mon, 7 Jul 2025 16:32:53 +0200 Subject: [PATCH 00629/11391] media: v4l2-common: Add a helper for obtaining the clock producer Introduce a helper for v4l2 sensor drivers on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. This helper behaves the same as devm_clk_get() except where there is no clock producer like in ACPI-based platforms. For ACPI-based platforms the function will read the "clock-frequency" ACPI _DSD property and register a fixed frequency clock with the frequency indicated in the property. This function also handles the special ACPI-based system case where: . The clock-frequency _DSD property is present. . A reference to the clock producer is present, where the clock is provided by a camera sensor PMIC driver (e.g. int3472/tps68470.c) In this case try to set the clock-frequency value to the provided clock. Reviewed-by: Laurent Pinchart Reviewed-by: Lad Prabhakar Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/v4l2-core/v4l2-common.c | 52 +++++++++++++++++++++++++++ include/media/v4l2-common.h | 27 ++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index 6e585bc76367..a5334aa35992 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -34,6 +34,9 @@ * Added Gerd Knorrs v4l1 enhancements (Justin Schoeman) */ +#include +#include +#include #include #include #include @@ -705,3 +708,52 @@ int v4l2_link_freq_to_bitmap(struct device *dev, const u64 *fw_link_freqs, return 0; } EXPORT_SYMBOL_GPL(v4l2_link_freq_to_bitmap); + +struct clk *devm_v4l2_sensor_clk_get(struct device *dev, const char *id) +{ + const char *clk_id __free(kfree) = NULL; + struct clk_hw *clk_hw; + struct clk *clk; + bool of_node; + u32 rate; + int ret; + + clk = devm_clk_get_optional(dev, id); + if (IS_ERR(clk)) + return clk; + + ret = device_property_read_u32(dev, "clock-frequency", &rate); + of_node = is_of_node(dev_fwnode(dev)); + + if (clk) { + if (!ret && !of_node) { + ret = clk_set_rate(clk, rate); + if (ret) { + dev_err(dev, "Failed to set clock rate: %u\n", + rate); + return ERR_PTR(ret); + } + } + return clk; + } + + if (!IS_ENABLED(CONFIG_COMMON_CLK) || of_node) + return ERR_PTR(-ENOENT); + + if (ret) + return ERR_PTR(ret == -EINVAL ? -EPROBE_DEFER : ret); + + if (!id) { + clk_id = kasprintf(GFP_KERNEL, "clk-%s", dev_name(dev)); + if (!clk_id) + return ERR_PTR(-ENOMEM); + id = clk_id; + } + + clk_hw = devm_clk_hw_register_fixed_rate(dev, id, NULL, 0, rate); + if (IS_ERR(clk_hw)) + return ERR_CAST(clk_hw); + + return clk_hw->clk; +} +EXPORT_SYMBOL_GPL(devm_v4l2_sensor_clk_get); diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index 0a43f56578bc..9d6c236e8f14 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h @@ -97,6 +97,7 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, /* ------------------------------------------------------------------------- */ +struct clk; struct v4l2_device; struct v4l2_subdev; struct v4l2_subdev_ops; @@ -620,6 +621,32 @@ int v4l2_link_freq_to_bitmap(struct device *dev, const u64 *fw_link_freqs, unsigned int num_of_driver_link_freqs, unsigned long *bitmap); +/** + * devm_v4l2_sensor_clk_get - lookup and obtain a reference to a clock producer + * for a camera sensor. + * + * @dev: device for v4l2 sensor clock "consumer" + * @id: clock consumer ID + * + * This function behaves the same way as devm_clk_get() except where there + * is no clock producer like in ACPI-based platforms. + * + * For ACPI-based platforms, the function will read the "clock-frequency" + * ACPI _DSD property and register a fixed-clock with the frequency indicated + * in the property. + * + * This function also handles the special ACPI-based system case where: + * + * * The clock-frequency _DSD property is present. + * * A reference to the clock producer is present, where the clock is provided + * by a camera sensor PMIC driver (e.g. int3472/tps68470.c) + * + * In this case try to set the clock-frequency value to the provided clock. + * + * Returns a pointer to a struct clk on success or an error pointer on failure. + */ +struct clk *devm_v4l2_sensor_clk_get(struct device *dev, const char *id); + static inline u64 v4l2_buffer_get_timestamp(const struct v4l2_buffer *buf) { /* From 2d240b124cc9df62ccccee6054bc3d1d19018758 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Mon, 14 Jul 2025 15:23:56 +0200 Subject: [PATCH 00630/11391] media: i2c: Kconfig: Ensure a dependency on HAVE_CLK for VIDEO_CAMERA_SENSOR Both ACPI and DT-based systems are required to obtain the external camera sensor clock using the new devm_v4l2_sensor_clk_get() helper function. Ensure a dependency on HAVE_CLK when config VIDEO_CAMERA_SENSOR is enabled. Signed-off-by: Mehdi Djait Reviewed-by: Arnd Bergmann Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 6237fe804a5c..1f5a3082ead9 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -27,7 +27,7 @@ config VIDEO_IR_I2C menuconfig VIDEO_CAMERA_SENSOR bool "Camera sensor devices" - depends on MEDIA_CAMERA_SUPPORT && I2C + depends on MEDIA_CAMERA_SUPPORT && I2C && HAVE_CLK select MEDIA_CONTROLLER select V4L2_FWNODE select VIDEO_V4L2_SUBDEV_API From e2b1ebd72c81ca7bcceb0ed2cea2200978b6e975 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:33:53 +0200 Subject: [PATCH 00631/11391] Documentation: media: camera-sensor: Mention v4l2_devm_sensor_clk_get() for obtaining the clock Add the new v4l2 helper devm_v4l2_sensor_clk_get() to Documentation. the helper works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Co-developed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- .../driver-api/media/camera-sensor.rst | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/Documentation/driver-api/media/camera-sensor.rst b/Documentation/driver-api/media/camera-sensor.rst index c290833165e6..94bd1dae82d5 100644 --- a/Documentation/driver-api/media/camera-sensor.rst +++ b/Documentation/driver-api/media/camera-sensor.rst @@ -29,21 +29,31 @@ used in the system. Using another frequency may cause harmful effects elsewhere. Therefore only the pre-determined frequencies are configurable by the user. +The external clock frequency shall be retrieved by obtaining the external clock +using the ``devm_v4l2_sensor_clk_get()`` helper function, and then getting its +frequency with ``clk_get_rate()``. Usage of the helper function guarantees +correct behaviour regardless of whether the sensor is integrated in a DT-based +or ACPI-based system. + ACPI ~~~~ -Read the ``clock-frequency`` _DSD property to denote the frequency. The driver -can rely on this frequency being used. +ACPI-based systems typically don't register the sensor external clock with the +kernel, but specify the external clock frequency in the ``clock-frequency`` +_DSD property. The ``devm_v4l2_sensor_clk_get()`` helper creates and returns a +fixed clock set at that rate. Devicetree ~~~~~~~~~~ -The preferred way to achieve this is using ``assigned-clocks``, -``assigned-clock-parents`` and ``assigned-clock-rates`` properties. See the -`clock device tree bindings +Devicetree-based systems declare the sensor external clock in the device tree +and reference it from the sensor node. The preferred way to select the external +clock frequency is to use the ``assigned-clocks``, ``assigned-clock-parents`` +and ``assigned-clock-rates`` properties in the sensor node to set the clock +rate. See the `clock device tree bindings `_ -for more information. The driver then gets the frequency using -``clk_get_rate()``. +for more information. The ``devm_v4l2_sensor_clk_get()`` helper retrieves and +returns that clock. This approach has the drawback that there's no guarantee that the frequency hasn't been modified directly or indirectly by another driver, or supported by From 46fa6e200d9842f697093eef5a43dcc9d6b2dfc8 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:33:54 +0200 Subject: [PATCH 00632/11391] media: i2c: ar0521: Use the v4l2 helper for obtaining the clock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Acked-by: Krzysztof Hałasa Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ar0521.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/ar0521.c b/drivers/media/i2c/ar0521.c index 24873149096c..939bf590d4b2 100644 --- a/drivers/media/i2c/ar0521.c +++ b/drivers/media/i2c/ar0521.c @@ -1077,11 +1077,10 @@ static int ar0521_probe(struct i2c_client *client) } /* Get master clock (extclk) */ - sensor->extclk = devm_clk_get(dev, "extclk"); - if (IS_ERR(sensor->extclk)) { - dev_err(dev, "failed to get extclk\n"); - return PTR_ERR(sensor->extclk); - } + sensor->extclk = devm_v4l2_sensor_clk_get(dev, "extclk"); + if (IS_ERR(sensor->extclk)) + return dev_err_probe(dev, PTR_ERR(sensor->extclk), + "failed to get extclk\n"); sensor->extclk_freq = clk_get_rate(sensor->extclk); From 2e47c27270e9b6deae90808930d3f71c9b270441 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:33:55 +0200 Subject: [PATCH 00633/11391] media: i2c: et8ek8: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/et8ek8/et8ek8_driver.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/et8ek8/et8ek8_driver.c b/drivers/media/i2c/et8ek8/et8ek8_driver.c index 7519863d77b1..4787b2c430f8 100644 --- a/drivers/media/i2c/et8ek8/et8ek8_driver.c +++ b/drivers/media/i2c/et8ek8/et8ek8_driver.c @@ -1433,11 +1433,10 @@ static int et8ek8_probe(struct i2c_client *client) return PTR_ERR(sensor->vana); } - sensor->ext_clk = devm_clk_get(dev, NULL); - if (IS_ERR(sensor->ext_clk)) { - dev_err(&client->dev, "could not get clock\n"); - return PTR_ERR(sensor->ext_clk); - } + sensor->ext_clk = devm_v4l2_sensor_clk_get(dev, NULL); + if (IS_ERR(sensor->ext_clk)) + return dev_err_probe(&client->dev, PTR_ERR(sensor->ext_clk), + "could not get clock\n"); ret = of_property_read_u32(dev->of_node, "clock-frequency", &sensor->xclk_freq); From da47267d99609fdc759ad45a5937ff9b54535fe7 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:33:56 +0200 Subject: [PATCH 00634/11391] media: i2c: gc05a2: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/gc05a2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/gc05a2.c b/drivers/media/i2c/gc05a2.c index 3f7f3d5abeeb..4dadd25e6c90 100644 --- a/drivers/media/i2c/gc05a2.c +++ b/drivers/media/i2c/gc05a2.c @@ -1235,7 +1235,7 @@ static int gc05a2_probe(struct i2c_client *client) return dev_err_probe(dev, PTR_ERR(gc05a2->regmap), "failed to init CCI\n"); - gc05a2->xclk = devm_clk_get(dev, NULL); + gc05a2->xclk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(gc05a2->xclk)) return dev_err_probe(dev, PTR_ERR(gc05a2->xclk), "failed to get xclk\n"); From 4475c7764ab589d59c75b01ff9f14116e42379d7 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:33:57 +0200 Subject: [PATCH 00635/11391] media: i2c: gc08a3: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/gc08a3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/gc08a3.c b/drivers/media/i2c/gc08a3.c index 938709a677b6..5d38dfa9878e 100644 --- a/drivers/media/i2c/gc08a3.c +++ b/drivers/media/i2c/gc08a3.c @@ -1199,7 +1199,7 @@ static int gc08a3_probe(struct i2c_client *client) return dev_err_probe(dev, PTR_ERR(gc08a3->regmap), "failed to init CCI\n"); - gc08a3->xclk = devm_clk_get(dev, NULL); + gc08a3->xclk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(gc08a3->xclk)) return dev_err_probe(dev, PTR_ERR(gc08a3->xclk), "failed to get xclk\n"); From 374e55cf087613663440719b08166b6686b36bcc Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:33:58 +0200 Subject: [PATCH 00636/11391] media: i2c: gc2145: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/gc2145.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/gc2145.c b/drivers/media/i2c/gc2145.c index ba02161d46e7..52d9387559c9 100644 --- a/drivers/media/i2c/gc2145.c +++ b/drivers/media/i2c/gc2145.c @@ -1334,7 +1334,7 @@ static int gc2145_probe(struct i2c_client *client) return -EINVAL; /* Get system clock (xclk) */ - gc2145->xclk = devm_clk_get(dev, NULL); + gc2145->xclk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(gc2145->xclk)) return dev_err_probe(dev, PTR_ERR(gc2145->xclk), "failed to get xclk\n"); From 9c54f6a9eccd617807e5f761f81ea8abfb3e4684 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:33:59 +0200 Subject: [PATCH 00637/11391] media: i2c: hi846: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/hi846.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/media/i2c/hi846.c b/drivers/media/i2c/hi846.c index 172772decd3d..a3f77b8434ca 100644 --- a/drivers/media/i2c/hi846.c +++ b/drivers/media/i2c/hi846.c @@ -2052,12 +2052,11 @@ static int hi846_probe(struct i2c_client *client) return ret; } - hi846->clock = devm_clk_get(&client->dev, NULL); - if (IS_ERR(hi846->clock)) { - dev_err(&client->dev, "failed to get clock: %pe\n", - hi846->clock); - return PTR_ERR(hi846->clock); - } + hi846->clock = devm_v4l2_sensor_clk_get(&client->dev, NULL); + if (IS_ERR(hi846->clock)) + return dev_err_probe(&client->dev, PTR_ERR(hi846->clock), + "failed to get clock: %pe\n", + hi846->clock); mclk_freq = clk_get_rate(hi846->clock); if (mclk_freq != 25000000) From c3b36a4cc9cceba7c1fe07edf6ca95985244134b Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:00 +0200 Subject: [PATCH 00638/11391] media: i2c: imx214: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx214.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c index a0cef9e61b41..cab013bd6af1 100644 --- a/drivers/media/i2c/imx214.c +++ b/drivers/media/i2c/imx214.c @@ -1396,7 +1396,7 @@ static int imx214_probe(struct i2c_client *client) imx214->dev = dev; - imx214->xclk = devm_clk_get(dev, NULL); + imx214->xclk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(imx214->xclk)) return dev_err_probe(dev, PTR_ERR(imx214->xclk), "failed to get xclk\n"); From 33cce53627a5e06e7a48a5684dc3849f399ca74a Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:01 +0200 Subject: [PATCH 00639/11391] media: i2c: imx219: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx219.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 3b4f68543342..bb7808515178 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -1188,7 +1188,7 @@ static int imx219_probe(struct i2c_client *client) "failed to initialize CCI\n"); /* Get system clock (xclk) */ - imx219->xclk = devm_clk_get(dev, NULL); + imx219->xclk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(imx219->xclk)) return dev_err_probe(dev, PTR_ERR(imx219->xclk), "failed to get xclk\n"); From c3032c14d3c2f719601bdcdd7fae76df6178786d Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:02 +0200 Subject: [PATCH 00640/11391] media: i2c: imx283: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx283.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/imx283.c b/drivers/media/i2c/imx283.c index da618c8cbadc..8bff5bf4df12 100644 --- a/drivers/media/i2c/imx283.c +++ b/drivers/media/i2c/imx283.c @@ -1462,11 +1462,10 @@ static int imx283_probe(struct i2c_client *client) } /* Get system clock (xclk) */ - imx283->xclk = devm_clk_get(imx283->dev, NULL); - if (IS_ERR(imx283->xclk)) { + imx283->xclk = devm_v4l2_sensor_clk_get(imx283->dev, NULL); + if (IS_ERR(imx283->xclk)) return dev_err_probe(imx283->dev, PTR_ERR(imx283->xclk), "failed to get xclk\n"); - } xclk_freq = clk_get_rate(imx283->xclk); for (i = 0; i < ARRAY_SIZE(imx283_frequencies); i++) { From d78dc79d1c8c3b0d5578df9e4cf03844ede8da19 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:03 +0200 Subject: [PATCH 00641/11391] media: i2c: imx290: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx290.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index 4f3f386c5353..81c0af959df4 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -1599,7 +1599,7 @@ static int imx290_probe(struct i2c_client *client) return ret; /* Acquire resources. */ - imx290->xclk = devm_clk_get(dev, "xclk"); + imx290->xclk = devm_v4l2_sensor_clk_get(dev, "xclk"); if (IS_ERR(imx290->xclk)) return dev_err_probe(dev, PTR_ERR(imx290->xclk), "Could not get xclk\n"); From 8dacf792b85f0b8d5a26e6677bebe3e81755e941 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:04 +0200 Subject: [PATCH 00642/11391] media: i2c: imx296: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx296.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/imx296.c b/drivers/media/i2c/imx296.c index f3bec16b527c..3795b75a4397 100644 --- a/drivers/media/i2c/imx296.c +++ b/drivers/media/i2c/imx296.c @@ -1044,7 +1044,7 @@ static int imx296_probe(struct i2c_client *client) return dev_err_probe(sensor->dev, PTR_ERR(sensor->reset), "failed to get reset GPIO\n"); - sensor->clk = devm_clk_get(sensor->dev, "inck"); + sensor->clk = devm_v4l2_sensor_clk_get(sensor->dev, "inck"); if (IS_ERR(sensor->clk)) return dev_err_probe(sensor->dev, PTR_ERR(sensor->clk), "failed to get clock\n"); From 69a30d67d0726ddac2a14423e58bbb1390d51347 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:05 +0200 Subject: [PATCH 00643/11391] media: i2c: imx334: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx334.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/imx334.c b/drivers/media/i2c/imx334.c index 846b9928d4e8..7a9b14d102c9 100644 --- a/drivers/media/i2c/imx334.c +++ b/drivers/media/i2c/imx334.c @@ -997,7 +997,7 @@ static int imx334_parse_hw_config(struct imx334 *imx334) "failed to get reset gpio\n"); /* Get sensor input clock */ - imx334->inclk = devm_clk_get(imx334->dev, NULL); + imx334->inclk = devm_v4l2_sensor_clk_get(imx334->dev, NULL); if (IS_ERR(imx334->inclk)) return dev_err_probe(imx334->dev, PTR_ERR(imx334->inclk), "could not get inclk\n"); From ae40acaed0384a6c50ff6da5b171ae075d819aec Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:06 +0200 Subject: [PATCH 00644/11391] media: i2c: imx335: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx335.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/imx335.c b/drivers/media/i2c/imx335.c index 9b4db4cd4929..c043df2f15fb 100644 --- a/drivers/media/i2c/imx335.c +++ b/drivers/media/i2c/imx335.c @@ -1026,11 +1026,10 @@ static int imx335_parse_hw_config(struct imx335 *imx335) } /* Get sensor input clock */ - imx335->inclk = devm_clk_get(imx335->dev, NULL); - if (IS_ERR(imx335->inclk)) { - dev_err(imx335->dev, "could not get inclk\n"); - return PTR_ERR(imx335->inclk); - } + imx335->inclk = devm_v4l2_sensor_clk_get(imx335->dev, NULL); + if (IS_ERR(imx335->inclk)) + return dev_err_probe(imx335->dev, PTR_ERR(imx335->inclk), + "could not get inclk\n"); rate = clk_get_rate(imx335->inclk); if (rate != IMX335_INCLK_RATE) { From e1d824320d82eb2d65eba9424fc0da067b65506e Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:07 +0200 Subject: [PATCH 00645/11391] media: i2c: imx412: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx412.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/imx412.c b/drivers/media/i2c/imx412.c index c74097a59c42..7bbd639a9ddf 100644 --- a/drivers/media/i2c/imx412.c +++ b/drivers/media/i2c/imx412.c @@ -933,11 +933,10 @@ static int imx412_parse_hw_config(struct imx412 *imx412) } /* Get sensor input clock */ - imx412->inclk = devm_clk_get(imx412->dev, NULL); - if (IS_ERR(imx412->inclk)) { - dev_err(imx412->dev, "could not get inclk\n"); - return PTR_ERR(imx412->inclk); - } + imx412->inclk = devm_v4l2_sensor_clk_get(imx412->dev, NULL); + if (IS_ERR(imx412->inclk)) + return dev_err_probe(imx412->dev, PTR_ERR(imx412->inclk), + "could not get inclk\n"); rate = clk_get_rate(imx412->inclk); if (rate != IMX412_INCLK_RATE) { From 180ea10775458a2f46e1f300f3765da03a1d9362 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:08 +0200 Subject: [PATCH 00646/11391] media: i2c: imx415: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Reviewed-by: Michael Riesch Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx415.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/imx415.c b/drivers/media/i2c/imx415.c index 278e743646ea..2e206a671ed3 100644 --- a/drivers/media/i2c/imx415.c +++ b/drivers/media/i2c/imx415.c @@ -1251,7 +1251,7 @@ static int imx415_parse_hw_config(struct imx415 *sensor) return dev_err_probe(sensor->dev, PTR_ERR(sensor->reset), "failed to get reset GPIO\n"); - sensor->clk = devm_clk_get(sensor->dev, NULL); + sensor->clk = devm_v4l2_sensor_clk_get(sensor->dev, NULL); if (IS_ERR(sensor->clk)) return dev_err_probe(sensor->dev, PTR_ERR(sensor->clk), "failed to get clock\n"); From ad2089b72798a75423ad4b830fa62dfb5c434451 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:09 +0200 Subject: [PATCH 00647/11391] media: i2c: mt9m001: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/mt9m001.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/mt9m001.c b/drivers/media/i2c/mt9m001.c index 12d3e86bdc0f..7a6114d18dfc 100644 --- a/drivers/media/i2c/mt9m001.c +++ b/drivers/media/i2c/mt9m001.c @@ -743,9 +743,10 @@ static int mt9m001_probe(struct i2c_client *client) if (!mt9m001) return -ENOMEM; - mt9m001->clk = devm_clk_get(&client->dev, NULL); + mt9m001->clk = devm_v4l2_sensor_clk_get(&client->dev, NULL); if (IS_ERR(mt9m001->clk)) - return PTR_ERR(mt9m001->clk); + return dev_err_probe(&client->dev, PTR_ERR(mt9m001->clk), + "failed to get the clock\n"); mt9m001->standby_gpio = devm_gpiod_get_optional(&client->dev, "standby", GPIOD_OUT_LOW); From 2e15ccbb1d68af68923e948d1266770114df2f52 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:10 +0200 Subject: [PATCH 00648/11391] media: i2c: mt9m111: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/mt9m111.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c index 9aa5dcda3805..05dcf37c6f01 100644 --- a/drivers/media/i2c/mt9m111.c +++ b/drivers/media/i2c/mt9m111.c @@ -1279,9 +1279,10 @@ static int mt9m111_probe(struct i2c_client *client) return ret; } - mt9m111->clk = devm_clk_get(&client->dev, "mclk"); + mt9m111->clk = devm_v4l2_sensor_clk_get(&client->dev, "mclk"); if (IS_ERR(mt9m111->clk)) - return PTR_ERR(mt9m111->clk); + return dev_err_probe(&client->dev, PTR_ERR(mt9m111->clk), + "failed to get mclk\n"); mt9m111->regulator = devm_regulator_get(&client->dev, "vdd"); if (IS_ERR(mt9m111->regulator)) { From b9342c89ca608789182a4fdbe7635088a377e67a Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:11 +0200 Subject: [PATCH 00649/11391] media: i2c: mt9m114: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/mt9m114.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/mt9m114.c b/drivers/media/i2c/mt9m114.c index 3f540ca40f3c..37fb8052d20f 100644 --- a/drivers/media/i2c/mt9m114.c +++ b/drivers/media/i2c/mt9m114.c @@ -2395,10 +2395,10 @@ static int mt9m114_probe(struct i2c_client *client) return ret; /* Acquire clocks, GPIOs and regulators. */ - sensor->clk = devm_clk_get(dev, NULL); + sensor->clk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(sensor->clk)) { - ret = PTR_ERR(sensor->clk); - dev_err_probe(dev, ret, "Failed to get clock\n"); + ret = dev_err_probe(dev, PTR_ERR(sensor->clk), + "Failed to get clock\n"); goto error_ep_free; } From d1360982c3e437fc900970f9b0f6f576de3d7947 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:12 +0200 Subject: [PATCH 00650/11391] media: i2c: mt9p031: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/mt9p031.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index 4ef5fb06131d..4df8f2be15f3 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -233,9 +233,10 @@ static int mt9p031_clk_setup(struct mt9p031 *mt9p031) unsigned long ext_freq; int ret; - mt9p031->clk = devm_clk_get(&client->dev, NULL); + mt9p031->clk = devm_v4l2_sensor_clk_get(&client->dev, NULL); if (IS_ERR(mt9p031->clk)) - return PTR_ERR(mt9p031->clk); + return dev_err_probe(&client->dev, PTR_ERR(mt9p031->clk), + "failed to get the clock\n"); ret = clk_set_rate(mt9p031->clk, mt9p031->ext_freq); if (ret < 0) From e49ee5d80be194901b5b0672dbe400df6ae8716b Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:13 +0200 Subject: [PATCH 00651/11391] media: i2c: mt9t112: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/mt9t112.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/media/i2c/mt9t112.c b/drivers/media/i2c/mt9t112.c index 878dff9b7577..2d2c840fc002 100644 --- a/drivers/media/i2c/mt9t112.c +++ b/drivers/media/i2c/mt9t112.c @@ -1078,13 +1078,12 @@ static int mt9t112_probe(struct i2c_client *client) v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); - priv->clk = devm_clk_get(&client->dev, "extclk"); - if (PTR_ERR(priv->clk) == -ENOENT) { + priv->clk = devm_v4l2_sensor_clk_get(&client->dev, "extclk"); + if (PTR_ERR(priv->clk) == -ENOENT) priv->clk = NULL; - } else if (IS_ERR(priv->clk)) { - dev_err(&client->dev, "Unable to get clock \"extclk\"\n"); - return PTR_ERR(priv->clk); - } + else if (IS_ERR(priv->clk)) + return dev_err_probe(&client->dev, PTR_ERR(priv->clk), + "Unable to get clock \"extclk\"\n"); priv->standby_gpio = devm_gpiod_get_optional(&client->dev, "standby", GPIOD_OUT_HIGH); From 3faab75678bb42ec04ffa08a4e2c133b474a08fc Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:14 +0200 Subject: [PATCH 00652/11391] media: i2c: mt9v032: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/mt9v032.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c index 302120ff125e..9f4b4cb9853e 100644 --- a/drivers/media/i2c/mt9v032.c +++ b/drivers/media/i2c/mt9v032.c @@ -1058,9 +1058,10 @@ static int mt9v032_probe(struct i2c_client *client) if (IS_ERR(mt9v032->regmap)) return PTR_ERR(mt9v032->regmap); - mt9v032->clk = devm_clk_get(&client->dev, NULL); + mt9v032->clk = devm_v4l2_sensor_clk_get(&client->dev, NULL); if (IS_ERR(mt9v032->clk)) - return PTR_ERR(mt9v032->clk); + return dev_err_probe(&client->dev, PTR_ERR(mt9v032->clk), + "failed to get the clock\n"); mt9v032->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_HIGH); From 6e4674fc4c19ebee9181159f0ac412f9c84dbc50 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:15 +0200 Subject: [PATCH 00653/11391] media: i2c: mt9v111: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/mt9v111.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/mt9v111.c b/drivers/media/i2c/mt9v111.c index 723fe138e7bc..6aa80b504168 100644 --- a/drivers/media/i2c/mt9v111.c +++ b/drivers/media/i2c/mt9v111.c @@ -1129,9 +1129,10 @@ static int mt9v111_probe(struct i2c_client *client) mt9v111->dev = &client->dev; mt9v111->client = client; - mt9v111->clk = devm_clk_get(&client->dev, NULL); + mt9v111->clk = devm_v4l2_sensor_clk_get(&client->dev, NULL); if (IS_ERR(mt9v111->clk)) - return PTR_ERR(mt9v111->clk); + return dev_err_probe(&client->dev, PTR_ERR(mt9v111->clk), + "failed to get the clock\n"); mt9v111->sysclk = clk_get_rate(mt9v111->clk); if (mt9v111->sysclk > MT9V111_MAX_CLKIN) From 52b0a078fab8625501f20e3eb4bf6c1c346c59ec Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:16 +0200 Subject: [PATCH 00654/11391] media: i2c: ov02a10: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov02a10.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov02a10.c b/drivers/media/i2c/ov02a10.c index 6c30e1a0d814..74fc0687c849 100644 --- a/drivers/media/i2c/ov02a10.c +++ b/drivers/media/i2c/ov02a10.c @@ -885,7 +885,7 @@ static int ov02a10_probe(struct i2c_client *client) ov02a10->fmt.code = MEDIA_BUS_FMT_SRGGB10_1X10; } - ov02a10->eclk = devm_clk_get(dev, "eclk"); + ov02a10->eclk = devm_v4l2_sensor_clk_get(dev, "eclk"); if (IS_ERR(ov02a10->eclk)) return dev_err_probe(dev, PTR_ERR(ov02a10->eclk), "failed to get eclk\n"); From 33df67eb771d8e807792ee3b62b230842552cc5f Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:17 +0200 Subject: [PATCH 00655/11391] media: i2c: ov2659: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov2659.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ov2659.c b/drivers/media/i2c/ov2659.c index 586b31ba076b..061401b020fc 100644 --- a/drivers/media/i2c/ov2659.c +++ b/drivers/media/i2c/ov2659.c @@ -1437,9 +1437,10 @@ static int ov2659_probe(struct i2c_client *client) ov2659->pdata = pdata; ov2659->client = client; - ov2659->clk = devm_clk_get(&client->dev, "xvclk"); + ov2659->clk = devm_v4l2_sensor_clk_get(&client->dev, "xvclk"); if (IS_ERR(ov2659->clk)) - return PTR_ERR(ov2659->clk); + return dev_err_probe(&client->dev, PTR_ERR(ov2659->clk), + "failed to get xvclk\n"); ov2659->xvclk_frequency = clk_get_rate(ov2659->clk); if (ov2659->xvclk_frequency < 6000000 || From e830bc33f6fdea0390fa7c813df9733beabb2d7b Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:18 +0200 Subject: [PATCH 00656/11391] media: i2c: ov2685: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov2685.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/ov2685.c b/drivers/media/i2c/ov2685.c index 9b8481b8dcd4..c435799514b9 100644 --- a/drivers/media/i2c/ov2685.c +++ b/drivers/media/i2c/ov2685.c @@ -783,11 +783,11 @@ static int ov2685_probe(struct i2c_client *client) ov2685->client = client; ov2685->cur_mode = &supported_modes[0]; - ov2685->xvclk = devm_clk_get(dev, "xvclk"); - if (IS_ERR(ov2685->xvclk)) { - dev_err(dev, "Failed to get xvclk\n"); - return -EINVAL; - } + ov2685->xvclk = devm_v4l2_sensor_clk_get(dev, "xvclk"); + if (IS_ERR(ov2685->xvclk)) + return dev_err_probe(dev, PTR_ERR(ov2685->xvclk), + "Failed to get xvclk\n"); + ret = clk_set_rate(ov2685->xvclk, OV2685_XVCLK_FREQ); if (ret < 0) { dev_err(dev, "Failed to set xvclk rate (24MHz)\n"); From 76d5e67d54331b48462d35286a4bc44faaba4c72 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:19 +0200 Subject: [PATCH 00657/11391] media: i2c: ov5640: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov5640.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index 0dae0438aa80..08ca366a22d7 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -3898,11 +3898,10 @@ static int ov5640_probe(struct i2c_client *client) ov5640_dvp_default_fmt; /* get system clock (xclk) */ - sensor->xclk = devm_clk_get(dev, "xclk"); - if (IS_ERR(sensor->xclk)) { - dev_err(dev, "failed to get xclk\n"); - return PTR_ERR(sensor->xclk); - } + sensor->xclk = devm_v4l2_sensor_clk_get(dev, "xclk"); + if (IS_ERR(sensor->xclk)) + return dev_err_probe(dev, PTR_ERR(sensor->xclk), + "failed to get xclk\n"); sensor->xclk_freq = clk_get_rate(sensor->xclk); if (sensor->xclk_freq < OV5640_XCLK_MIN || From 1e8faa6626b66842c14c7cf13acfb385c800118b Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:20 +0200 Subject: [PATCH 00658/11391] media: i2c: ov5645: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov5645.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov5645.c b/drivers/media/i2c/ov5645.c index 004d0ee5c3f5..70b4cdb1b9af 100644 --- a/drivers/media/i2c/ov5645.c +++ b/drivers/media/i2c/ov5645.c @@ -1044,7 +1044,7 @@ static int ov5645_probe(struct i2c_client *client) "invalid bus type, must be CSI2\n"); /* get system clock (xclk) */ - ov5645->xclk = devm_clk_get(dev, NULL); + ov5645->xclk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(ov5645->xclk)) return dev_err_probe(dev, PTR_ERR(ov5645->xclk), "could not get xclk"); From f801ccf74011e0f6f35a71a8cc5f1a0cf63ccc24 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:21 +0200 Subject: [PATCH 00659/11391] media: i2c: ov5647: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov5647.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c index a727beb9d57e..e193fef4fced 100644 --- a/drivers/media/i2c/ov5647.c +++ b/drivers/media/i2c/ov5647.c @@ -1398,11 +1398,10 @@ static int ov5647_probe(struct i2c_client *client) } } - sensor->xclk = devm_clk_get(dev, NULL); - if (IS_ERR(sensor->xclk)) { - dev_err(dev, "could not get xclk"); - return PTR_ERR(sensor->xclk); - } + sensor->xclk = devm_v4l2_sensor_clk_get(dev, NULL); + if (IS_ERR(sensor->xclk)) + return dev_err_probe(dev, PTR_ERR(sensor->xclk), + "could not get xclk\n"); xclk_freq = clk_get_rate(sensor->xclk); if (xclk_freq != 25000000) { From 85f809c2af15fc715a5747cfd2aa9853882f66e6 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:22 +0200 Subject: [PATCH 00660/11391] media: i2c: ov5648: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov5648.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/ov5648.c b/drivers/media/i2c/ov5648.c index 4b86d2631bd1..8a3190bf73da 100644 --- a/drivers/media/i2c/ov5648.c +++ b/drivers/media/i2c/ov5648.c @@ -2521,10 +2521,10 @@ static int ov5648_probe(struct i2c_client *client) /* External Clock */ - sensor->xvclk = devm_clk_get(dev, NULL); + sensor->xvclk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(sensor->xvclk)) { - dev_err(dev, "failed to get external clock\n"); - ret = PTR_ERR(sensor->xvclk); + ret = dev_err_probe(dev, PTR_ERR(sensor->xvclk), + "failed to get external clock\n"); goto error_endpoint; } From e3ed4873e9923c6added068cab4ad4eb616407d9 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:23 +0200 Subject: [PATCH 00661/11391] media: i2c: ov5695: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov5695.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/ov5695.c b/drivers/media/i2c/ov5695.c index 663eccdfea6a..fe7ad7b2c05a 100644 --- a/drivers/media/i2c/ov5695.c +++ b/drivers/media/i2c/ov5695.c @@ -1264,11 +1264,11 @@ static int ov5695_probe(struct i2c_client *client) ov5695->client = client; ov5695->cur_mode = &supported_modes[0]; - ov5695->xvclk = devm_clk_get(dev, "xvclk"); - if (IS_ERR(ov5695->xvclk)) { - dev_err(dev, "Failed to get xvclk\n"); - return -EINVAL; - } + ov5695->xvclk = devm_v4l2_sensor_clk_get(dev, "xvclk"); + if (IS_ERR(ov5695->xvclk)) + return dev_err_probe(dev, PTR_ERR(ov5695->xvclk), + "Failed to get xvclk\n"); + ret = clk_set_rate(ov5695->xvclk, OV5695_XVCLK_FREQ); if (ret < 0) { dev_err(dev, "Failed to set xvclk rate (24MHz)\n"); From 197b2c2484cf088b80242d9379b6bc2a8abc5df2 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:24 +0200 Subject: [PATCH 00662/11391] media: i2c: ov64a40: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov64a40.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov64a40.c b/drivers/media/i2c/ov64a40.c index a5da4fe47e0b..d7a13e855a41 100644 --- a/drivers/media/i2c/ov64a40.c +++ b/drivers/media/i2c/ov64a40.c @@ -3550,7 +3550,7 @@ static int ov64a40_probe(struct i2c_client *client) return PTR_ERR(ov64a40->cci); } - ov64a40->xclk = devm_clk_get(&client->dev, NULL); + ov64a40->xclk = devm_v4l2_sensor_clk_get(&client->dev, NULL); if (IS_ERR(ov64a40->xclk)) return dev_err_probe(&client->dev, PTR_ERR(ov64a40->xclk), "Failed to get clock\n"); From c6e79ddd0006cc1c42a4eabebb22a6e363c5d4bd Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:25 +0200 Subject: [PATCH 00663/11391] media: i2c: ov6650: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov6650.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c index 9c7627161142..3e37a6436aeb 100644 --- a/drivers/media/i2c/ov6650.c +++ b/drivers/media/i2c/ov6650.c @@ -898,12 +898,10 @@ static int ov6650_video_probe(struct v4l2_subdev *sd) u8 pidh, pidl, midh, midl; int i, ret = 0; - priv->clk = devm_clk_get(&client->dev, NULL); - if (IS_ERR(priv->clk)) { - ret = PTR_ERR(priv->clk); - dev_err(&client->dev, "clk request err: %d\n", ret); - return ret; - } + priv->clk = devm_v4l2_sensor_clk_get(&client->dev, NULL); + if (IS_ERR(priv->clk)) + return dev_err_probe(&client->dev, PTR_ERR(priv->clk), + "clk request err\n"); rate = clk_get_rate(priv->clk); for (i = 0; rate && i < ARRAY_SIZE(ov6650_xclk); i++) { From f3c4ae273390a2b484e974d41e88c75b69766c88 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:26 +0200 Subject: [PATCH 00664/11391] media: i2c: ov7740: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov7740.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c index 1f1c0de8e510..632fb80469be 100644 --- a/drivers/media/i2c/ov7740.c +++ b/drivers/media/i2c/ov7740.c @@ -1036,13 +1036,10 @@ static int ov7740_probe(struct i2c_client *client) if (!ov7740) return -ENOMEM; - ov7740->xvclk = devm_clk_get(&client->dev, "xvclk"); - if (IS_ERR(ov7740->xvclk)) { - ret = PTR_ERR(ov7740->xvclk); - dev_err(&client->dev, - "OV7740: fail to get xvclk: %d\n", ret); - return ret; - } + ov7740->xvclk = devm_v4l2_sensor_clk_get(&client->dev, "xvclk"); + if (IS_ERR(ov7740->xvclk)) + return dev_err_probe(&client->dev, PTR_ERR(ov7740->xvclk), + "OV7740: fail to get xvclk\n"); ret = ov7740_probe_dt(client, ov7740); if (ret) From 4be64122c8da26a3bb698c5c8a38acfcd7de0b1b Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:27 +0200 Subject: [PATCH 00665/11391] media: i2c: ov8856: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov8856.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c index 4b6874d2a104..b85051f053ff 100644 --- a/drivers/media/i2c/ov8856.c +++ b/drivers/media/i2c/ov8856.c @@ -2274,12 +2274,10 @@ static int ov8856_get_hwcfg(struct ov8856 *ov8856, struct device *dev) return ret; if (!is_acpi_node(fwnode)) { - ov8856->xvclk = devm_clk_get(dev, "xvclk"); - if (IS_ERR(ov8856->xvclk)) { - dev_err_probe(dev, PTR_ERR(ov8856->xvclk), - "could not get xvclk clock\n"); - return PTR_ERR(ov8856->xvclk); - } + ov8856->xvclk = devm_v4l2_sensor_clk_get(dev, "xvclk"); + if (IS_ERR(ov8856->xvclk)) + return dev_err_probe(dev, PTR_ERR(ov8856->xvclk), + "could not get xvclk clock\n"); clk_set_rate(ov8856->xvclk, xvclk_rate); xvclk_rate = clk_get_rate(ov8856->xvclk); From 5ee9d47242c27f023248870eddcb721eaddfe9e5 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:28 +0200 Subject: [PATCH 00666/11391] media: i2c: ov8858: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov8858.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov8858.c b/drivers/media/i2c/ov8858.c index 95f9ae794846..c1c6bea8a68b 100644 --- a/drivers/media/i2c/ov8858.c +++ b/drivers/media/i2c/ov8858.c @@ -1877,7 +1877,7 @@ static int ov8858_probe(struct i2c_client *client) if (!ov8858) return -ENOMEM; - ov8858->xvclk = devm_clk_get(dev, "xvclk"); + ov8858->xvclk = devm_v4l2_sensor_clk_get(dev, "xvclk"); if (IS_ERR(ov8858->xvclk)) return dev_err_probe(dev, PTR_ERR(ov8858->xvclk), "Failed to get xvclk\n"); From c5f46dd95202218f36d9c275d99f44afbd0a9b88 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:29 +0200 Subject: [PATCH 00667/11391] media: i2c: ov8865: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Laurent Pinchart Reviewed-by: Lad Prabhakar Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov8865.c | 36 +++++------------------------------- 1 file changed, 5 insertions(+), 31 deletions(-) diff --git a/drivers/media/i2c/ov8865.c b/drivers/media/i2c/ov8865.c index a2138f7988aa..06582ce92588 100644 --- a/drivers/media/i2c/ov8865.c +++ b/drivers/media/i2c/ov8865.c @@ -2956,7 +2956,6 @@ static int ov8865_probe(struct i2c_client *client) struct ov8865_sensor *sensor; struct v4l2_subdev *subdev; struct media_pad *pad; - unsigned int rate = 0; unsigned int i; int ret; @@ -3020,39 +3019,14 @@ static int ov8865_probe(struct i2c_client *client) /* External Clock */ - sensor->extclk = devm_clk_get(dev, NULL); - if (PTR_ERR(sensor->extclk) == -ENOENT) { - dev_info(dev, "no external clock found, continuing...\n"); - sensor->extclk = NULL; - } else if (IS_ERR(sensor->extclk)) { - dev_err(dev, "failed to get external clock\n"); - ret = PTR_ERR(sensor->extclk); + sensor->extclk = devm_v4l2_sensor_clk_get(dev, NULL); + if (IS_ERR(sensor->extclk)) { + ret = dev_err_probe(dev, PTR_ERR(sensor->extclk), + "failed to get external clock\n"); goto error_endpoint; } - /* - * We could have either a 24MHz or 19.2MHz clock rate from either dt or - * ACPI...but we also need to support the weird IPU3 case which will - * have an external clock AND a clock-frequency property. Check for the - * clock-frequency property and if found, set that rate if we managed - * to acquire a clock. This should cover the ACPI case. If the system - * uses devicetree then the configured rate should already be set, so - * we can just read it. - */ - ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", - &rate); - if (!ret && sensor->extclk) { - ret = clk_set_rate(sensor->extclk, rate); - if (ret) { - dev_err_probe(dev, ret, "failed to set clock rate\n"); - goto error_endpoint; - } - } else if (ret && !sensor->extclk) { - dev_err_probe(dev, ret, "invalid clock config\n"); - goto error_endpoint; - } - - sensor->extclk_rate = rate ? rate : clk_get_rate(sensor->extclk); + sensor->extclk_rate = clk_get_rate(sensor->extclk); for (i = 0; i < ARRAY_SIZE(supported_extclk_rates); i++) { if (sensor->extclk_rate == supported_extclk_rates[i]) From 220150677061268d1e33ca27e5cf03823636dcbd Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:30 +0200 Subject: [PATCH 00668/11391] media: i2c: ov9282: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov9282.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/ov9282.c b/drivers/media/i2c/ov9282.c index c882a021cf18..a9f6176e9729 100644 --- a/drivers/media/i2c/ov9282.c +++ b/drivers/media/i2c/ov9282.c @@ -1135,11 +1135,10 @@ static int ov9282_parse_hw_config(struct ov9282 *ov9282) } /* Get sensor input clock */ - ov9282->inclk = devm_clk_get(ov9282->dev, NULL); - if (IS_ERR(ov9282->inclk)) { - dev_err(ov9282->dev, "could not get inclk"); - return PTR_ERR(ov9282->inclk); - } + ov9282->inclk = devm_v4l2_sensor_clk_get(ov9282->dev, NULL); + if (IS_ERR(ov9282->inclk)) + return dev_err_probe(ov9282->dev, PTR_ERR(ov9282->inclk), + "could not get inclk\n"); ret = ov9282_configure_regulators(ov9282); if (ret) From f9f6ebba712ece9e61d99f7d092891e026926bfa Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:31 +0200 Subject: [PATCH 00669/11391] media: i2c: ov9640: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov9640.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ov9640.c b/drivers/media/i2c/ov9640.c index 01dbc0ba89c8..2190c52b1433 100644 --- a/drivers/media/i2c/ov9640.c +++ b/drivers/media/i2c/ov9640.c @@ -718,9 +718,10 @@ static int ov9640_probe(struct i2c_client *client) priv->subdev.ctrl_handler = &priv->hdl; - priv->clk = devm_clk_get(&client->dev, "mclk"); + priv->clk = devm_v4l2_sensor_clk_get(&client->dev, "mclk"); if (IS_ERR(priv->clk)) { - ret = PTR_ERR(priv->clk); + ret = dev_err_probe(&client->dev, PTR_ERR(priv->clk), + "failed to get mclk\n"); goto ectrlinit; } From 1808dd608f856b4cae1dd42c4bdc83fdef215b47 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:32 +0200 Subject: [PATCH 00670/11391] media: i2c: ov9650: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov9650.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c index 026ea34d6291..c94e8fe29f22 100644 --- a/drivers/media/i2c/ov9650.c +++ b/drivers/media/i2c/ov9650.c @@ -1494,9 +1494,10 @@ static int ov965x_probe(struct i2c_client *client) } if (dev_fwnode(&client->dev)) { - ov965x->clk = devm_clk_get(&client->dev, NULL); + ov965x->clk = devm_v4l2_sensor_clk_get(&client->dev, NULL); if (IS_ERR(ov965x->clk)) - return PTR_ERR(ov965x->clk); + return dev_err_probe(&client->dev, PTR_ERR(ov965x->clk), + "failed to get the clock\n"); ov965x->mclk_frequency = clk_get_rate(ov965x->clk); ret = ov965x_configure_gpios(ov965x); From 54ec6f9c6f60562f8da5a9e3e55506d5cd5162b0 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:33 +0200 Subject: [PATCH 00671/11391] media: i2c: s5c73m3: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/s5c73m3/s5c73m3-core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index 7716dfe2b8c9..088184da5dea 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c @@ -1556,9 +1556,11 @@ static int s5c73m3_get_dt_data(struct s5c73m3 *state) if (!node) return -EINVAL; - state->clock = devm_clk_get(dev, S5C73M3_CLK_NAME); + state->clock = devm_v4l2_sensor_clk_get(dev, S5C73M3_CLK_NAME); if (IS_ERR(state->clock)) - return PTR_ERR(state->clock); + return dev_err_probe(dev, PTR_ERR(state->clock), + "Failed to get the clock %s\n", + S5C73M3_CLK_NAME); if (of_property_read_u32(node, "clock-frequency", &state->mclk_frequency)) { From 2db026f2e90b6fdda0d2ab3a340d3855e49f965f Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:34 +0200 Subject: [PATCH 00672/11391] media: i2c: s5k5baf: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/s5k5baf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c index 24f399cd2124..01d37f49e5ad 100644 --- a/drivers/media/i2c/s5k5baf.c +++ b/drivers/media/i2c/s5k5baf.c @@ -1967,7 +1967,7 @@ static int s5k5baf_probe(struct i2c_client *c) if (ret < 0) goto err_me; - state->clock = devm_clk_get(state->sd.dev, S5K5BAF_CLK_NAME); + state->clock = devm_v4l2_sensor_clk_get(state->sd.dev, S5K5BAF_CLK_NAME); if (IS_ERR(state->clock)) { ret = -EPROBE_DEFER; goto err_me; From 7f5af01769c4099b2716d6997da10dedad289a4f Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:35 +0200 Subject: [PATCH 00673/11391] media: i2c: s5k6a3: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/s5k6a3.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/s5k6a3.c b/drivers/media/i2c/s5k6a3.c index 0c2674115b7b..4bf5f122b113 100644 --- a/drivers/media/i2c/s5k6a3.c +++ b/drivers/media/i2c/s5k6a3.c @@ -292,9 +292,10 @@ static int s5k6a3_probe(struct i2c_client *client) mutex_init(&sensor->lock); sensor->dev = dev; - sensor->clock = devm_clk_get(sensor->dev, S5K6A3_CLK_NAME); + sensor->clock = devm_v4l2_sensor_clk_get(sensor->dev, S5K6A3_CLK_NAME); if (IS_ERR(sensor->clock)) - return PTR_ERR(sensor->clock); + return dev_err_probe(sensor->dev, PTR_ERR(sensor->clock), + "failed to get extclk\n"); sensor->gpio_reset = devm_gpiod_get(dev, NULL, GPIOD_OUT_HIGH); ret = PTR_ERR_OR_ZERO(sensor->gpio_reset); From e55df3c6602722991dfaae4232b560c07b29a38a Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:36 +0200 Subject: [PATCH 00674/11391] media: i2c: vd55g1: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/vd55g1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/vd55g1.c b/drivers/media/i2c/vd55g1.c index c0754fd03b1d..b89fff7e11f8 100644 --- a/drivers/media/i2c/vd55g1.c +++ b/drivers/media/i2c/vd55g1.c @@ -1863,7 +1863,7 @@ static int vd55g1_probe(struct i2c_client *client) if (ret) return dev_err_probe(dev, ret, "Failed to get regulators\n"); - sensor->xclk = devm_clk_get(dev, NULL); + sensor->xclk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(sensor->xclk)) return dev_err_probe(dev, PTR_ERR(sensor->xclk), "Failed to get xclk\n"); From 19248489e86eee761bbb76aa2446fb4da0aa9470 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:37 +0200 Subject: [PATCH 00675/11391] media: i2c: vd56g3: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/vd56g3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/vd56g3.c b/drivers/media/i2c/vd56g3.c index 5d951ad0b478..ac3e868dbb43 100644 --- a/drivers/media/i2c/vd56g3.c +++ b/drivers/media/i2c/vd56g3.c @@ -1474,7 +1474,7 @@ static int vd56g3_probe(struct i2c_client *client) if (ret) return dev_err_probe(dev, ret, "Failed to get regulators\n"); - sensor->xclk = devm_clk_get(dev, NULL); + sensor->xclk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(sensor->xclk)) return dev_err_probe(dev, PTR_ERR(sensor->xclk), "Failed to get xclk\n"); From 51d79d123b615ac83aa0f4bad988c2c6a29bf986 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:38 +0200 Subject: [PATCH 00676/11391] media: i2c: vgxy61: Use the v4l2 helper for obtaining the clock devm_clk_get() fails on ACPI-based platforms, where firmware does not provide a direct reference to the clock producer. Replace devm_clk_get() with the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/vgxy61.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/vgxy61.c b/drivers/media/i2c/vgxy61.c index 5b0479f3a3c0..3d001e0b646b 100644 --- a/drivers/media/i2c/vgxy61.c +++ b/drivers/media/i2c/vgxy61.c @@ -1761,11 +1761,11 @@ static int vgxy61_probe(struct i2c_client *client) return ret; } - sensor->xclk = devm_clk_get(dev, NULL); - if (IS_ERR(sensor->xclk)) { - dev_err(dev, "failed to get xclk\n"); - return PTR_ERR(sensor->xclk); - } + sensor->xclk = devm_v4l2_sensor_clk_get(dev, NULL); + if (IS_ERR(sensor->xclk)) + return dev_err_probe(dev, PTR_ERR(sensor->xclk), + "failed to get xclk\n"); + sensor->clk_freq = clk_get_rate(sensor->xclk); if (sensor->clk_freq < 6 * HZ_PER_MHZ || sensor->clk_freq > 27 * HZ_PER_MHZ) { From 380e6896c2234b677c6f8ab1bfb7621645708cc1 Mon Sep 17 00:00:00 2001 From: Mehdi Djait Date: Thu, 26 Jun 2025 15:34:39 +0200 Subject: [PATCH 00677/11391] media: i2c: ov2680: Use the v4l2 helper for obtaining the clock Use the new v4l2 helper devm_v4l2_sensor_clk_get() that works on both DT- and ACPI-based platforms to retrieve a reference to the clock producer from firmware. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Mehdi Djait Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov2680.c | 29 ++--------------------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/drivers/media/i2c/ov2680.c b/drivers/media/i2c/ov2680.c index 7237fb27ecd0..78e63bd1b35b 100644 --- a/drivers/media/i2c/ov2680.c +++ b/drivers/media/i2c/ov2680.c @@ -1079,7 +1079,6 @@ static int ov2680_parse_dt(struct ov2680_dev *sensor) struct device *dev = sensor->dev; struct fwnode_handle *ep_fwnode; struct gpio_desc *gpio; - unsigned int rate = 0; int i, ret; /* @@ -1114,38 +1113,14 @@ static int ov2680_parse_dt(struct ov2680_dev *sensor) sensor->pwdn_gpio = gpio; - sensor->xvclk = devm_clk_get_optional(dev, "xvclk"); + sensor->xvclk = devm_v4l2_sensor_clk_get(dev, "xvclk"); if (IS_ERR(sensor->xvclk)) { ret = dev_err_probe(dev, PTR_ERR(sensor->xvclk), "xvclk clock missing or invalid\n"); goto out_free_bus_cfg; } - /* - * We could have either a 24MHz or 19.2MHz clock rate from either DT or - * ACPI... but we also need to support the weird IPU3 case which will - * have an external clock AND a clock-frequency property. Check for the - * clock-frequency property and if found, set that rate if we managed - * to acquire a clock. This should cover the ACPI case. If the system - * uses devicetree then the configured rate should already be set, so - * we can just read it. - */ - ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", - &rate); - if (ret && !sensor->xvclk) { - dev_err_probe(dev, ret, "invalid clock config\n"); - goto out_free_bus_cfg; - } - - if (!ret && sensor->xvclk) { - ret = clk_set_rate(sensor->xvclk, rate); - if (ret) { - dev_err_probe(dev, ret, "failed to set clock rate\n"); - goto out_free_bus_cfg; - } - } - - sensor->xvclk_freq = rate ?: clk_get_rate(sensor->xvclk); + sensor->xvclk_freq = clk_get_rate(sensor->xvclk); for (i = 0; i < ARRAY_SIZE(ov2680_xvclk_freqs); i++) { if (sensor->xvclk_freq == ov2680_xvclk_freqs[i]) From 5c36b86d2bf68fbcad16169983ef7ee8c537db59 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 13 Aug 2025 15:07:18 +0200 Subject: [PATCH 00678/11391] regmap: Remove superfluous check for !config in __regmap_init() The first thing __regmap_init() do is check if config is non-NULL, so there is no need to check for this again later. Fixes: d77e745613680c54 ("regmap: Add bulk read/write callbacks into regmap_config") Signed-off-by: Geert Uytterhoeven Link: https://patch.msgid.link/a154d9db0f290dda96b48bd817eb743773e846e1.1755090330.git.geert+renesas@glider.be Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 1f3f782a04ba..6883e1a43fe5 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -827,7 +827,7 @@ struct regmap *__regmap_init(struct device *dev, map->read_flag_mask = bus->read_flag_mask; } - if (config && config->read && config->write) { + if (config->read && config->write) { map->reg_read = _regmap_bus_read; if (config->reg_update_bits) map->reg_update_bits = config->reg_update_bits; From 09449e48be7390ebc53812ab898d669e3832c704 Mon Sep 17 00:00:00 2001 From: Jayesh Choudhary Date: Wed, 16 Jul 2025 11:31:08 +0530 Subject: [PATCH 00679/11391] arm64: dts: ti: k3-j784s4-j742s2-main-common: Add DSI & DSI PHY Add DT nodes for DPI to DSI Bridge and DSI Phy. The DSI bridge is Cadence DSI and the PHY is a Cadence DPHY with TI wrapper. Signed-off-by: Jayesh Choudhary Tested-by: Harikrishna Shenoy Reviewed-by: Harikrishna Shenoy Reviewed-by: Udit Kumar Link: https://lore.kernel.org/r/20250716060114.52122-2-j-choudhary@ti.com Signed-off-by: Nishanth Menon --- .../dts/ti/k3-j784s4-j742s2-main-common.dtsi | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi index 7c5b0c69897d..79d97d46b4c6 100644 --- a/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi @@ -2522,6 +2522,45 @@ watchdog18: watchdog@2550000 { status = "reserved"; }; + dphy_tx0: phy@4480000 { + compatible = "ti,j721e-dphy"; + reg = <0x00 0x04480000 0x00 0x00001000>; + clocks = <&k3_clks 402 20>, <&k3_clks 402 3>; + clock-names = "psm", "pll_ref"; + #phy-cells = <0>; + power-domains = <&k3_pds 402 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 402 3>; + assigned-clock-parents = <&k3_clks 402 4>; + assigned-clock-rates = <19200000>; + status = "disabled"; + }; + + dsi0: dsi@4800000 { + compatible = "ti,j721e-dsi"; + reg = <0x00 0x04800000 0x00 0x00100000>, + <0x00 0x04710000 0x00 0x00000100>; + clocks = <&k3_clks 215 2>, <&k3_clks 215 5>; + clock-names = "dsi_p_clk", "dsi_sys_clk"; + power-domains = <&k3_pds 215 TI_SCI_PD_EXCLUSIVE>; + interrupts = ; + phys = <&dphy_tx0>; + phy-names = "dphy"; + status = "disabled"; + + dsi0_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + }; + + port@1 { + reg = <1>; + }; + }; + }; + mhdp: bridge@a000000 { compatible = "ti,j721e-mhdp8546"; reg = <0x0 0xa000000 0x0 0x30a00>, From a5ed774877a38f2feeb45f0c2cd16184b47b476b Mon Sep 17 00:00:00 2001 From: Jayesh Choudhary Date: Wed, 16 Jul 2025 11:31:09 +0530 Subject: [PATCH 00680/11391] arm64: dts: ti: k3-j784s4-j742s2-evm-common: Enable DisplayPort-1 Enable DSI display for J784S4 EVM. Add DT node for DSI-to-eDP bridge. The DSI to eDP bridge is SN65DSI86 on the board. Add the endpoint nodes to describe connection from: DSS => DSI => SN65DSI86 bridge => DisplayPort-1 Signed-off-by: Jayesh Choudhary Tested-by: Harikrishna Shenoy Reviewed-by: Harikrishna Shenoy Reviewed-by: Udit Kumar Link: https://lore.kernel.org/r/20250716060114.52122-3-j-choudhary@ti.com Signed-off-by: Nishanth Menon --- .../dts/ti/k3-j784s4-j742s2-evm-common.dtsi | 121 +++++++++++++++++- 1 file changed, 120 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-evm-common.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-evm-common.dtsi index fa656b7b13a1..6afa802544e9 100644 --- a/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-evm-common.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-evm-common.dtsi @@ -301,6 +301,52 @@ codec_audio: sound { clock-names = "cpb-mcasp-auxclk", "cpb-mcasp-auxclk-48000", "cpb-codec-scki", "cpb-codec-scki-48000"; }; + + vsys_io_1v8: regulator-vsys-io-1v8 { + compatible = "regulator-fixed"; + regulator-name = "vsys_io_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + vsys_io_1v2: regulator-vsys-io-1v2 { + compatible = "regulator-fixed"; + regulator-name = "vsys_io_1v2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + regulator-boot-on; + }; + + edp1_refclk: clock-edp1-refclk { + compatible = "fixed-clock"; + clock-frequency = <19200000>; + #clock-cells = <0>; + }; + + dp1_pwr_3v3: regulator-dp1-prw { + compatible = "regulator-fixed"; + regulator-name = "dp1-pwr"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&exp4 1 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + dp1: connector-dp1 { + compatible = "dp-connector"; + label = "DP1"; + type = "full-size"; + dp-pwr-supply = <&dp1_pwr_3v3>; + + port { + dp1_connector_in: endpoint { + remote-endpoint = <&dp1_out>; + }; + }; + }; }; &wkup_gpio0 { @@ -1340,12 +1386,26 @@ &mhdp { }; &dss_ports { + #address-cells = <1>; + #size-cells = <0>; + /* DP */ - port { + port@0 { + reg = <0>; + dpi0_out: endpoint { remote-endpoint = <&dp0_in>; }; }; + + /* DSI */ + port@2 { + reg = <2>; + + dpi2_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; }; &main_i2c4 { @@ -1360,6 +1420,65 @@ exp4: gpio@20 { gpio-controller; #gpio-cells = <2>; }; + + bridge_dsi_edp: bridge-dsi-edp@2c { + compatible = "ti,sn65dsi86"; + reg = <0x2c>; + clock-names = "refclk"; + clocks = <&edp1_refclk>; + enable-gpios = <&exp4 2 GPIO_ACTIVE_HIGH>; + vpll-supply = <&vsys_io_1v8>; + vccio-supply = <&vsys_io_1v8>; + vcca-supply = <&vsys_io_1v2>; + vcc-supply = <&vsys_io_1v2>; + + dsi_edp_bridge_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + dp1_in: endpoint { + remote-endpoint = <&dsi0_out>; + }; + }; + + port@1 { + reg = <1>; + + dp1_out: endpoint { + remote-endpoint = <&dp1_connector_in>; + }; + }; + }; + }; +}; + +&dsi0_ports { + port@0 { + reg = <0>; + + dsi0_out: endpoint { + remote-endpoint = <&dp1_in>; + }; + }; + + port@1 { + reg = <1>; + + dsi0_in: endpoint { + remote-endpoint = <&dpi2_out>; + }; + }; +}; + +&dphy_tx0 { + status = "okay"; +}; + +&dsi0 { + status = "okay"; }; &dp0_ports { From 19a4472e591d9945f4983d052adf7d7fa67efcce Mon Sep 17 00:00:00 2001 From: Rahul T R Date: Wed, 16 Jul 2025 11:31:10 +0530 Subject: [PATCH 00681/11391] arm64: dts: ti: k3-j721s2-main: Add DSI & DSI PHY Add DT nodes for DPI to DSI Bridge and DSI Phy. The DSI bridge is Cadence DSI and the PHY is a Cadence DPHY with TI wrapper. Signed-off-by: Rahul T R [j-choudhary@ti.com: disable dsi and dphy nodes, rename dphy node] Signed-off-by: Jayesh Choudhary Tested-by: Harikrishna Shenoy Reviewed-by: Harikrishna Shenoy Reviewed-by: Udit Kumar Link: https://lore.kernel.org/r/20250716060114.52122-4-j-choudhary@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi | 39 ++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi b/arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi index 62f45377a2c9..c31d7f3eab28 100644 --- a/arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi @@ -1795,6 +1795,45 @@ main_spi7: spi@2170000 { status = "disabled"; }; + dphy_tx0: phy@4480000 { + compatible = "ti,j721e-dphy"; + reg = <0x00 0x04480000 0x00 0x00001000>; + clocks = <&k3_clks 363 8>, <&k3_clks 363 14>; + clock-names = "psm", "pll_ref"; + #phy-cells = <0>; + power-domains = <&k3_pds 363 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 363 14>; + assigned-clock-parents = <&k3_clks 363 15>; + assigned-clock-rates = <19200000>; + status = "disabled"; + }; + + dsi0: dsi@4800000 { + compatible = "ti,j721e-dsi"; + reg = <0x00 0x04800000 0x00 0x00100000>, + <0x00 0x04710000 0x00 0x00000100>; + clocks = <&k3_clks 154 4>, <&k3_clks 154 1>; + clock-names = "dsi_p_clk", "dsi_sys_clk"; + power-domains = <&k3_pds 154 TI_SCI_PD_EXCLUSIVE>; + interrupts = ; + phys = <&dphy_tx0>; + phy-names = "dphy"; + status = "disabled"; + + dsi0_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + }; + + port@1 { + reg = <1>; + }; + }; + }; + dss: dss@4a00000 { compatible = "ti,j721e-dss"; reg = <0x00 0x04a00000 0x00 0x10000>, /* common_m */ From 722a128adaf97fc2ecb64610a482f1399b3f4c2a Mon Sep 17 00:00:00 2001 From: Jayesh Choudhary Date: Wed, 16 Jul 2025 11:31:11 +0530 Subject: [PATCH 00682/11391] arm64: dts: ti: k3-j721s2-common-proc-board: Add main_i2c4 instance Add dt node for main_i2c4 instance along with required pinmuxing. Also add the gpio expander 'exp4' required by display connector. Signed-off-by: Jayesh Choudhary Tested-by: Harikrishna Shenoy Reviewed-by: Harikrishna Shenoy Reviewed-by: Udit Kumar Link: https://lore.kernel.org/r/20250716060114.52122-5-j-choudhary@ti.com Signed-off-by: Nishanth Menon --- .../dts/ti/k3-j721s2-common-proc-board.dts | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts b/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts index e2fc1288ed07..793d50344fad 100644 --- a/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts +++ b/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts @@ -148,6 +148,13 @@ J721S2_IOPAD(0x060, PIN_INPUT_PULLUP, 13) /* (AC27) MCASP2_AXR1.I2C3_SDA */ >; }; + main_i2c4_pins_default: main-i2c4-default-pins { + pinctrl-single,pins = < + J721S2_IOPAD(0x014, PIN_INPUT_PULLUP, 8) /* (AD25) I2C4_SCL */ + J721S2_IOPAD(0x010, PIN_INPUT_PULLUP, 8) /* (AF28) I2C4_SDA */ + >; + }; + main_i2c5_pins_default: main-i2c5-default-pins { pinctrl-single,pins = < J721S2_IOPAD(0x01c, PIN_INPUT, 8) /* (Y24) MCAN15_TX.I2C5_SCL */ @@ -370,6 +377,23 @@ exp2: gpio@22 { }; }; +&main_i2c4 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c4_pins_default>; + clock-frequency = <400000>; + + exp4: gpio@20 { + compatible = "ti,tca6408"; + reg = <0x20>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "DP0_PWR_SW_EN", "DP1_PWR_SW_EN", "UB981_PDB", + "UB981_GPIO0", "UB981_GPIO1", "UB981_GPIO2", + "UB981_GPIO3", "PWR_SW_CNTL_DSI0#"; + }; +}; + &main_i2c5 { pinctrl-names = "default"; pinctrl-0 = <&main_i2c5_pins_default>; From 3c29300dcef587df697750e99f6375e2ca8907fb Mon Sep 17 00:00:00 2001 From: Rahul T R Date: Wed, 16 Jul 2025 11:31:12 +0530 Subject: [PATCH 00683/11391] arm64: dts: ti: k3-j721s2-som-p0: Add DSI to eDP Add DT nodes for DSI to eDP bridge. The DSI to eDP bridge used is SN65DSI86 on SOM. Signed-off-by: Rahul T R Signed-off-by: Jayesh Choudhary Tested-by: Harikrishna Shenoy Reviewed-by: Harikrishna Shenoy Reviewed-by: Udit Kumar Link: https://lore.kernel.org/r/20250716060114.52122-6-j-choudhary@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-j721s2-som-p0.dtsi | 51 ++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/arch/arm64/boot/dts/ti/k3-j721s2-som-p0.dtsi b/arch/arm64/boot/dts/ti/k3-j721s2-som-p0.dtsi index 54fc5c4f8c3f..a9dbe14fb0c9 100644 --- a/arch/arm64/boot/dts/ti/k3-j721s2-som-p0.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j721s2-som-p0.dtsi @@ -152,6 +152,30 @@ transceiver0: can-phy0 { #phy-cells = <0>; max-bitrate = <5000000>; }; + + vsys_io_1v8: regulator-vsys-io-1v8 { + compatible = "regulator-fixed"; + regulator-name = "vsys_io_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + vsys_io_1v2: regulator-vsys-io-1v2 { + compatible = "regulator-fixed"; + regulator-name = "vsys_io_1v2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + regulator-boot-on; + }; + + edp1_refclk: clock-edp1-refclk { + compatible = "fixed-clock"; + clock-frequency = <19200000>; + #clock-cells = <0>; + }; }; &wkup_pmx0 { @@ -630,3 +654,30 @@ &c71_1 { memory-region = <&c71_1_dma_memory_region>, <&c71_1_memory_region>; }; + +&main_i2c4 { + bridge_dsi_edp: bridge-dsi-edp@2c { + compatible = "ti,sn65dsi86"; + reg = <0x2c>; + clock-names = "refclk"; + clocks = <&edp1_refclk>; + enable-gpios = <&exp_som 5 0>; + vpll-supply = <&vsys_io_1v8>; + vccio-supply = <&vsys_io_1v8>; + vcca-supply = <&vsys_io_1v2>; + vcc-supply = <&vsys_io_1v2>; + + dsi_edp_bridge_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + }; + + port@1 { + reg = <1>; + }; + }; + }; +}; From 2bca9f69225e8c6e3c270f20c69a1460761f9bd2 Mon Sep 17 00:00:00 2001 From: Jayesh Choudhary Date: Wed, 16 Jul 2025 11:31:13 +0530 Subject: [PATCH 00684/11391] arm64: dts: ti: k3-j721s2-common-proc-board: Enable DisplayPort-1 Enable DSI display for J721S2 EVM. Add the endpoint nodes to describe connection from: DSS => DSI Bridge => DSI to eDP bridge => DisplayPort-1 Signed-off-by: Jayesh Choudhary Tested-by: Harikrishna Shenoy Reviewed-by: Harikrishna Shenoy Reviewed-by: Udit Kumar Link: https://lore.kernel.org/r/20250716060114.52122-7-j-choudhary@ti.com Signed-off-by: Nishanth Menon --- .../dts/ti/k3-j721s2-common-proc-board.dts | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts b/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts index 793d50344fad..9e43dcff8ef2 100644 --- a/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts +++ b/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts @@ -93,6 +93,28 @@ vdd_sd_dv: gpio-regulator-TLV71033 { <3300000 0x1>; }; + dp1_pwr_3v3: regulator-dp1-prw { + compatible = "regulator-fixed"; + regulator-name = "dp1-pwr"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&exp4 1 GPIO_ACTIVE_HIGH>; /* P1 - DP1_PWR_SW_EN */ + enable-active-high; + }; + + dp1: connector-dp1 { + compatible = "dp-connector"; + label = "DP1"; + type = "full-size"; + dp-pwr-supply = <&dp1_pwr_3v3>; + + port { + dp1_connector_in: endpoint { + remote-endpoint = <&dp1_out>; + }; + }; + }; + transceiver1: can-phy1 { compatible = "ti,tcan1043"; #phy-cells = <0>; @@ -563,3 +585,74 @@ &main_mcan5 { pinctrl-0 = <&main_mcan5_pins_default>; phys = <&transceiver4>; }; + +&dss { + /* + * DSS on J721S2-EVM supports DP on VP0 and DSI on VP2. + * These clock assignments are chosen to enable the following outputs: + * VP0 - DisplayPort SST + * VP2 - DSI + */ + status = "okay"; + assigned-clocks = <&k3_clks 158 2>, + <&k3_clks 158 14>; + assigned-clock-parents = <&k3_clks 158 3>, + <&k3_clks 158 16>; +}; + +&dss_ports { + #address-cells = <1>; + #size-cells = <0>; + + port@2 { + reg = <2>; + + dpi2_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; +}; + +&dsi0_ports { + port@0 { + reg = <0>; + + dsi0_out: endpoint { + remote-endpoint = <&dp1_in>; + }; + }; + + port@1 { + reg = <1>; + + dsi0_in: endpoint { + remote-endpoint = <&dpi2_out>; + }; + }; +}; + +&dsi_edp_bridge_ports { + port@0 { + reg = <0>; + + dp1_in: endpoint { + remote-endpoint = <&dsi0_out>; + }; + }; + + port@1 { + reg = <1>; + + dp1_out: endpoint { + remote-endpoint = <&dp1_connector_in>; + }; + }; +}; + +&dphy_tx0 { + status = "okay"; +}; + +&dsi0 { + status = "okay"; +}; From 11b9e4517bfa8edecbef0acfcad1bdca4f4a4192 Mon Sep 17 00:00:00 2001 From: Jayesh Choudhary Date: Wed, 16 Jul 2025 11:31:14 +0530 Subject: [PATCH 00685/11391] arm64: dts: ti: k3-am68-sk: Enable DSI on DisplayPort-0 Enable DSI support for AM68-SK platform. Add DT node for DSI2eDP bridge. The DSI to eDP bridge is sn65dsi86 on the board. Add the endpoint nodes to describe connection from: DSS => DSI => SN65DSI86 bridge => DisplayPort-0 Signed-off-by: Jayesh Choudhary Tested-by: Harikrishna Shenoy Reviewed-by: Harikrishna Shenoy Reviewed-by: Udit Kumar Link: https://lore.kernel.org/r/20250716060114.52122-8-j-choudhary@ti.com Signed-off-by: Nishanth Menon --- .../boot/dts/ti/k3-am68-sk-base-board.dts | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts b/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts index e84c504c87d2..75a107456ce1 100644 --- a/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts +++ b/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts @@ -135,6 +135,34 @@ transceiver4: can-phy3 { max-bitrate = <5000000>; }; + edp0_refclk: clock-edp0-refclk { + compatible = "fixed-clock"; + clock-frequency = <19200000>; + #clock-cells = <0>; + }; + + dp0_pwr_3v3: regulator-dp0-pwr { + compatible = "regulator-fixed"; + regulator-name = "dp0-pwr"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&exp2 2 GPIO_ACTIVE_HIGH>; /*P0 - DP0_3V3 _EN */ + enable-active-high; + }; + + dp0: dp0-connector { + compatible = "dp-connector"; + label = "DP0"; + type = "full-size"; + dp-pwr-supply = <&dp0_pwr_3v3>; + + port { + dp0_connector_in: endpoint { + remote-endpoint = <&dp0_out>; + }; + }; + }; + connector-hdmi { compatible = "hdmi-connector"; label = "hdmi"; @@ -615,6 +643,39 @@ exp2: gpio@20 { gpio-line-names = "HDMI_PDn","HDMI_LS_OE", "DP0_3V3_EN","eDP_ENABLE"; }; + + bridge_dsi_edp: bridge-dsi-edp@2c { + compatible = "ti,sn65dsi86"; + reg = <0x2c>; + clock-names = "refclk"; + clocks = <&edp0_refclk>; + enable-gpios = <&exp2 3 GPIO_ACTIVE_HIGH>; + vpll-supply = <&vsys_io_1v8>; + vccio-supply = <&vsys_io_1v8>; + vcca-supply = <&vsys_io_1v2>; + vcc-supply = <&vsys_io_1v2>; + + dsi_edp_bridge_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + dp0_in: endpoint { + remote-endpoint = <&dsi0_out>; + }; + }; + + port@1 { + reg = <1>; + + dp0_out: endpoint { + remote-endpoint = <&dp0_connector_in>; + }; + }; + }; + }; }; &main_sdhci1 { @@ -711,6 +772,15 @@ dpi_out0: endpoint { remote-endpoint = <&tfp410_in>; }; }; + + /* DSI */ + port@2 { + reg = <2>; + + dpi0_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; }; &serdes_ln_ctrl { @@ -768,3 +838,30 @@ &usb0 { phys = <&serdes0_usb_link>; phy-names = "cdns3,usb3-phy"; }; + +&dphy_tx0 { + status = "okay"; +}; + +&dsi0 { + status = "okay"; +}; + +&dsi0_ports { + + port@0 { + reg = <0>; + + dsi0_out: endpoint { + remote-endpoint = <&dp0_in>; + }; + }; + + port@1 { + reg = <1>; + + dsi0_in: endpoint { + remote-endpoint = <&dpi0_out>; + }; + }; +}; From 6aa4c1a38cf10c9760f81d456b7f92ff157e5f83 Mon Sep 17 00:00:00 2001 From: Wadim Egorov Date: Mon, 4 Aug 2025 12:54:50 +0200 Subject: [PATCH 00686/11391] arm64: dts: ti: k3-am642-phyboard-electra: Add ti,pa-stats property Add ti,pa-stats phandles. This is a phandle to PA_STATS syscon regmap and will be used to dump IET related statistics for ICSSG Driver. Signed-off-by: Wadim Egorov Link: https://lore.kernel.org/r/20250804105450.2322647-1-w.egorov@phytec.de Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts b/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts index 129524eb5b91..e4afa8c0a8ca 100644 --- a/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts +++ b/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts @@ -100,6 +100,7 @@ ethernet { ti,mii-g-rt = <&icssg0_mii_g_rt>; ti,mii-rt = <&icssg0_mii_rt>; ti,iep = <&icssg0_iep0>, <&icssg0_iep1>; + ti,pa-stats = <&icssg0_pa_stats>; ethernet-ports { #address-cells = <1>; From f13db4f77d54a6db644f09a168919ad1b3432f52 Mon Sep 17 00:00:00 2001 From: Wadim Egorov Date: Tue, 5 Aug 2025 11:00:21 +0200 Subject: [PATCH 00687/11391] arm64: dts: ti: k3-am62a-phycore-som: Add 1.4GHz opp entry The phyCORE-AM62Ax is capable of supplying 0v85 to the VDD_CORE which allows the Cortex-A53s to operate at 1.4GHz according to chapter 7.5 of the SoC's data sheet[0]. Append the 1.4Ghz entry to the OPP table to enable this OPP [0] https://www.ti.com/lit/ds/symlink/am62a3.pdf Signed-off-by: Wadim Egorov Link: https://lore.kernel.org/r/20250805090021.1407753-2-w.egorov@phytec.de Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am62a-phycore-som.dtsi | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm64/boot/dts/ti/k3-am62a-phycore-som.dtsi b/arch/arm64/boot/dts/ti/k3-am62a-phycore-som.dtsi index 5dc5d2cb20cc..207ca00630d1 100644 --- a/arch/arm64/boot/dts/ti/k3-am62a-phycore-som.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62a-phycore-som.dtsi @@ -200,6 +200,15 @@ AM62AX_IOPAD(0x1f4, PIN_INPUT, 0) /* (D16) EXTINTn */ }; }; +&a53_opp_table { + /* Requires VDD_CORE at 0v85 */ + opp-1400000000 { + opp-hz = /bits/ 64 <1400000000>; + opp-supported-hw = <0x01 0x0004>; + clock-latency-ns = <6000000>; + }; +}; + &c7x_0 { mboxes = <&mailbox0_cluster1 &mbox_c7x_0>; memory-region = <&c7x_0_dma_memory_region>, From 94801d4bf1ed9277462ebe1afaf8323664fd6a85 Mon Sep 17 00:00:00 2001 From: Yemike Abhilash Chandra Date: Fri, 8 Aug 2025 15:27:58 +0530 Subject: [PATCH 00688/11391] arm64: dts: ti: k3-j721s2-main: Add CSI2 interrupts property Add interrupts property for CDNS CSI2RX. Interrupt IDs are taken from the J721S2 TRM [0]. Interrupt Line | Source Interrupt --------------------|----------------------------- GIC500SS_SPI_IN_185 | CSI_RX_IF0_CSI_ERR_IRQ_OUT_0 GIC500SS_SPI_IN_184 | CSI_RX_IF0_CSI_IRQ_OUT_0 GIC500SS_SPI_IN_189 | CSI_RX_IF1_CSI_ERR_IRQ_OUT_0 GIC500SS_SPI_IN_188 | CSI_RX_IF1_CSI_IRQ_OUT_0 [0]: https://www.ti.com/lit/zip/spruj28 Signed-off-by: Yemike Abhilash Chandra Reviewed-by: Udit Kumar Reviewed-by: Jared McArthur Link: https://lore.kernel.org/r/20250808095804.544298-2-y-abhilashchandra@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi b/arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi index c31d7f3eab28..726374dc8795 100644 --- a/arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi @@ -1248,6 +1248,9 @@ ti_csi2rx0: ticsi2rx@4500000 { cdns_csi2rx0: csi-bridge@4504000 { compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; reg = <0x00 0x04504000 0x00 0x1000>; + interrupts = , + ; + interrupt-names = "error_irq", "irq"; clocks = <&k3_clks 38 3>, <&k3_clks 38 1>, <&k3_clks 38 3>, <&k3_clks 38 3>, <&k3_clks 38 4>, <&k3_clks 38 4>; clock-names = "sys_clk", "p_clk", "pixel_if0_clk", @@ -1301,6 +1304,9 @@ ti_csi2rx1: ticsi2rx@4510000 { cdns_csi2rx1: csi-bridge@4514000 { compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; reg = <0x00 0x04514000 0x00 0x1000>; + interrupts = , + ; + interrupt-names = "error_irq", "irq"; clocks = <&k3_clks 39 3>, <&k3_clks 39 1>, <&k3_clks 39 3>, <&k3_clks 39 3>, <&k3_clks 39 4>, <&k3_clks 39 4>; clock-names = "sys_clk", "p_clk", "pixel_if0_clk", From 33b34bfa4f22216845f5fd738d320e78d75cf1ff Mon Sep 17 00:00:00 2001 From: Yemike Abhilash Chandra Date: Fri, 8 Aug 2025 15:27:59 +0530 Subject: [PATCH 00689/11391] arm64: dts: ti: k3-j721e-main: Add CSI2 interrupts property Add interrupts property for CSI2RX. Interrupt IDs are taken from the J721E TRM [0]. Interrupt Line | Source Interrupt ------------------|------------------------- GIC500_SPI_IN_185 | CSI_RX_IF0_CSI_ERR_IRQ_0 GIC500_SPI_IN_184 | CSI_RX_IF0_CSI_IRQ_0 GIC500_SPI_IN_189 | CSI_RX_IF1_CSI_ERR_IRQ_0 GIC500_SPI_IN_188 | CSI_RX_IF1_CSI_IRQ_0 [0]: http://www.ti.com/lit/pdf/spruil1 Signed-off-by: Yemike Abhilash Chandra Reviewed-by: Udit Kumar Reviewed-by: Jared McArthur Link: https://lore.kernel.org/r/20250808095804.544298-3-y-abhilashchandra@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-j721e-main.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi b/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi index 5bd0d36bf33e..ab3666ff4297 100644 --- a/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi @@ -608,6 +608,9 @@ ti_csi2rx0: ticsi2rx@4500000 { cdns_csi2rx0: csi-bridge@4504000 { compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; reg = <0x0 0x4504000 0x0 0x1000>; + interrupts = , + ; + interrupt-names = "error_irq", "irq"; clocks = <&k3_clks 26 2>, <&k3_clks 26 0>, <&k3_clks 26 2>, <&k3_clks 26 2>, <&k3_clks 26 3>, <&k3_clks 26 3>; clock-names = "sys_clk", "p_clk", "pixel_if0_clk", @@ -661,6 +664,9 @@ ti_csi2rx1: ticsi2rx@4510000 { cdns_csi2rx1: csi-bridge@4514000 { compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; reg = <0x0 0x4514000 0x0 0x1000>; + interrupts = , + ; + interrupt-names = "error_irq", "irq"; clocks = <&k3_clks 27 2>, <&k3_clks 27 0>, <&k3_clks 27 2>, <&k3_clks 27 2>, <&k3_clks 27 3>, <&k3_clks 27 3>; clock-names = "sys_clk", "p_clk", "pixel_if0_clk", From 84ba1f67c6169e4533aa109888accbbccef25705 Mon Sep 17 00:00:00 2001 From: Yemike Abhilash Chandra Date: Fri, 8 Aug 2025 15:28:00 +0530 Subject: [PATCH 00690/11391] arm64: dts: ti: k3-j784s4-j742s2-main-common: Add CSI2 interrupts property Add interrupts property for CSI2RX. Interrupt IDs are taken from the J784S4 TRM [0]. Interrupt Line | Source Interrupt --------------------|------------------------- GIC500SS_SPI_IN_185 | CSI_RX_IF0_CSI_ERR_IRQ_0 GIC500SS_SPI_IN_184 | CSI_RX_IF0_CSI_IRQ_0 GIC500SS_SPI_IN_189 | CSI_RX_IF1_CSI_ERR_IRQ_0 GIC500SS_SPI_IN_188 | CSI_RX_IF1_CSI_IRQ_0 GIC500SS_SPI_IN_193 | CSI_RX_IF2_CSI_ERR_IRQ_0 GIC500SS_SPI_IN_192 | CSI_RX_IF2_CSI_IRQ_0 [0]: https://www.ti.com/lit/zip/spruj52 Signed-off-by: Yemike Abhilash Chandra Reviewed-by: Udit Kumar Reviewed-by: Jared McArthur Link: https://lore.kernel.org/r/20250808095804.544298-4-y-abhilashchandra@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi index 79d97d46b4c6..fbbe768e7a30 100644 --- a/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi @@ -819,6 +819,9 @@ ti_csi2rx0: ticsi2rx@4500000 { cdns_csi2rx0: csi-bridge@4504000 { compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; reg = <0x00 0x04504000 0x00 0x00001000>; + interrupts = , + ; + interrupt-names = "error_irq", "irq"; clocks = <&k3_clks 72 2>, <&k3_clks 72 0>, <&k3_clks 72 2>, <&k3_clks 72 2>, <&k3_clks 72 3>, <&k3_clks 72 3>; clock-names = "sys_clk", "p_clk", "pixel_if0_clk", @@ -872,6 +875,9 @@ ti_csi2rx1: ticsi2rx@4510000 { cdns_csi2rx1: csi-bridge@4514000 { compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; reg = <0x00 0x04514000 0x00 0x00001000>; + interrupts = , + ; + interrupt-names = "error_irq", "irq"; clocks = <&k3_clks 73 2>, <&k3_clks 73 0>, <&k3_clks 73 2>, <&k3_clks 73 2>, <&k3_clks 73 3>, <&k3_clks 73 3>; clock-names = "sys_clk", "p_clk", "pixel_if0_clk", @@ -924,6 +930,9 @@ ti_csi2rx2: ticsi2rx@4520000 { cdns_csi2rx2: csi-bridge@4524000 { compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; reg = <0x00 0x04524000 0x00 0x00001000>; + interrupts = , + ; + interrupt-names = "error_irq", "irq"; clocks = <&k3_clks 74 2>, <&k3_clks 74 0>, <&k3_clks 74 2>, <&k3_clks 74 2>, <&k3_clks 74 3>, <&k3_clks 74 3>; clock-names = "sys_clk", "p_clk", "pixel_if0_clk", From 265dca4380753af9aa9480c7c201c820d6e7905e Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Mon, 11 Aug 2025 09:09:05 +0200 Subject: [PATCH 00691/11391] 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 @@ u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe) /**** 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 00692/11391] 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 @@ u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe) #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 347866a21ff447e868305426c294395b2cee68a7 Mon Sep 17 00:00:00 2001 From: Yemike Abhilash Chandra Date: Fri, 8 Aug 2025 15:28:01 +0530 Subject: [PATCH 00693/11391] arm64: dts: ti: k3-am62p-j722s-common-main: Add CSI2 interrupts property Add interrupts property for CDNS CSI2RX. Interrupt IDs are taken from the J722S TRM [0]. Interrupt Line | Source Interrupt -------------------|------------------------- GICSS0_SPI_IN_175 | CSI_RX_IF0_CSI_ERR_IRQ_0 GICSS0_SPI_IN_173 | CSI_RX_IF0_CSI_IRQ_0 [0]: https://www.ti.com/lit/zip/sprujb3 Signed-off-by: Yemike Abhilash Chandra Reviewed-by: Udit Kumar Reviewed-by: Jared McArthur Link: https://lore.kernel.org/r/20250808095804.544298-5-y-abhilashchandra@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am62p-j722s-common-main.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/ti/k3-am62p-j722s-common-main.dtsi b/arch/arm64/boot/dts/ti/k3-am62p-j722s-common-main.dtsi index 2e5e25a8ca86..4427b12058a6 100644 --- a/arch/arm64/boot/dts/ti/k3-am62p-j722s-common-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62p-j722s-common-main.dtsi @@ -1045,6 +1045,9 @@ ti_csi2rx0: ticsi2rx@30102000 { cdns_csi2rx0: csi-bridge@30101000 { compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; reg = <0x00 0x30101000 0x00 0x1000>; + interrupts = , + ; + interrupt-names = "error_irq", "irq"; clocks = <&k3_clks 182 0>, <&k3_clks 182 3>, <&k3_clks 182 0>, <&k3_clks 182 0>, <&k3_clks 182 4>, <&k3_clks 182 4>; clock-names = "sys_clk", "p_clk", "pixel_if0_clk", From 772cc597174486b85585ed02a74cc332ba25de01 Mon Sep 17 00:00:00 2001 From: Yemike Abhilash Chandra Date: Fri, 8 Aug 2025 15:28:02 +0530 Subject: [PATCH 00694/11391] arm64: dts: ti: k3-j722s-main: Add CSI2 interrupts property Add interrupts property for CDNS CSI2RX. Interrupt IDs are taken from the J722S TRM [0]. Interrupt Line | Source Interrupt -------------------|------------------------- GICSS0_SPI_IN_178 | CSI_RX_IF1_CSI_ERR_IRQ_0 GICSS0_SPI_IN_179 | CSI_RX_IF1_CSI_IRQ_0 GICSS0_SPI_IN_219 | CSI_RX_IF2_CSI_ERR_IRQ_0 GICSS0_SPI_IN_232 | CSI_RX_IF2_CSI_IRQ_0 GICSS0_SPI_IN_249 | CSI_RX_IF3_CSI_ERR_IRQ_0 GICSS0_SPI_IN_250 | CSI_RX_IF3_CSI_IRQ_0 [0]: https://www.ti.com/lit/zip/sprujb3 Signed-off-by: Yemike Abhilash Chandra Reviewed-by: Udit Kumar Reviewed-by: Jared McArthur Link: https://lore.kernel.org/r/20250808095804.544298-6-y-abhilashchandra@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-j722s-main.dtsi | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm64/boot/dts/ti/k3-j722s-main.dtsi b/arch/arm64/boot/dts/ti/k3-j722s-main.dtsi index 5cfa7bf36641..6a8e5ff3b1d5 100644 --- a/arch/arm64/boot/dts/ti/k3-j722s-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j722s-main.dtsi @@ -168,6 +168,9 @@ ti_csi2rx1: ticsi2rx@30122000 { cdns_csi2rx1: csi-bridge@30121000 { compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; reg = <0x00 0x30121000 0x00 0x1000>; + interrupts = , + ; + interrupt-names = "error_irq", "irq"; clocks = <&k3_clks 247 0>, <&k3_clks 247 3>, <&k3_clks 247 0>, <&k3_clks 247 0>, <&k3_clks 247 4>, <&k3_clks 247 4>; clock-names = "sys_clk", "p_clk", "pixel_if0_clk", @@ -221,6 +224,9 @@ ti_csi2rx2: ticsi2rx@30142000 { cdns_csi2rx2: csi-bridge@30141000 { compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; reg = <0x00 0x30141000 0x00 0x1000>; + interrupts = , + ; + interrupt-names = "error_irq", "irq"; clocks = <&k3_clks 248 0>, <&k3_clks 248 3>, <&k3_clks 248 0>, <&k3_clks 248 0>, <&k3_clks 248 4>, <&k3_clks 248 4>; clock-names = "sys_clk", "p_clk", "pixel_if0_clk", @@ -274,6 +280,9 @@ ti_csi2rx3: ticsi2rx@30162000 { cdns_csi2rx3: csi-bridge@30161000 { compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; reg = <0x00 0x30161000 0x00 0x1000>; + interrupts = , + ; + interrupt-names = "error_irq", "irq"; clocks = <&k3_clks 249 0>, <&k3_clks 249 3>, <&k3_clks 249 0>, <&k3_clks 249 0>, <&k3_clks 249 4>, <&k3_clks 249 4>; clock-names = "sys_clk", "p_clk", "pixel_if0_clk", From 96ba5ce55ec192ca28446d4045dfd501270769b3 Mon Sep 17 00:00:00 2001 From: Yemike Abhilash Chandra Date: Fri, 8 Aug 2025 15:28:03 +0530 Subject: [PATCH 00695/11391] arm64: dts: ti: k3-am62-main: Add CSI2 interrupts property Add interrupts property for CDNS CSI2RX. Interrupt IDs are taken from the AM62 TRM [0]. Interrupt Line | Source Interrupt ---------------|-------------------------- gicss0.spi.175 | csi_rx_if.0.csi_err_irq.0 gicss0.spi.173 | csi_rx_if.0.csi_irq.0 [0]: https://www.ti.com/lit/pdf/spruiv7 Signed-off-by: Yemike Abhilash Chandra Reviewed-by: Udit Kumar Reviewed-by: Jared McArthur Link: https://lore.kernel.org/r/20250808095804.544298-7-y-abhilashchandra@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am62-main.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/ti/k3-am62-main.dtsi b/arch/arm64/boot/dts/ti/k3-am62-main.dtsi index 120ba8f9dd0e..029380dc1a35 100644 --- a/arch/arm64/boot/dts/ti/k3-am62-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62-main.dtsi @@ -1031,6 +1031,9 @@ ti_csi2rx0: ticsi2rx@30102000 { cdns_csi2rx0: csi-bridge@30101000 { compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; reg = <0x00 0x30101000 0x00 0x1000>; + interrupts = , + ; + interrupt-names = "error_irq", "irq"; clocks = <&k3_clks 182 0>, <&k3_clks 182 3>, <&k3_clks 182 0>, <&k3_clks 182 0>, <&k3_clks 182 4>, <&k3_clks 182 4>; clock-names = "sys_clk", "p_clk", "pixel_if0_clk", From e5b264e0a201254a38836b794ff362e8400f3df7 Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Mon, 11 Aug 2025 11:54:17 +0300 Subject: [PATCH 00696/11391] 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 9307cad31efcfe3446847ee34effaaa5c4930fa8 Mon Sep 17 00:00:00 2001 From: Yemike Abhilash Chandra Date: Fri, 8 Aug 2025 15:28:04 +0530 Subject: [PATCH 00697/11391] arm64: dts: ti: k3-am62a-main: Add CSI2 interrupts property Add interrupts property for CDNS CSI2RX. Interrupt IDs are taken from the AM62A TRM [0]. Interrupt Line | Source Interrupt ---------------------------|---------------------------------- GICSS0_COMMON_0_SPI_IN_175 | CSI_RX_IF0_COMMON_0_CSI_ERR_IRQ_0 GICSS0_COMMON_0_SPI_IN_173 | CSI_RX_IF0_COMMON_0_CSI_IRQ_0 [0]: https://www.ti.com/lit/pdf/spruj16 Signed-off-by: Yemike Abhilash Chandra Reviewed-by: Udit Kumar Reviewed-by: Jared McArthur Link: https://lore.kernel.org/r/20250808095804.544298-8-y-abhilashchandra@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-am62a-main.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/ti/k3-am62a-main.dtsi b/arch/arm64/boot/dts/ti/k3-am62a-main.dtsi index 44e7e459f176..9cad79d7bbc1 100644 --- a/arch/arm64/boot/dts/ti/k3-am62a-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62a-main.dtsi @@ -1054,6 +1054,9 @@ ti_csi2rx0: ticsi2rx@30102000 { cdns_csi2rx0: csi-bridge@30101000 { compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; reg = <0x00 0x30101000 0x00 0x1000>; + interrupts = , + ; + interrupt-names = "error_irq", "irq"; clocks = <&k3_clks 182 0>, <&k3_clks 182 3>, <&k3_clks 182 0>, <&k3_clks 182 0>, <&k3_clks 182 4>, <&k3_clks 182 4>; clock-names = "sys_clk", "p_clk", "pixel_if0_clk", From 260221b2a053a30e30575fa90c326590e8fb0c76 Mon Sep 17 00:00:00 2001 From: Yuri Martins Date: Tue, 12 Aug 2025 01:56:06 +0000 Subject: [PATCH 00698/11391] 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 47a32605c6e7f283f373b56e9caf97c56b7e5634 Mon Sep 17 00:00:00 2001 From: Brandon Brnich Date: Fri, 8 Aug 2025 10:55:55 -0500 Subject: [PATCH 00699/11391] arm64: dts: ti: k3-j722s-main: Add E5010 JPEG Encoder This adds node for E5010 JPEG Encoder which is a stateful JPEG Encoder present in J722s SoC, supporting baseline encoding of semiplanar based YUV420 and YUV422 raw video formats to JPEG encoding, with resolutions supported from 64x64 to 8kx8k. Signed-off-by: Brandon Brnich Reviewed-by: Devarsh Thakkar Link: https://lore.kernel.org/r/20250808155555.2632451-1-b-brnich@ti.com Signed-off-by: Nishanth Menon --- arch/arm64/boot/dts/ti/k3-j722s-main.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm64/boot/dts/ti/k3-j722s-main.dtsi b/arch/arm64/boot/dts/ti/k3-j722s-main.dtsi index 6a8e5ff3b1d5..993828872dfb 100644 --- a/arch/arm64/boot/dts/ti/k3-j722s-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j722s-main.dtsi @@ -394,6 +394,16 @@ c7x_1: dsp@7e200000 { ti,sci-proc-ids = <0x31 0xff>; status = "disabled"; }; + + e5010: jpeg-encoder@fd20000 { + compatible = "ti,am62a-jpeg-enc", "img,e5010-jpeg-enc"; + reg = <0x00 0xfd20000 0x00 0x100>, + <0x00 0xfd20200 0x00 0x200>; + reg-names = "core", "mmu"; + clocks = <&k3_clks 201 0>; + power-domains = <&k3_pds 201 TI_SCI_PD_EXCLUSIVE>; + interrupts = ; + }; }; &main_bcdma_csi { From a5039648f86424885aae37f03dc39bc9cb972ecb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Mon, 11 Aug 2025 09:48:30 +0200 Subject: [PATCH 00700/11391] soc: ti: pruss: don't use %pK through printk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the past %pK was preferable to %p as it would not leak raw pointer values into the kernel log. Since commit ad67b74d2469 ("printk: hash addresses printed with %p") the regular %p has been improved to avoid this issue. Furthermore, restricted pointers ("%pK") were never meant to be used through printk(). They can still unintentionally leak raw pointers or acquire sleeping locks in atomic contexts. Switch to the regular pointer formatting which is safer and easier to reason about. Signed-off-by: Thomas Weißschuh Link: https://lore.kernel.org/r/20250811-restricted-pointers-soc-v2-1-7af7ed993546@linutronix.de Signed-off-by: Nishanth Menon --- drivers/soc/ti/pruss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c index d7634bf5413a..038576805bfa 100644 --- a/drivers/soc/ti/pruss.c +++ b/drivers/soc/ti/pruss.c @@ -449,7 +449,7 @@ static int pruss_of_setup_memories(struct device *dev, struct pruss *pruss) pruss->mem_regions[i].pa = res.start; pruss->mem_regions[i].size = resource_size(&res); - dev_dbg(dev, "memory %8s: pa %pa size 0x%zx va %pK\n", + dev_dbg(dev, "memory %8s: pa %pa size 0x%zx va %p\n", mem_names[i], &pruss->mem_regions[i].pa, pruss->mem_regions[i].size, pruss->mem_regions[i].va); } From 20b3c9a403ee23e57a7e6bf5370ca438c3cd2e99 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Wed, 6 Aug 2025 16:28:23 -0500 Subject: [PATCH 00701/11391] dt-bindings: arm: Convert ti,keystone to DT schema Signed-off-by: Rob Herring (Arm) Reviewed-by: Andrew Davis Link: https://lore.kernel.org/r/20250806212824.1635084-1-robh@kernel.org Signed-off-by: Nishanth Menon --- .../bindings/arm/keystone/keystone.txt | 42 ------------------- .../bindings/arm/ti/ti,keystone.yaml | 42 +++++++++++++++++++ 2 files changed, 42 insertions(+), 42 deletions(-) delete mode 100644 Documentation/devicetree/bindings/arm/keystone/keystone.txt create mode 100644 Documentation/devicetree/bindings/arm/ti/ti,keystone.yaml diff --git a/Documentation/devicetree/bindings/arm/keystone/keystone.txt b/Documentation/devicetree/bindings/arm/keystone/keystone.txt deleted file mode 100644 index f310bad04483..000000000000 --- a/Documentation/devicetree/bindings/arm/keystone/keystone.txt +++ /dev/null @@ -1,42 +0,0 @@ -TI Keystone Platforms Device Tree Bindings ------------------------------------------------ - -Boards with Keystone2 based devices (TCI66xxK2H) SOC shall have the -following properties. - -Required properties: - - compatible: All TI specific devices present in Keystone SOC should be in - the form "ti,keystone-*". Generic devices like gic, arch_timers, ns16550 - type UART should use the specified compatible for those devices. - -SoC families: - -- Keystone 2 generic SoC: - compatible = "ti,keystone" - -SoCs: - -- Keystone 2 Hawking/Kepler - compatible = "ti,k2hk", "ti,keystone" -- Keystone 2 Lamarr - compatible = "ti,k2l", "ti,keystone" -- Keystone 2 Edison - compatible = "ti,k2e", "ti,keystone" -- K2G - compatible = "ti,k2g", "ti,keystone" - -Boards: -- Keystone 2 Hawking/Kepler EVM - compatible = "ti,k2hk-evm", "ti,k2hk", "ti,keystone" - -- Keystone 2 Lamarr EVM - compatible = "ti,k2l-evm", "ti, k2l", "ti,keystone" - -- Keystone 2 Edison EVM - compatible = "ti,k2e-evm", "ti,k2e", "ti,keystone" - -- K2G EVM - compatible = "ti,k2g-evm", "ti,k2g", "ti-keystone" - -- K2G Industrial Communication Engine EVM - compatible = "ti,k2g-ice", "ti,k2g", "ti-keystone" diff --git a/Documentation/devicetree/bindings/arm/ti/ti,keystone.yaml b/Documentation/devicetree/bindings/arm/ti/ti,keystone.yaml new file mode 100644 index 000000000000..20d4084f4506 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/ti/ti,keystone.yaml @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/ti/ti,keystone.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI Keystone Platforms + +maintainers: + - Nishanth Menon + - Santosh Shilimkar + +properties: + compatible: + oneOf: + - description: K2G + items: + - enum: + - ti,k2g-evm + - ti,k2g-ice + - const: ti,k2g + - const: ti,keystone + - description: Keystone 2 Edison + items: + - enum: + - ti,k2e-evm + - const: ti,k2e + - const: ti,keystone + - description: Keystone 2 Lamarr + items: + - enum: + - ti,k2l-evm + - const: ti,k2l + - const: ti,keystone + - description: Keystone 2 Hawking/Kepler + items: + - enum: + - ti,k2hk-evm + - const: ti,k2hk + - const: ti,keystone + +additionalProperties: true From 784ad808ae864490b93db0f650b8b6417eb7ce68 Mon Sep 17 00:00:00 2001 From: Prashanth K Date: Fri, 25 Jul 2025 11:51:58 +0530 Subject: [PATCH 00702/11391] 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 00703/11391] 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 00704/11391] 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 00705/11391] 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 00706/11391] 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 00707/11391] 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 00708/11391] 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 @@ max3421_probe(struct spi_device *spi) 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 00709/11391] 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 00710/11391] 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 aff8436ed97b99cd27f192d9a71ac2b1aa7b9d03 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 11 Aug 2025 12:13:55 +0200 Subject: [PATCH 00711/11391] ALSA: usb-audio: Use auto-cleanup for shutdown locks Introduce an auto-cleanup macro for the temporary shutdown locks for USB-audio, and replace the manual lock/unlock pairs with it. Namely, the former err = snd_usb_lock_shutdown(chip); if (err < 0) return err; .... snd_usb_unlock_shutdown(chip); is replaced with CLASS(snd_usb_lock, pm)(chip); if (pm.err < 0) return pm.err; .... with the automatic unlocking. Link: https://patch.msgid.link/20250811101647.8637-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/mixer.c | 59 +++-- sound/usb/mixer_quirks.c | 348 ++++++++++++------------------ sound/usb/pcm.c | 31 ++- sound/usb/qcom/qc_audio_offload.c | 15 +- sound/usb/usbaudio.h | 23 ++ 5 files changed, 209 insertions(+), 267 deletions(-) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 63b300bc67ba..5fcf1117777d 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -313,8 +313,8 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int timeout = 10; int idx = 0, err; - err = snd_usb_lock_shutdown(chip); - if (err < 0) + CLASS(snd_usb_lock, pm)(chip); + if (pm.err < 0) return -EIO; while (timeout-- > 0) { @@ -324,20 +324,15 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, validx, idx, buf, val_len); if (err >= val_len) { *value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len)); - err = 0; - goto out; + return 0; } else if (err == -ETIMEDOUT) { - goto out; + return err; } } usb_audio_dbg(chip, "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", request, validx, idx, cval->val_type); - err = -EINVAL; - - out: - snd_usb_unlock_shutdown(chip); - return err; + return -EINVAL; } static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, @@ -362,14 +357,16 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, memset(buf, 0, sizeof(buf)); - if (snd_usb_lock_shutdown(chip)) - return -EIO; + { + CLASS(snd_usb_lock, pm)(chip); + if (pm.err) + return -EIO; - idx = mixer_ctrl_intf(cval->head.mixer) | (cval->head.id << 8); - ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest, - USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - validx, idx, buf, size); - snd_usb_unlock_shutdown(chip); + idx = mixer_ctrl_intf(cval->head.mixer) | (cval->head.id << 8); + ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, + validx, idx, buf, size); + } if (ret < 0) { usb_audio_dbg(chip, @@ -484,8 +481,8 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, buf[2] = (value_set >> 16) & 0xff; buf[3] = (value_set >> 24) & 0xff; - err = snd_usb_lock_shutdown(chip); - if (err < 0) + CLASS(snd_usb_lock, pm)(chip); + if (pm.err < 0) return -EIO; while (timeout-- > 0) { @@ -494,20 +491,14 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, usb_sndctrlpipe(chip->dev, 0), request, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, validx, idx, buf, val_len); - if (err >= 0) { - err = 0; - goto out; - } else if (err == -ETIMEDOUT) { - goto out; - } + if (err >= 0) + return 0; + else if (err == -ETIMEDOUT) + return err; } usb_audio_dbg(chip, "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n", request, validx, idx, cval->val_type, buf[0], buf[1]); - err = -EINVAL; - - out: - snd_usb_unlock_shutdown(chip); - return err; + return -EINVAL; } static int set_cur_ctl_value(struct usb_mixer_elem_info *cval, @@ -1494,9 +1485,11 @@ static int get_connector_value(struct usb_mixer_elem_info *cval, validx = cval->control << 8 | 0; - ret = snd_usb_lock_shutdown(chip) ? -EIO : 0; - if (ret) + CLASS(snd_usb_lock, pm)(chip); + if (pm.err) { + ret = -EIO; goto error; + } idx = mixer_ctrl_intf(cval->head.mixer) | (cval->head.id << 8); if (cval->head.mixer->protocol == UAC_VERSION_2) { @@ -1517,8 +1510,6 @@ static int get_connector_value(struct usb_mixer_elem_info *cval, *val = !!uac3_conn.bmConInserted; } - snd_usb_unlock_shutdown(chip); - if (ret < 0) { if (name && strstr(name, "Speaker")) { if (val) diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 7cc27ae5512f..afeea297e10f 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -307,9 +307,9 @@ static int snd_audigy2nx_led_update(struct usb_mixer_interface *mixer, struct snd_usb_audio *chip = mixer->chip; int err; - err = snd_usb_lock_shutdown(chip); - if (err < 0) - return err; + CLASS(snd_usb_lock, pm)(chip); + if (pm.err < 0) + return pm.err; if (chip->usb_id == USB_ID(0x041e, 0x3042)) err = snd_usb_ctl_msg(chip->dev, @@ -327,7 +327,6 @@ static int snd_audigy2nx_led_update(struct usb_mixer_interface *mixer, usb_sndctrlpipe(chip->dev, 0), 0x24, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, value, index + 2, NULL, 0); - snd_usb_unlock_shutdown(chip); return err; } @@ -438,15 +437,14 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry, for (i = 0; jacks[i].name; ++i) { snd_iprintf(buffer, "%s: ", jacks[i].name); - err = snd_usb_lock_shutdown(mixer->chip); - if (err < 0) + CLASS(snd_usb_lock, pm)(mixer->chip); + if (pm.err < 0) return; err = snd_usb_ctl_msg(mixer->chip->dev, usb_rcvctrlpipe(mixer->chip->dev, 0), UAC_GET_MEM, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, jacks[i].unitid << 8, buf, 3); - snd_usb_unlock_shutdown(mixer->chip); if (err == 3 && (buf[0] == 3 || buf[0] == 6)) snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]); else @@ -474,21 +472,18 @@ static int snd_emu0204_ch_switch_update(struct usb_mixer_interface *mixer, int value) { struct snd_usb_audio *chip = mixer->chip; - int err; unsigned char buf[2]; - err = snd_usb_lock_shutdown(chip); - if (err < 0) - return err; + CLASS(snd_usb_lock, pm)(chip); + if (pm.err < 0) + return pm.err; buf[0] = 0x01; buf[1] = value ? 0x02 : 0x01; - err = snd_usb_ctl_msg(chip->dev, - usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR, - USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, - 0x0400, 0x0e00, buf, 2); - snd_usb_unlock_shutdown(chip); - return err; + return snd_usb_ctl_msg(chip->dev, + usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, + 0x0400, 0x0e00, buf, 2); } static int snd_emu0204_ch_switch_put(struct snd_kcontrol *kcontrol, @@ -804,17 +799,14 @@ static int snd_xonar_u1_switch_update(struct usb_mixer_interface *mixer, unsigned char status) { struct snd_usb_audio *chip = mixer->chip; - int err; - err = snd_usb_lock_shutdown(chip); - if (err < 0) - return err; - err = snd_usb_ctl_msg(chip->dev, - usb_sndctrlpipe(chip->dev, 0), 0x08, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, - 50, 0, &status, 1); - snd_usb_unlock_shutdown(chip); - return err; + CLASS(snd_usb_lock, pm)(chip); + if (pm.err < 0) + return pm.err; + return snd_usb_ctl_msg(chip->dev, + usb_sndctrlpipe(chip->dev, 0), 0x08, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, + 50, 0, &status, 1); } static int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol, @@ -945,20 +937,17 @@ static int snd_mbox1_clk_switch_get(struct snd_kcontrol *kctl, struct snd_usb_audio *chip = list->mixer->chip; int err; - err = snd_usb_lock_shutdown(chip); - if (err < 0) - goto err; + CLASS(snd_usb_lock, pm)(chip); + if (pm.err < 0) + return pm.err; err = snd_mbox1_is_spdif_synced(chip); if (err < 0) - goto err; + return err; kctl->private_value = err; - err = 0; ucontrol->value.enumerated.item[0] = kctl->private_value; -err: - snd_usb_unlock_shutdown(chip); - return err; + return 0; } static int snd_mbox1_clk_switch_update(struct usb_mixer_interface *mixer, int is_spdif_sync) @@ -966,27 +955,24 @@ static int snd_mbox1_clk_switch_update(struct usb_mixer_interface *mixer, int is struct snd_usb_audio *chip = mixer->chip; int err; - err = snd_usb_lock_shutdown(chip); - if (err < 0) - return err; + CLASS(snd_usb_lock, pm)(chip); + if (pm.err < 0) + return pm.err; err = snd_mbox1_is_spdif_input(chip); if (err < 0) - goto err; + return err; err = snd_mbox1_is_spdif_synced(chip); if (err < 0) - goto err; + return err; /* FIXME: hardcoded sample rate */ err = snd_mbox1_set_clk_source(chip, is_spdif_sync ? 0 : 48000); if (err < 0) - goto err; + return err; - err = snd_mbox1_is_spdif_synced(chip); -err: - snd_usb_unlock_shutdown(chip); - return err; + return snd_mbox1_is_spdif_synced(chip); } static int snd_mbox1_clk_switch_put(struct snd_kcontrol *kctl, @@ -1037,26 +1023,23 @@ static int snd_mbox1_src_switch_update(struct usb_mixer_interface *mixer, int is struct snd_usb_audio *chip = mixer->chip; int err; - err = snd_usb_lock_shutdown(chip); + CLASS(snd_usb_lock, pm)(chip); + if (pm.err < 0) + return pm.err; + + err = snd_mbox1_is_spdif_input(chip); + if (err < 0) + return err; + + err = snd_mbox1_set_input_source(chip, is_spdif_input); if (err < 0) return err; err = snd_mbox1_is_spdif_input(chip); if (err < 0) - goto err; + return err; - err = snd_mbox1_set_input_source(chip, is_spdif_input); - if (err < 0) - goto err; - - err = snd_mbox1_is_spdif_input(chip); - if (err < 0) - goto err; - - err = snd_mbox1_is_spdif_synced(chip); -err: - snd_usb_unlock_shutdown(chip); - return err; + return snd_mbox1_is_spdif_synced(chip); } static int snd_mbox1_src_switch_put(struct snd_kcontrol *kctl, @@ -1167,17 +1150,14 @@ static int snd_ni_update_cur_val(struct usb_mixer_elem_list *list) { struct snd_usb_audio *chip = list->mixer->chip; unsigned int pval = list->kctl->private_value; - int err; - err = snd_usb_lock_shutdown(chip); - if (err < 0) - return err; - err = usb_control_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), - (pval >> 16) & 0xff, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, - pval >> 24, pval & 0xffff, NULL, 0, 1000); - snd_usb_unlock_shutdown(chip); - return err; + CLASS(snd_usb_lock, pm)(chip); + if (pm.err < 0) + return pm.err; + return usb_control_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), + (pval >> 16) & 0xff, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + pval >> 24, pval & 0xffff, NULL, 0, 1000); } static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol, @@ -1329,23 +1309,20 @@ static int snd_ftu_eff_switch_update(struct usb_mixer_elem_list *list) struct snd_usb_audio *chip = list->mixer->chip; unsigned int pval = list->kctl->private_value; unsigned char value[2]; - int err; value[0] = pval >> 24; value[1] = 0; - err = snd_usb_lock_shutdown(chip); - if (err < 0) - return err; - err = snd_usb_ctl_msg(chip->dev, - usb_sndctrlpipe(chip->dev, 0), - UAC_SET_CUR, - USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, - pval & 0xff00, - snd_usb_ctrl_intf(list->mixer->hostif) | ((pval & 0xff) << 8), - value, 2); - snd_usb_unlock_shutdown(chip); - return err; + CLASS(snd_usb_lock, pm)(chip); + if (pm.err < 0) + return pm.err; + return snd_usb_ctl_msg(chip->dev, + usb_sndctrlpipe(chip->dev, 0), + UAC_SET_CUR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, + pval & 0xff00, + snd_usb_ctrl_intf(list->mixer->hostif) | ((pval & 0xff) << 8), + value, 2); } static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl, @@ -1908,9 +1885,9 @@ static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol, unsigned char data[3]; int rate; - err = snd_usb_lock_shutdown(chip); - if (err < 0) - return err; + CLASS(snd_usb_lock, pm)(chip); + if (pm.err < 0) + return pm.err; ucontrol->value.iec958.status[0] = kcontrol->private_value & 0xff; ucontrol->value.iec958.status[1] = (kcontrol->private_value >> 8) & 0xff; @@ -1918,15 +1895,11 @@ static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol, /* use known values for that card: interface#1 altsetting#1 */ iface = usb_ifnum_to_if(chip->dev, 1); - if (!iface || iface->num_altsetting < 2) { - err = -EINVAL; - goto end; - } + if (!iface || iface->num_altsetting < 2) + return -EINVAL; alts = &iface->altsetting[1]; - if (get_iface_desc(alts)->bNumEndpoints < 1) { - err = -EINVAL; - goto end; - } + if (get_iface_desc(alts)->bNumEndpoints < 1) + return -EINVAL; ep = get_endpoint(alts, 0)->bEndpointAddress; err = snd_usb_ctl_msg(chip->dev, @@ -1938,16 +1911,13 @@ static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol, data, sizeof(data)); if (err < 0) - goto end; + return err; rate = data[0] | (data[1] << 8) | (data[2] << 16); ucontrol->value.iec958.status[3] = (rate == 48000) ? IEC958_AES3_CON_FS_48000 : IEC958_AES3_CON_FS_44100; - err = 0; - end: - snd_usb_unlock_shutdown(chip); - return err; + return 0; } static int snd_microii_spdif_default_update(struct usb_mixer_elem_list *list) @@ -1957,9 +1927,9 @@ static int snd_microii_spdif_default_update(struct usb_mixer_elem_list *list) u8 reg; int err; - err = snd_usb_lock_shutdown(chip); - if (err < 0) - return err; + CLASS(snd_usb_lock, pm)(chip); + if (pm.err < 0) + return pm.err; reg = ((pval >> 4) & 0xf0) | (pval & 0x0f); err = snd_usb_ctl_msg(chip->dev, @@ -1971,7 +1941,7 @@ static int snd_microii_spdif_default_update(struct usb_mixer_elem_list *list) NULL, 0); if (err < 0) - goto end; + return err; reg = (pval & IEC958_AES0_NONAUDIO) ? 0xa0 : 0x20; reg |= (pval >> 12) & 0x0f; @@ -1983,11 +1953,6 @@ static int snd_microii_spdif_default_update(struct usb_mixer_elem_list *list) 3, NULL, 0); - if (err < 0) - goto end; - - end: - snd_usb_unlock_shutdown(chip); return err; } @@ -2042,23 +2007,19 @@ static int snd_microii_spdif_switch_update(struct usb_mixer_elem_list *list) { struct snd_usb_audio *chip = list->mixer->chip; u8 reg = list->kctl->private_value; - int err; - err = snd_usb_lock_shutdown(chip); - if (err < 0) - return err; + CLASS(snd_usb_lock, pm)(chip); + if (pm.err < 0) + return pm.err; - err = snd_usb_ctl_msg(chip->dev, - usb_sndctrlpipe(chip->dev, 0), - UAC_SET_CUR, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, - reg, - 9, - NULL, - 0); - - snd_usb_unlock_shutdown(chip); - return err; + return snd_usb_ctl_msg(chip->dev, + usb_sndctrlpipe(chip->dev, 0), + UAC_SET_CUR, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, + reg, + 9, + NULL, + 0); } static int snd_microii_spdif_switch_put(struct snd_kcontrol *kcontrol, @@ -2137,21 +2098,18 @@ static int snd_soundblaster_e1_switch_update(struct usb_mixer_interface *mixer, unsigned char state) { struct snd_usb_audio *chip = mixer->chip; - int err; unsigned char buff[2]; buff[0] = 0x02; buff[1] = state ? 0x02 : 0x00; - err = snd_usb_lock_shutdown(chip); - if (err < 0) - return err; - err = snd_usb_ctl_msg(chip->dev, - usb_sndctrlpipe(chip->dev, 0), HID_REQ_SET_REPORT, - USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, - 0x0202, 3, buff, 2); - snd_usb_unlock_shutdown(chip); - return err; + CLASS(snd_usb_lock, pm)(chip); + if (pm.err < 0) + return pm.err; + return snd_usb_ctl_msg(chip->dev, + usb_sndctrlpipe(chip->dev, 0), HID_REQ_SET_REPORT, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, + 0x0202, 3, buff, 2); } static int snd_soundblaster_e1_switch_put(struct snd_kcontrol *kcontrol, @@ -2273,32 +2231,28 @@ static int realtek_ctl_connector_get(struct snd_kcontrol *kcontrol, bool presence; int err; - err = snd_usb_lock_shutdown(chip); - if (err < 0) - return err; + CLASS(snd_usb_lock, pm)(chip); + if (pm.err < 0) + return pm.err; err = realtek_hda_get(chip, HDA_VERB_CMD(AC_VERB_GET_PIN_SENSE, node_id, 0), &sense); if (err < 0) - goto err; + return err; if (pv & REALTEK_MIC_FLAG) { err = realtek_hda_set(chip, HDA_VERB_CMD(AC_VERB_SET_COEF_INDEX, REALTEK_VENDOR_REGISTERS, REALTEK_CBJ_CTRL2)); if (err < 0) - goto err; + return err; err = realtek_hda_get(chip, HDA_VERB_CMD(AC_VERB_GET_PROC_COEF, REALTEK_VENDOR_REGISTERS, 0), &cbj_ctrl2); if (err < 0) - goto err; + return err; } -err: - snd_usb_unlock_shutdown(chip); - if (err < 0) - return err; presence = sense & AC_PINSENSE_PRESENCE; if (pv & REALTEK_MIC_FLAG) @@ -2485,14 +2439,11 @@ static int snd_rme_get_status1(struct snd_kcontrol *kcontrol, { struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); struct snd_usb_audio *chip = list->mixer->chip; - int err; - err = snd_usb_lock_shutdown(chip); - if (err < 0) - return err; - err = snd_rme_read_value(chip, SND_RME_GET_STATUS1, status1); - snd_usb_unlock_shutdown(chip); - return err; + CLASS(snd_usb_lock, pm)(chip); + if (pm.err < 0) + return pm.err; + return snd_rme_read_value(chip, SND_RME_GET_STATUS1, status1); } static int snd_rme_rate_get(struct snd_kcontrol *kcontrol, @@ -2609,22 +2560,19 @@ static int snd_rme_current_freq_get(struct snd_kcontrol *kcontrol, unsigned int freq; int err; - err = snd_usb_lock_shutdown(chip); - if (err < 0) - return err; + CLASS(snd_usb_lock, pm)(chip); + if (pm.err < 0) + return pm.err; err = snd_rme_read_value(chip, SND_RME_GET_STATUS1, &status1); if (err < 0) - goto end; + return err; err = snd_rme_read_value(chip, SND_RME_GET_CURRENT_FREQ, &den); if (err < 0) - goto end; + return err; freq = (den == 0) ? 0 : div64_u64(num, den); freq <<= SND_RME_CLK_FREQMUL(status1); ucontrol->value.integer.value[0] = freq; - -end: - snd_usb_unlock_shutdown(chip); - return err; + return 0; } static int snd_rme_rate_info(struct snd_kcontrol *kcontrol, @@ -2831,13 +2779,12 @@ enum { static int snd_bbfpro_ctl_update(struct usb_mixer_interface *mixer, u8 reg, u8 index, u8 value) { - int err; u16 usb_req, usb_idx, usb_val; struct snd_usb_audio *chip = mixer->chip; - err = snd_usb_lock_shutdown(chip); - if (err < 0) - return err; + CLASS(snd_usb_lock, pm)(chip); + if (pm.err < 0) + return pm.err; if (reg == SND_BBFPRO_CTL_REG1) { usb_req = SND_BBFPRO_USBREQ_CTL_REG1; @@ -2854,13 +2801,10 @@ static int snd_bbfpro_ctl_update(struct usb_mixer_interface *mixer, u8 reg, usb_val = value ? usb_idx : 0; } - err = snd_usb_ctl_msg(chip->dev, - usb_sndctrlpipe(chip->dev, 0), usb_req, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - usb_val, usb_idx, NULL, 0); - - snd_usb_unlock_shutdown(chip); - return err; + return snd_usb_ctl_msg(chip->dev, + usb_sndctrlpipe(chip->dev, 0), usb_req, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + usb_val, usb_idx, NULL, 0); } static int snd_bbfpro_ctl_get(struct snd_kcontrol *kcontrol, @@ -2975,7 +2919,6 @@ static int snd_bbfpro_ctl_resume(struct usb_mixer_elem_list *list) static int snd_bbfpro_gain_update(struct usb_mixer_interface *mixer, u8 channel, u8 gain) { - int err; struct snd_usb_audio *chip = mixer->chip; if (channel < 2) { @@ -2986,18 +2929,15 @@ static int snd_bbfpro_gain_update(struct usb_mixer_interface *mixer, gain = ((gain % 6) << 5) | (60 / 3); } - err = snd_usb_lock_shutdown(chip); - if (err < 0) - return err; + CLASS(snd_usb_lock, pm)(chip); + if (pm.err < 0) + return pm.err; - err = snd_usb_ctl_msg(chip->dev, - usb_sndctrlpipe(chip->dev, 0), - SND_BBFPRO_USBREQ_GAIN, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - gain, channel, NULL, 0); - - snd_usb_unlock_shutdown(chip); - return err; + return snd_usb_ctl_msg(chip->dev, + usb_sndctrlpipe(chip->dev, 0), + SND_BBFPRO_USBREQ_GAIN, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + gain, channel, NULL, 0); } static int snd_bbfpro_gain_get(struct snd_kcontrol *kcontrol, @@ -3084,14 +3024,13 @@ static int snd_bbfpro_vol_update(struct usb_mixer_interface *mixer, u16 index, u32 value) { struct snd_usb_audio *chip = mixer->chip; - int err; u16 idx; u16 usb_idx, usb_val; u32 v; - err = snd_usb_lock_shutdown(chip); - if (err < 0) - return err; + CLASS(snd_usb_lock, pm)(chip); + if (pm.err < 0) + return pm.err; idx = index & SND_BBFPRO_MIXER_IDX_MASK; // 18 bit linear volume, split so 2 bits end up in index. @@ -3099,15 +3038,12 @@ static int snd_bbfpro_vol_update(struct usb_mixer_interface *mixer, u16 index, usb_idx = idx | (v & 0x3) << 14; usb_val = (v >> 2) & 0xffff; - err = snd_usb_ctl_msg(chip->dev, - usb_sndctrlpipe(chip->dev, 0), - SND_BBFPRO_USBREQ_MIXER, - USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, - usb_val, usb_idx, NULL, 0); - - snd_usb_unlock_shutdown(chip); - return err; + return snd_usb_ctl_msg(chip->dev, + usb_sndctrlpipe(chip->dev, 0), + SND_BBFPRO_USBREQ_MIXER, + USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_DEVICE, + usb_val, usb_idx, NULL, 0); } static int snd_bbfpro_vol_get(struct snd_kcontrol *kcontrol, @@ -4212,26 +4148,22 @@ static int snd_djm_controls_info(struct snd_kcontrol *kctl, static int snd_djm_controls_update(struct usb_mixer_interface *mixer, u8 device_idx, u8 group, u16 value) { - int err; const struct snd_djm_device *device = &snd_djm_devices[device_idx]; if (group >= device->ncontrols || value >= device->controls[group].noptions) return -EINVAL; - err = snd_usb_lock_shutdown(mixer->chip); - if (err) - return err; + CLASS(snd_usb_lock, pm)(mixer->chip); + if (pm.err) + return pm.err; - err = snd_usb_ctl_msg(mixer->chip->dev, - usb_sndctrlpipe(mixer->chip->dev, 0), - USB_REQ_SET_FEATURE, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - device->controls[group].options[value], - device->controls[group].wIndex, - NULL, 0); - - snd_usb_unlock_shutdown(mixer->chip); - return err; + return snd_usb_ctl_msg(mixer->chip->dev, + usb_sndctrlpipe(mixer->chip->dev, 0), + USB_REQ_SET_FEATURE, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + device->controls[group].options[value], + device->controls[group].wIndex, + NULL, 0); } static int snd_djm_controls_get(struct snd_kcontrol *kctl, diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index c52fd0989c93..97e7c3b62c8e 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -614,11 +614,11 @@ int snd_usb_hw_free(struct snd_usb_substream *subs) scoped_guard(mutex, &chip->mutex) { subs->cur_audiofmt = NULL; } - if (!snd_usb_lock_shutdown(chip)) { + CLASS(snd_usb_lock, pm)(chip); + if (!pm.err) { if (stop_endpoints(subs, false)) sync_pending_stops(subs); close_endpoints(chip, subs); - snd_usb_unlock_shutdown(chip); } return 0; @@ -675,28 +675,26 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) int retry = 0; int ret; - ret = snd_usb_lock_shutdown(chip); - if (ret < 0) - return ret; - if (snd_BUG_ON(!subs->data_endpoint)) { - ret = -EIO; - goto unlock; - } + CLASS(snd_usb_lock, pm)(chip); + if (pm.err < 0) + return pm.err; + if (snd_BUG_ON(!subs->data_endpoint)) + return -EIO; ret = snd_usb_pcm_change_state(subs, UAC3_PD_STATE_D0); if (ret < 0) - goto unlock; + return ret; again: if (subs->sync_endpoint) { ret = snd_usb_endpoint_prepare(chip, subs->sync_endpoint); if (ret < 0) - goto unlock; + return ret; } ret = snd_usb_endpoint_prepare(chip, subs->data_endpoint); if (ret < 0) - goto unlock; + return ret; else if (ret > 0) snd_usb_set_format_quirk(subs, subs->cur_audiofmt); ret = 0; @@ -722,8 +720,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) goto again; } } - unlock: - snd_usb_unlock_shutdown(chip); + return ret; } @@ -1296,9 +1293,11 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream) snd_media_stop_pipeline(subs); - if (!snd_usb_lock_shutdown(subs->stream->chip)) { + { + CLASS(snd_usb_lock, pm)(subs->stream->chip); + if (pm.err) + return pm.err; ret = snd_usb_pcm_change_state(subs, UAC3_PD_STATE_D1); - snd_usb_unlock_shutdown(subs->stream->chip); if (ret < 0) return ret; } diff --git a/sound/usb/qcom/qc_audio_offload.c b/sound/usb/qcom/qc_audio_offload.c index a25c5a531690..965ddc792acc 100644 --- a/sound/usb/qcom/qc_audio_offload.c +++ b/sound/usb/qcom/qc_audio_offload.c @@ -961,21 +961,21 @@ static int enable_audio_stream(struct snd_usb_substream *subs, goto put_suspend; if (!atomic_read(&chip->shutdown)) { - ret = snd_usb_lock_shutdown(chip); - if (ret < 0) + CLASS(snd_usb_lock, pm)(chip); + if (pm.err < 0) { + ret = pm.err; goto detach_ep; + } if (subs->sync_endpoint) { ret = snd_usb_endpoint_prepare(chip, subs->sync_endpoint); if (ret < 0) - goto unlock; + goto detach_ep; } ret = snd_usb_endpoint_prepare(chip, subs->data_endpoint); if (ret < 0) - goto unlock; - - snd_usb_unlock_shutdown(chip); + goto detach_ep; dev_dbg(uaudio_qdev->data->dev, "selected %s iface:%d altsetting:%d datainterval:%dus\n", @@ -989,9 +989,6 @@ static int enable_audio_stream(struct snd_usb_substream *subs, return 0; -unlock: - snd_usb_unlock_shutdown(chip); - detach_ep: snd_usb_hw_free(subs); diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 158ec053dc44..7521098ba391 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -139,6 +139,29 @@ struct snd_usb_audio_quirk { int snd_usb_lock_shutdown(struct snd_usb_audio *chip); void snd_usb_unlock_shutdown(struct snd_usb_audio *chip); +/* auto-cleanup */ +struct __snd_usb_lock { + struct snd_usb_audio *chip; + int err; +}; + +static inline struct __snd_usb_lock __snd_usb_lock_shutdown(struct snd_usb_audio *chip) +{ + struct __snd_usb_lock T = { .chip = chip }; + T.err = snd_usb_lock_shutdown(chip); + return T; +} + +static inline void __snd_usb_unlock_shutdown(struct __snd_usb_lock *lock) +{ + if (!lock->err) + snd_usb_unlock_shutdown(lock->chip); +} + +DEFINE_CLASS(snd_usb_lock, struct __snd_usb_lock, + __snd_usb_unlock_shutdown(&(_T)), __snd_usb_lock_shutdown(chip), + struct snd_usb_audio *chip) + extern bool snd_usb_use_vmalloc; extern bool snd_usb_skip_validation; From 96c08ff80b8fce45e49fee5eba4b40b1654eb5aa Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 6 Aug 2025 14:46:12 +0300 Subject: [PATCH 00712/11391] 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 113e9a284d4372322da90c05f1dc36e0a52e5fca Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Wed, 13 Aug 2025 12:34:16 +0200 Subject: [PATCH 00713/11391] ALSA: hda: Improve local variable data type in snd_hda_get_num_devices() Use 'int' instead of 'unsigned int' because the local variable 'parm' can be negative. While an unsigned integer is harmless in practice due to the implicit type conversion, it's safer and more idiomatic to use a signed integer to properly check for -1. Signed-off-by: Thorsten Blum Link: https://patch.msgid.link/20250813103418.164110-2-thorsten.blum@linux.dev Signed-off-by: Takashi Iwai --- sound/hda/common/codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/hda/common/codec.c b/sound/hda/common/codec.c index eb268d442201..cab479111603 100644 --- a/sound/hda/common/codec.c +++ b/sound/hda/common/codec.c @@ -300,7 +300,7 @@ EXPORT_SYMBOL_GPL(snd_hda_get_conn_index); unsigned int snd_hda_get_num_devices(struct hda_codec *codec, hda_nid_t nid) { unsigned int wcaps = get_wcaps(codec, nid); - unsigned int parm; + int parm; if (!codec->dp_mst || !(wcaps & AC_WCAP_DIGITAL) || get_wcaps_type(wcaps) != AC_WID_PIN) From 70d00858645c0fb72ac63cf61c784b600aa9ea50 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 13 Aug 2025 08:38:08 +0300 Subject: [PATCH 00714/11391] audit: add a missing tab Someone got a bit carried away deleting tabs. Add it back. Signed-off-by: Dan Carpenter Signed-off-by: Paul Moore --- kernel/auditsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 1c29541c8fb6..497bda0043fb 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -1778,7 +1778,7 @@ static void audit_log_exit(void) axs->target_sessionid[i], &axs->target_ref[i], axs->target_comm[i])) - call_panic = 1; + call_panic = 1; } if (context->target_pid && From 7bb184222e9fa8b839247c3a1cb1bcf628e519a5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:18 +0200 Subject: [PATCH 00715/11391] scripts: sphinx-pre-install: fix version check for Fedora The script is now picking the wrong version. Fix it. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/9d1e5c9906534e2bae586f891770066346463146.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/sphinx-pre-install b/scripts/sphinx-pre-install index 3f8d6925e896..07234d482fa8 100755 --- a/scripts/sphinx-pre-install +++ b/scripts/sphinx-pre-install @@ -413,7 +413,7 @@ sub give_redhat_hints() my $old = 0; my $rel; my $noto_sans_redhat = "google-noto-sans-cjk-ttc-fonts"; - $rel = $1 if ($system_release =~ /(release|Linux)\s+(\d+)/); + $rel = $2 if ($system_release =~ /(release|Linux)\s+(\d+)/); if (!($system_release =~ /Fedora/)) { $map{"virtualenv"} = "python-virtualenv"; From a9c50a51e0129057dbaf58fbaf7ba1a8a69e9b21 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:19 +0200 Subject: [PATCH 00716/11391] scripts: sphinx-pre-install: rename it to scripts/sphinx-pre-install.pl That helps us to later replace the scripts. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/08d9a32a5aaf3784fef016594efe505d7c5a2697.1754992972.git.mchehab+huawei@kernel.org --- Documentation/Makefile | 14 +++++++------- .../{sphinx-pre-install => sphinx-pre-install.pl} | 0 2 files changed, 7 insertions(+), 7 deletions(-) rename scripts/{sphinx-pre-install => sphinx-pre-install.pl} (100%) diff --git a/Documentation/Makefile b/Documentation/Makefile index b98477df5ddf..c486fe3cc5e1 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -46,7 +46,7 @@ ifeq ($(HAVE_SPHINX),0) .DEFAULT: $(warning The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed and in PATH, or set the SPHINXBUILD make variable to point to the full path of the '$(SPHINXBUILD)' executable.) @echo - @$(srctree)/scripts/sphinx-pre-install + @$(srctree)/scripts/sphinx-pre-install.pl @echo " SKIP Sphinx $@ target." else # HAVE_SPHINX @@ -121,7 +121,7 @@ $(YNL_RST_DIR)/%.rst: $(YNL_YAML_DIR)/%.yaml $(YNL_TOOL) htmldocs texinfodocs latexdocs epubdocs xmldocs: $(YNL_INDEX) htmldocs: - @$(srctree)/scripts/sphinx-pre-install --version-check + @$(srctree)/scripts/sphinx-pre-install.pl --version-check @+$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,html,$(var),,$(var))) # If Rust support is available and .config exists, add rustdoc generated contents. @@ -135,7 +135,7 @@ endif endif texinfodocs: - @$(srctree)/scripts/sphinx-pre-install --version-check + @$(srctree)/scripts/sphinx-pre-install.pl --version-check @+$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,texinfo,$(var),texinfo,$(var))) # Note: the 'info' Make target is generated by sphinx itself when @@ -147,7 +147,7 @@ linkcheckdocs: @$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,linkcheck,$(var),,$(var))) latexdocs: - @$(srctree)/scripts/sphinx-pre-install --version-check + @$(srctree)/scripts/sphinx-pre-install.pl --version-check @+$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,latex,$(var),latex,$(var))) ifeq ($(HAVE_PDFLATEX),0) @@ -160,7 +160,7 @@ else # HAVE_PDFLATEX pdfdocs: DENY_VF = XDG_CONFIG_HOME=$(FONTS_CONF_DENY_VF) pdfdocs: latexdocs - @$(srctree)/scripts/sphinx-pre-install --version-check + @$(srctree)/scripts/sphinx-pre-install.pl --version-check $(foreach var,$(SPHINXDIRS), \ $(MAKE) PDFLATEX="$(PDFLATEX)" LATEXOPTS="$(LATEXOPTS)" $(DENY_VF) -C $(BUILDDIR)/$(var)/latex || sh $(srctree)/scripts/check-variable-fonts.sh || exit; \ mkdir -p $(BUILDDIR)/$(var)/pdf; \ @@ -170,11 +170,11 @@ pdfdocs: latexdocs endif # HAVE_PDFLATEX epubdocs: - @$(srctree)/scripts/sphinx-pre-install --version-check + @$(srctree)/scripts/sphinx-pre-install.pl --version-check @+$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,epub,$(var),epub,$(var))) xmldocs: - @$(srctree)/scripts/sphinx-pre-install --version-check + @$(srctree)/scripts/sphinx-pre-install.pl --version-check @+$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,xml,$(var),xml,$(var))) endif # HAVE_SPHINX diff --git a/scripts/sphinx-pre-install b/scripts/sphinx-pre-install.pl similarity index 100% rename from scripts/sphinx-pre-install rename to scripts/sphinx-pre-install.pl From ca9087f50772aa5794dd655ff5a0719dd4b83b1f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:20 +0200 Subject: [PATCH 00717/11391] scripts: sphinx-pre-install: Convert script to Python Port scripts/sphinx-pre-install to Python. That allows a better maintainance of the file. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/8d236079545aff796900bde4cdaaf79411d04074.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 1102 +++++++++++++++++++++++++++++++++ 1 file changed, 1102 insertions(+) create mode 100755 scripts/sphinx-pre-install.py diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py new file mode 100755 index 000000000000..dcee2181b72f --- /dev/null +++ b/scripts/sphinx-pre-install.py @@ -0,0 +1,1102 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2017-2025 Mauro Carvalho Chehab +# +# pylint: disable=C0103,C0114,C0115,C0116,C0301 +# pylint: disable=R0902,R0904,R0912,R0915,R1705,R1710,E1121 + + +import argparse +import os +import re +import subprocess +import sys +from glob import glob + + +def parse_version(version): + """Convert a major.minor.patch version into a tuple""" +# + return tuple(int(x) for x in version.split(".")) + + +def ver_str(version): + """Returns a version tuple as major.minor.patch""" + + return ".".join([str(x) for x in version]) + + +RECOMMENDED_VERSION = parse_version("3.4.3") + + +class SphinxDependencyChecker: + # List of required texlive packages on Fedora and OpenSuse + texlive = { + "amsfonts.sty": "texlive-amsfonts", + "amsmath.sty": "texlive-amsmath", + "amssymb.sty": "texlive-amsfonts", + "amsthm.sty": "texlive-amscls", + "anyfontsize.sty": "texlive-anyfontsize", + "atbegshi.sty": "texlive-oberdiek", + "bm.sty": "texlive-tools", + "capt-of.sty": "texlive-capt-of", + "cmap.sty": "texlive-cmap", + "ctexhook.sty": "texlive-ctex", + "ecrm1000.tfm": "texlive-ec", + "eqparbox.sty": "texlive-eqparbox", + "eu1enc.def": "texlive-euenc", + "fancybox.sty": "texlive-fancybox", + "fancyvrb.sty": "texlive-fancyvrb", + "float.sty": "texlive-float", + "fncychap.sty": "texlive-fncychap", + "footnote.sty": "texlive-mdwtools", + "framed.sty": "texlive-framed", + "luatex85.sty": "texlive-luatex85", + "multirow.sty": "texlive-multirow", + "needspace.sty": "texlive-needspace", + "palatino.sty": "texlive-psnfss", + "parskip.sty": "texlive-parskip", + "polyglossia.sty": "texlive-polyglossia", + "tabulary.sty": "texlive-tabulary", + "threeparttable.sty": "texlive-threeparttable", + "titlesec.sty": "texlive-titlesec", + "ucs.sty": "texlive-ucs", + "upquote.sty": "texlive-upquote", + "wrapfig.sty": "texlive-wrapfig", + } + + def __init__(self, args): + self.pdf = args.pdf + self.virtualenv = args.virtualenv + self.version_check = args.version_check + + self.missing = {} + + self.need = 0 + self.optional = 0 + self.need_symlink = 0 + self.need_sphinx = 0 + self.need_pip = 0 + self.need_virtualenv = 0 + self.rec_sphinx_upgrade = 0 + self.verbose_warn_install = 1 + + self.system_release = "" + self.install = "" + self.virtenv_dir = "" + self.python_cmd = "" + self.activate_cmd = "" + + self.min_version = (0, 0, 0) + self.cur_version = (0, 0, 0) + self.latest_avail_ver = (0, 0, 0) + self.venv_ver = (0, 0, 0) + + prefix = os.environ.get("srctree", ".") + "/" + + self.conf = prefix + "Documentation/conf.py" + self.requirement_file = prefix + "Documentation/sphinx/requirements.txt" + self.virtenv_prefix = ["sphinx_", "Sphinx_" ] + + # + # Ancillary methods that don't depend on self + # + + @staticmethod + def which(prog): + for path in os.environ.get("PATH", "").split(":"): + full_path = os.path.join(path, prog) + if os.access(full_path, os.X_OK): + return full_path + + return None + + @staticmethod + def find_python_no_venv(): + # FIXME: does it makes sense now that this script is in Python? + + result = subprocess.run(["pwd"], capture_output=True, text=True) + cur_dir = result.stdout.strip() + + python_names = ["python3", "python"] + + for d in os.environ.get("PATH", "").split(":"): + if f"{cur_dir}/sphinx" in d: + continue + + for p in python_names: + if os.access(os.path.join(d, p), os.X_OK): + return os.path.join(d, p) + + # Python not found at the PATH + return python_names[-1] + + @staticmethod + def run(*args, **kwargs): + """Excecute a command, hiding its output by default""" + + if not kwargs.get('capture_output', False): + if 'stdout' not in kwargs: + kwargs['stdout'] = subprocess.DEVNULL + if 'stderr' not in kwargs: + kwargs['stderr'] = subprocess.DEVNULL + + return subprocess.run(*args, **kwargs) + + # + # Methods to check if a feature exists + # + + # Note: is_optional has 3 states: + # - 0: mandatory + # - 1: optional, but nice to have + # - 2: LaTeX optional - pdf builds without it, but may have visual impact + + def check_missing(self, progs): + for prog, is_optional in sorted(self.missing.items()): + # At least on some LTS distros like CentOS 7, texlive doesn't + # provide all packages we need. When such distros are + # detected, we have to disable PDF output. + # + # So, we need to ignore the packages that distros would + # need for LaTeX to work + if is_optional == 2 and not self.pdf: + self.optional -= 1 + continue + + if self.verbose_warn_install: + if is_optional: + print(f'Warning: better to also install "{prog}".') + else: + print(f'ERROR: please install "{prog}", otherwise, build won\'t work.') + + self.install += " " + progs.get(prog, prog) + + self.install = self.install.lstrip() + + def add_package(self, package, is_optional): + self.missing[package] = is_optional + if is_optional: + self.optional += 1 + else: + self.need += 1 + + def check_missing_file(self, files, package, is_optional): + for f in files: + if os.path.exists(f): + return + self.add_package(package, is_optional) + + def check_program(self, prog, is_optional): + found = self.which(prog) + if found: + return found + + self.add_package(prog, is_optional) + + return None + + def check_perl_module(self, prog, is_optional): + # While testing with lxc download template, one of the + # distros (Oracle) didn't have perl - nor even an option to install + # before installing oraclelinux-release-el9 package. + # + # Check it before running an error. If perl is not there, + # add it as a mandatory package, as some parts of the doc builder + # needs it. + if not self.which("perl"): + self.add_package("perl", 0) + self.add_package(prog, is_optional) + return + + try: + self.run(["perl", f"-M{prog}", "-e", "1"], check=True) + except subprocess.CalledProcessError: + self.add_package(prog, is_optional) + + def check_python_module(self, module, is_optional): + # FIXME: is it needed at the Python version? Maybe due to venv? + if not self.python_cmd: + return + + try: + self.run([self.python_cmd, "-c", f"import {module}"], check=True) + except subprocess.CalledProcessError: + self.add_package(module, is_optional) + + def check_rpm_missing(self, pkgs, is_optional): + for prog in pkgs: + try: + self.run(["rpm", "-q", prog], check=True) + except subprocess.CalledProcessError: + self.add_package(prog, is_optional) + + def check_pacman_missing(self, pkgs, is_optional): + for prog in pkgs: + try: + self.run(["pacman", "-Q", prog], check=True) + except subprocess.CalledProcessError: + self.add_package(prog, is_optional) + + def check_missing_tex(self, is_optional): + kpsewhich = self.which("kpsewhich") + for prog, package in self.texlive.items(): + + # If kpsewhich is not there, just add it to deps + if not kpsewhich: + self.add_package(package, is_optional) + continue + + # Check if the package is needed + try: + result = self.run( + [kpsewhich, prog], stdout=subprocess.PIPE, text=True, check=True + ) + + # Didn't find. Add it + if not result.stdout.strip(): + self.add_package(package, is_optional) + + except subprocess.CalledProcessError: + # kpsewhich returned an error. Add it, just in case + self.add_package(package, is_optional) + + def get_sphinx_fname(self): + if "SPHINXBUILD" in os.environ: + return os.environ["SPHINXBUILD"] + + fname = "sphinx-build" + if self.which(fname): + return fname + + fname = "sphinx-build-3" + if self.which(fname): + self.need_symlink = 1 + return fname + + return "" + + def get_sphinx_version(self, cmd): + try: + result = self.run([cmd, "--version"], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, check=True) + except (subprocess.CalledProcessError, FileNotFoundError): + return None + + for line in result.stdout.split("\n"): + match = re.match(r"^sphinx-build\s+([\d\.]+)(?:\+(?:/[\da-f]+)|b\d+)?\s*$", line) + if match: + return parse_version(match.group(1)) + + match = re.match(r"^Sphinx.*\s+([\d\.]+)\s*$", line) + if match: + return parse_version(match.group(1)) + + def check_sphinx(self): + try: + with open(self.conf, "r", encoding="utf-8") as f: + for line in f: + match = re.match(r"^\s*needs_sphinx\s*=\s*[\'\"]([\d\.]+)[\'\"]", line) + if match: + self.min_version = parse_version(match.group(1)) + break + except IOError: + sys.exit(f"Can't open {self.conf}") + + if not self.min_version: + sys.exit(f"Can't get needs_sphinx version from {self.conf}") + + self.virtenv_dir = self.virtenv_prefix[0] + "latest" + + sphinx = self.get_sphinx_fname() + if not sphinx: + self.need_sphinx = 1 + return + + self.cur_version = self.get_sphinx_version(sphinx) + if not self.cur_version: + sys.exit(f"{sphinx} didn't return its version") + + if self.cur_version < self.min_version: + curver = ver_str(self.cur_version) + minver = ver_str(self.min_version) + + print(f"ERROR: Sphinx version is {curver}. It should be >= {minver}") + self.need_sphinx = 1 + return + + # On version check mode, just assume Sphinx has all mandatory deps + if self.version_check and self.cur_version >= RECOMMENDED_VERSION: + sys.exit(0) + + def catcheck(self, filename): + if os.path.exists(filename): + with open(filename, "r", encoding="utf-8") as f: + return f.read().strip() + return "" + + # + # Distro-specific hints methods + # + + def give_debian_hints(self): + progs = { + "Pod::Usage": "perl-modules", + "convert": "imagemagick", + "dot": "graphviz", + "ensurepip": "python3-venv", + "python-sphinx": "python3-sphinx", + "rsvg-convert": "librsvg2-bin", + "virtualenv": "virtualenv", + "xelatex": "texlive-xetex", + "yaml": "python3-yaml", + } + + if self.pdf: + pdf_pkgs = { + "texlive-lang-chinese": [ + "/usr/share/texlive/texmf-dist/tex/latex/ctex/ctexhook.sty", + ], + "fonts-dejavu": [ + "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", + ], + "fonts-noto-cjk": [ + "/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc", + "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc", + "/usr/share/fonts/opentype/noto/NotoSerifCJK-Regular.ttc", + ], + } + + for package, files in pdf_pkgs.items(): + self.check_missing_file(files, package, 2) + + self.check_program("dvipng", 2) + + self.check_missing(progs) + + if not self.need and not self.optional: + return + + if self.verbose_warn_install: + print("You should run:") + print(f"\n\tsudo apt-get install {self.install}") + + def give_redhat_hints(self): + progs = { + "Pod::Usage": "perl-Pod-Usage", + "convert": "ImageMagick", + "dot": "graphviz", + "python-sphinx": "python3-sphinx", + "rsvg-convert": "librsvg2-tools", + "virtualenv": "python3-virtualenv", + "xelatex": "texlive-xetex-bin", + "yaml": "python3-pyyaml", + } + + fedora26_opt_pkgs = [ + "graphviz-gd", # Fedora 26: needed for PDF support + ] + + fedora_tex_pkgs = [ + "dejavu-sans-fonts", + "dejavu-sans-mono-fonts", + "dejavu-serif-fonts", + "texlive-collection-fontsrecommended", + "texlive-collection-latex", + "texlive-xecjk", + ] + + old = 0 + rel = None + pkg_manager = "dnf" + + match = re.search(r"(release|Linux)\s+(\d+)", self.system_release) + if match: + rel = int(match.group(2)) + + if not rel: + print("Couldn't identify release number") + old = 1 + self.pdf = False + elif re.search("Fedora", self.system_release): + # Fedora 38 and upper use this CJK font + + noto_sans_redhat = "google-noto-sans-cjk-fonts" + else: + # Almalinux, CentOS, RHEL, ... + + # at least up to version 9 (and Fedora < 38), that's the CJK font + noto_sans_redhat = "google-noto-sans-cjk-ttc-fonts" + + progs["virtualenv"] = "python-virtualenv" + + if rel and rel < 8: + old = 1 + self.pdf = False + + # RHEL 7 is in ELS, currently up to Jun, 2026 + + print("Note: texlive packages on RHEL/CENTOS <= 7 are incomplete. Can't support PDF output") + print("If you want to build PDF, please read:") + print("\thttps://www.systutorials.com/241660/how-to-install-tex-live-on-centos-7-linux/") + + if self.pdf: + pdf_pkgs = [ + "/usr/share/fonts/google-noto-cjk/NotoSansCJK-Regular.ttc", + "/usr/share/fonts/google-noto-sans-cjk-fonts/NotoSansCJK-Regular.ttc", + ] + + self.check_missing_file(pdf_pkgs, noto_sans_redhat, 2) + + if not old: + self.check_rpm_missing(fedora26_opt_pkgs, 2) + self.check_rpm_missing(fedora_tex_pkgs, 2) + + self.check_missing_tex(2) + + self.check_missing(progs) + + if not self.need and not self.optional: + return + + if self.verbose_warn_install: + print("You should run:") + + if old: + # dnf is there since Fedora 18+ and RHEL 8 + pkg_manager = "yum" + + print(f"\n\tsudo {pkg_manager} install -y {self.install}") + + def give_opensuse_hints(self): + progs = { + "Pod::Usage": "perl-Pod-Usage", + "convert": "ImageMagick", + "dot": "graphviz", + "python-sphinx": "python3-sphinx", + "virtualenv": "python3-virtualenv", + "xelatex": "texlive-xetex-bin", + "yaml": "python3-pyyaml", + } + + # On Tumbleweed, this package is also named rsvg-convert + if not re.search(r"Tumbleweed", self.system_release): + progs["rsvg-convert"] = "rsvg-view" + + suse_tex_pkgs = [ + "texlive-babel-english", + "texlive-caption", + "texlive-colortbl", + "texlive-courier", + "texlive-dvips", + "texlive-helvetic", + "texlive-makeindex", + "texlive-metafont", + "texlive-metapost", + "texlive-palatino", + "texlive-preview", + "texlive-times", + "texlive-zapfchan", + "texlive-zapfding", + ] + + progs["latexmk"] = "texlive-latexmk-bin" + + # FIXME: add support for installing CJK fonts + # + # I tried hard, but was unable to find a way to install + # "Noto Sans CJK SC" on openSUSE + + if self.pdf: + self.check_rpm_missing(suse_tex_pkgs, 2) + if self.pdf: + self.check_missing_tex(2) + self.check_missing(progs) + + if not self.need and not self.optional: + return + + if self.verbose_warn_install: + print("You should run:") + print(f"\n\tsudo zypper install --no-recommends {self.install}") + + def give_mageia_hints(self): + progs = { + "Pod::Usage": "perl-Pod-Usage", + "convert": "ImageMagick", + "dot": "graphviz", + "python-sphinx": "python3-sphinx", + "rsvg-convert": "librsvg2", + "virtualenv": "python3-virtualenv", + "xelatex": "texlive", + "yaml": "python3-yaml", + } + + tex_pkgs = [ + "texlive-fontsextra", + ] + + if re.search(r"OpenMandriva", self.system_release): + packager_cmd = "dnf install" + noto_sans = "noto-sans-cjk-fonts" + tex_pkgs = ["texlive-collection-fontsextra"] + else: + packager_cmd = "urpmi" + noto_sans = "google-noto-sans-cjk-ttc-fonts" + + progs["latexmk"] = "texlive-collection-basic" + + if self.pdf: + pdf_pkgs = [ + "/usr/share/fonts/google-noto-cjk/NotoSansCJK-Regular.ttc", + "/usr/share/fonts/TTF/NotoSans-Regular.ttf", + ] + + self.check_missing_file(pdf_pkgs, noto_sans, 2) + self.check_rpm_missing(tex_pkgs, 2) + + self.check_missing(progs) + + if not self.need and not self.optional: + return + if self.verbose_warn_install: + print("You should run:") + print(f"\n\tsudo {packager_cmd} {self.install}") + + def give_arch_linux_hints(self): + progs = { + "convert": "imagemagick", + "dot": "graphviz", + "latexmk": "texlive-core", + "rsvg-convert": "extra/librsvg", + "virtualenv": "python-virtualenv", + "xelatex": "texlive-xetex", + "yaml": "python-yaml", + } + + archlinux_tex_pkgs = [ + "texlive-core", + "texlive-latexextra", + "ttf-dejavu", + ] + + if self.pdf: + self.check_pacman_missing(archlinux_tex_pkgs, 2) + + self.check_missing_file( + ["/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc"], + "noto-fonts-cjk", + 2, + ) + + self.check_missing(progs) + + if not self.need and not self.optional: + return + if self.verbose_warn_install: + print("You should run:") + print(f"\n\tsudo pacman -S {self.install}") + + def give_gentoo_hints(self): + progs = { + "convert": "media-gfx/imagemagick", + "dot": "media-gfx/graphviz", + "rsvg-convert": "gnome-base/librsvg", + "virtualenv": "dev-python/virtualenv", + "xelatex": "dev-texlive/texlive-xetex media-fonts/dejavu", + "yaml": "dev-python/pyyaml", + } + + if self.pdf: + pdf_pkgs = { + "media-fonts/dejavu": [ + "/usr/share/fonts/dejavu/DejaVuSans.ttf", + ], + "media-fonts/noto-cjk": [ + "/usr/share/fonts/noto-cjk/NotoSansCJKsc-Regular.otf", + "/usr/share/fonts/noto-cjk/NotoSerifCJK-Regular.ttc", + ], + } + for package, files in pdf_pkgs.items(): + self.check_missing_file(files, package, 2) + + self.check_missing(progs) + + if not self.need and not self.optional: + return + + if self.verbose_warn_install: + print("You should run:") + print("\n") + + imagemagick = "media-gfx/imagemagick svg png" + cairo = "media-gfx/graphviz cairo pdf" + portage_imagemagick = "/etc/portage/package.use/imagemagick" + portage_cairo = "/etc/portage/package.use/graphviz" + + result = self.run(["grep", "imagemagick", portage_imagemagick], + stdout=subprocess.PIPE, text=True) + if not result.stdout.strip(): + print(f"\tsudo su -c 'echo \"{imagemagick}\" > {portage_imagemagick}'") + + result = self.run(["grep", "graphviz", portage_cairo], + stdout=subprocess.PIPE, text=True) + + if not result.stdout.strip(): + print(f"\tsudo su -c 'echo \"{cairo}\" > {portage_cairo}'") + + print(f"\tsudo emerge --ask {self.install}") + + # + # Dispatch the check to an os_specific hinter + # + + def check_distros(self): + # OS-specific hints logic + os_hints = { + re.compile("Red Hat Enterprise Linux"): self.give_redhat_hints, + re.compile("Fedora"): self.give_redhat_hints, + re.compile("AlmaLinux"): self.give_redhat_hints, + re.compile("Amazon Linux"): self.give_redhat_hints, + re.compile("CentOS"): self.give_redhat_hints, + re.compile("openEuler"): self.give_redhat_hints, + re.compile("Oracle Linux Server"): self.give_redhat_hints, + re.compile("Rocky Linux"): self.give_redhat_hints, + re.compile("Scientific Linux"): self.give_redhat_hints, + re.compile("Springdale Open Enterprise"): self.give_redhat_hints, + + re.compile("Ubuntu"): self.give_debian_hints, + re.compile("Debian"): self.give_debian_hints, + re.compile("Devuan"): self.give_debian_hints, + re.compile("Kali"): self.give_debian_hints, + re.compile("Mint"): self.give_debian_hints, + + re.compile("openSUSE"): self.give_opensuse_hints, + + re.compile("Mageia"): self.give_mageia_hints, + re.compile("OpenMandriva"): self.give_mageia_hints, + + re.compile("Arch Linux"): self.give_arch_linux_hints, + re.compile("Gentoo"): self.give_gentoo_hints, + } + + # If the OS is detected, use per-OS hint logic + for regex, os_hint in os_hints.items(): + if regex.search(self.system_release): + os_hint() + + return + + # + # Fall-back to generic hint code for other distros + # That's far from ideal, specially for LaTeX dependencies. + # + progs = {"sphinx-build": "sphinx"} + if self.pdf: + self.check_missing_tex(2) + + self.check_missing(progs) + + print(f"I don't know distro {self.system_release}.") + print("So, I can't provide you a hint with the install procedure.") + print("There are likely missing dependencies.") + + # + # Common dependencies + # + def deactivate_help(self): + print("\n If you want to exit the virtualenv, you can use:") + print("\tdeactivate") + + def get_virtenv(self): + cwd = os.getcwd() + + activates = [] + + # Add all sphinx prefixes with possible version numbers + for p in self.virtenv_prefix: + activates += glob(f"{cwd}/{p}[0-9]*/bin/activate") + + activates.sort(reverse=True, key=str.lower) + + # Place sphinx_latest first, if it exists + for p in self.virtenv_prefix: + activates = glob(f"{cwd}/{p}*latest/bin/activate") + activates + + ver = (0, 0, 0) + for f in activates: + # Discard too old Sphinx virtual environments + match = re.search(r"(\d+)\.(\d+)\.(\d+)", f) + if match: + ver = (int(match.group(1)), int(match.group(2)), int(match.group(3))) + + if ver < self.min_version: + continue + + sphinx_cmd = f.replace("activate", "sphinx-build") + if not os.path.isfile(sphinx_cmd): + continue + + ver = self.get_sphinx_version(sphinx_cmd) + + if not ver: + venv_dir = f.replace("/bin/activate", "") + print(f"Warning: virtual environment {venv_dir} is not working.\n" \ + "Python version upgrade? Remove it with:\n\n" \ + "\trm -rf {venv_dir}\n\n") + else: + if self.need_sphinx and ver >= self.min_version: + return (f, ver) + elif parse_version(ver) > self.cur_version: + return (f, ver) + + return ("", ver) + + def recommend_sphinx_upgrade(self): + # Avoid running sphinx-builds from venv if cur_version is good + if self.cur_version and self.cur_version >= RECOMMENDED_VERSION: + self.latest_avail_ver = self.cur_version + return None + + # Get the highest version from sphinx_*/bin/sphinx-build and the + # corresponding command to activate the venv/virtenv + self.activate_cmd, self.venv_ver = self.get_virtenv() + + # Store the highest version from Sphinx existing virtualenvs + if self.activate_cmd and self.venv_ver > self.cur_version: + self.latest_avail_ver = self.venv_ver + else: + if self.cur_version: + self.latest_avail_ver = self.cur_version + else: + self.latest_avail_ver = (0, 0, 0) + + # As we don't know package version of Sphinx, and there's no + # virtual environments, don't check if upgrades are needed + if not self.virtualenv: + if not self.latest_avail_ver: + return None + + return self.latest_avail_ver + + # Either there are already a virtual env or a new one should be created + self.need_pip = 1 + + if not self.latest_avail_ver: + return None + + # Return if the reason is due to an upgrade or not + if self.latest_avail_ver != (0, 0, 0): + if self.latest_avail_ver < RECOMMENDED_VERSION: + self.rec_sphinx_upgrade = 1 + + return self.latest_avail_ver + + def recommend_sphinx_version(self, virtualenv_cmd): + # The logic here is complex, as it have to deal with different versions: + # - minimal supported version; + # - minimal PDF version; + # - recommended version. + # It also needs to work fine with both distro's package and venv/virtualenv + + # Version is OK. Nothing to do. + if self.cur_version != (0, 0, 0) and self.cur_version >= RECOMMENDED_VERSION: + return + + if not self.need_sphinx: + # sphinx-build is present and its version is >= $min_version + + # only recommend enabling a newer virtenv version if makes sense. + if self.latest_avail_ver and self.latest_avail_ver > self.cur_version: + print("\nYou may also use the newer Sphinx version {self.latest_avail_ver} with:") + if f"{self.virtenv_prefix}" in os.getcwd(): + print("\tdeactivate") + print(f"\t. {self.activate_cmd}") + self.deactivate_help() + return + + if self.latest_avail_ver and self.latest_avail_ver >= RECOMMENDED_VERSION: + return + + if not self.virtualenv: + # No sphinx either via package or via virtenv. As we can't + # Compare the versions here, just return, recommending the + # user to install it from the package distro. + if not self.latest_avail_ver or self.latest_avail_ver == (0, 0, 0): + return + + # User doesn't want a virtenv recommendation, but he already + # installed one via virtenv with a newer version. + # So, print commands to enable it + if self.latest_avail_ver > self.cur_version: + print("\nYou may also use the Sphinx virtualenv version {self.latest_avail_ver} with:") + if f"{self.virtenv_prefix}" in os.getcwd(): + print("\tdeactivate") + print(f"\t. {self.activate_cmd}") + self.deactivate_help() + return + print("\n") + else: + if self.need_sphinx: + self.need += 1 + + # Suggest newer versions if current ones are too old + if self.latest_avail_ver and self.latest_avail_ver >= self.min_version: + if self.latest_avail_ver >= RECOMMENDED_VERSION: + print("\nNeed to activate Sphinx (version {self.latest_avail_ver}) on virtualenv with:") + print(f"\t. {self.activate_cmd}") + self.deactivate_help() + return + + # Version is above the minimal required one, but may be + # below the recommended one. So, print warnings/notes + if self.latest_avail_ver < RECOMMENDED_VERSION: + print(f"Warning: It is recommended at least Sphinx version {RECOMMENDED_VERSION}.") + + # At this point, either it needs Sphinx or upgrade is recommended, + # both via pip + + if self.rec_sphinx_upgrade: + if not self.virtualenv: + print("Instead of install/upgrade Python Sphinx pkg, you could use pip/pypi with:\n\n") + else: + print("To upgrade Sphinx, use:\n\n") + else: + print("\nSphinx needs to be installed either:\n1) via pip/pypi with:\n") + + self.python_cmd = self.find_python_no_venv() + + print(f"\t{virtualenv_cmd} {self.virtenv_dir}") + print(f"\t. {self.virtenv_dir}/bin/activate") + print(f"\tpip install -r {self.requirement_file}") + self.deactivate_help() + + print("\n2) As a package with:") + + old_need = self.need + old_optional = self.optional + self.missing = {} + self.pdf = False + self.optional = 0 + self.install = "" + old_verbose = self.verbose_warn_install + self.verbose_warn_install = 0 + + self.add_package("python-sphinx", 0) + + self.check_distros() + + self.need = old_need + self.optional = old_optional + self.verbose_warn_install = old_verbose + + print("\n" \ + " Please note that Sphinx >= 3.0 will currently produce false-positive\n" \ + " warning when the same name is used for more than one type (functions,\n" \ + " structs, enums,...). This is known Sphinx bug. For more details, see:\n" \ + "\thttps://github.com/sphinx-doc/sphinx/pull/8313") + + def check_needs(self): + self.get_system_release() + + # Check if Sphinx is already accessible from current environment + self.check_sphinx() + + if self.system_release: + print(f"Detected OS: {self.system_release}.") + else: + print("Unknown OS") + if self.cur_version != (0, 0, 0): + ver = ver_str(self.cur_version) + print(f"Sphinx version: {ver}\n") + + # FIXME: Check python command line, trying first python3 + self.python_cmd = self.which("python3") + if not self.python_cmd: + self.python_cmd = self.check_program("python", 0) + + # Check the type of virtual env, depending on Python version + if self.python_cmd: + if self.virtualenv: + try: + result = self.run( + [self.python_cmd, "--version"], + capture_output=True, + text=True, + check=True, + ) + + output = result.stdout + result.stderr + + match = re.search(r"(\d+)\.(\d+)\.", output) + if match: + major = int(match.group(1)) + minor = int(match.group(2)) + + if major < 3: + sys.exit("Python 3 is required to build the kernel docs") + if major == 3 and minor < 3: + self.need_virtualenv = True + else: + sys.exit(f"Warning: couldn't identify {self.python_cmd} version!") + + except subprocess.CalledProcessError as e: + sys.exit(f"Error checking Python version: {e}") + else: + self.add_package("python-sphinx", 0) + + self.venv_ver = self.recommend_sphinx_upgrade() + + virtualenv_cmd = "" + + if self.need_pip: + # Set virtualenv command line, if python < 3.3 + # FIXME: can be removed as we're now with an upper min requirement + # but then we need to check python version + if self.need_virtualenv: + virtualenv_cmd = self.which("virtualenv-3") + if not virtualenv_cmd: + virtualenv_cmd = self.which("virtualenv-3.5") + if not virtualenv_cmd: + self.check_program("virtualenv", 0) + virtualenv_cmd = "virtualenv" + else: + virtualenv_cmd = f"{self.python_cmd} -m venv" + self.check_python_module("ensurepip", 0) + + # Check for needed programs/tools + self.check_perl_module("Pod::Usage", 0) + self.check_python_module("yaml", 0) + self.check_program("make", 0) + self.check_program("gcc", 0) + self.check_program("dot", 1) + self.check_program("convert", 1) + + if self.pdf: + # Extra PDF files - should use 2 for LaTeX is_optional + self.check_program("xelatex", 2) + self.check_program("rsvg-convert", 2) + self.check_program("latexmk", 2) + + # Do distro-specific checks and output distro-install commands + self.check_distros() + + if not self.python_cmd: + if self.need == 1: + sys.exit("Can't build as 1 mandatory dependency is missing") + elif self.need: + sys.exit(f"Can't build as {self.need} mandatory dependencies are missing") + + # Check if sphinx-build is called sphinx-build-3 + if self.need_symlink: + sphinx_path = self.which("sphinx-build-3") + if sphinx_path: + print(f"\tsudo ln -sf {sphinx_path} /usr/bin/sphinx-build\n") + + self.recommend_sphinx_version(virtualenv_cmd) + print("") + + if not self.optional: + print("All optional dependencies are met.") + + if self.need == 1: + sys.exit("Can't build as 1 mandatory dependency is missing") + elif self.need: + sys.exit(f"Can't build as {self.need} mandatory dependencies are missing") + + print("Needed package dependencies are met.") + + def get_system_release(self): + """ + Determine the system type. There's no unique way that would work + with all distros with a minimal package install. So, several + methods are used here. + + By default, it will use lsb_release function. If not available, it will + fail back to reading the known different places where the distro name + is stored. + + Several modern distros now have /etc/os-release, which usually have + a decent coverage. + """ + + if self.which("lsb_release"): + result = self.run(["lsb_release", "-d"], capture_output=True, text=True) + self.system_release = result.stdout.replace("Description:", "").strip() + + release_files = [ + "/etc/system-release", + "/etc/redhat-release", + "/etc/lsb-release", + "/etc/gentoo-release", + ] + + if not self.system_release: + for f in release_files: + self.system_release = self.catcheck(f) + if self.system_release: + break + + # This seems more common than LSB these days + if not self.system_release: + os_var = {} + try: + with open("/etc/os-release", "r", encoding="utf-8") as f: + for line in f: + match = re.match(r"^([\w\d\_]+)=\"?([^\"]*)\"?\n", line) + if match: + os_var[match.group(1)] = match.group(2) + + self.system_release = os_var.get("NAME", "") + if "VERSION_ID" in os_var: + self.system_release += " " + os_var["VERSION_ID"] + elif "VERSION" in os_var: + self.system_release += " " + os_var["VERSION"] + except IOError: + pass + + if not self.system_release: + self.system_release = self.catcheck("/etc/issue") + + self.system_release = self.system_release.strip() + +DESCRIPTION = """ +Process some flags related to Sphinx installation and documentation build. +""" + + +def main(): + parser = argparse.ArgumentParser(description=DESCRIPTION) + + parser.add_argument( + "--no-virtualenv", + action="store_false", + dest="virtualenv", + help="Recommend installing Sphinx instead of using a virtualenv", + ) + + parser.add_argument( + "--no-pdf", + action="store_false", + dest="pdf", + help="Don't check for dependencies required to build PDF docs", + ) + + parser.add_argument( + "--version-check", + action="store_true", + dest="version_check", + help="If version is compatible, don't check for missing dependencies", + ) + + args = parser.parse_args() + + checker = SphinxDependencyChecker(args) + + checker.check_needs() + + +if __name__ == "__main__": + main() From 56a8767751c4bd2b93ba8840a78eccae7018d57c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:21 +0200 Subject: [PATCH 00718/11391] scripts: sphinx-pre-install: Make it compatible with Python 3.6 The minimal version requirements we have is 3.9. Yet, the script which detects it is this one. So, let's try supporting an old version here, as we may want to suggest to upgrade Python version to build the docs. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/39d6e27a047bc3cc8208ac5e11fe6ba44faff9c4.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index dcee2181b72f..71d86b230b22 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -115,7 +115,8 @@ class SphinxDependencyChecker: def find_python_no_venv(): # FIXME: does it makes sense now that this script is in Python? - result = subprocess.run(["pwd"], capture_output=True, text=True) + result = SphinxDependencyChecker.run(["pwd"], capture_output=True, + text=True) cur_dir = result.stdout.strip() python_names = ["python3", "python"] @@ -135,12 +136,23 @@ class SphinxDependencyChecker: def run(*args, **kwargs): """Excecute a command, hiding its output by default""" - if not kwargs.get('capture_output', False): + capture_output = kwargs.pop('capture_output', False) + + if capture_output: + if 'stdout' not in kwargs: + kwargs['stdout'] = subprocess.PIPE + if 'stderr' not in kwargs: + kwargs['stderr'] = subprocess.PIPE + else: if 'stdout' not in kwargs: kwargs['stdout'] = subprocess.DEVNULL if 'stderr' not in kwargs: kwargs['stderr'] = subprocess.DEVNULL + # Don't break with older Python versions + if 'text' in kwargs and sys.version_info < (3, 7): + kwargs['universal_newlines'] = kwargs.pop('text') + return subprocess.run(*args, **kwargs) # From 728648b6a5faa1d6be1e90c04a71481ba33fd08d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:22 +0200 Subject: [PATCH 00719/11391] scripts: sphinx-pre-install: run on a supported version The scripts/sphinx-pre-install is used to detect problems at the system environment and adjust it to build the Kernel documentation. If the version is too old, it won't run, though. Check if the version which started the script is valid. If not, seek for a new one that is compatible with documentation build. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/76627055a7f82f6a79296ddbd873fa5ac8f82a1d.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 65 ++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index 71d86b230b22..3912359d2bae 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -5,6 +5,9 @@ # pylint: disable=C0103,C0114,C0115,C0116,C0301 # pylint: disable=R0902,R0904,R0912,R0915,R1705,R1710,E1121 +# Note: this script requires at least Python 3.6 to run. +# Don't add changes not compatible with it, it is meant to report +# incompatible python versions. import argparse import os @@ -16,7 +19,6 @@ from glob import glob def parse_version(version): """Convert a major.minor.patch version into a tuple""" -# return tuple(int(x) for x in version.split(".")) @@ -27,6 +29,7 @@ def ver_str(version): RECOMMENDED_VERSION = parse_version("3.4.3") +MIN_PYTHON_VERSION = parse_version("3.7") class SphinxDependencyChecker: @@ -132,6 +135,65 @@ class SphinxDependencyChecker: # Python not found at the PATH return python_names[-1] + @staticmethod + def get_python_version(cmd): + + result = SphinxDependencyChecker.run([cmd, "--version"], + capture_output=True, text=True) + version = result.stdout.strip() + + match = re.search(r"(\d+\.\d+\.\d+)", version) + if match: + return parse_version(match.group(1)) + + print(f"Can't parse version {version}") + return (0, 0, 0) + + @staticmethod + def find_python(): + + patterns = [ + "python3.[0-9]", + "python3.[0-9][0-9]", + ] + + new_python_cmd = None + + # Seek for a python binary newer than MIN_PYTHON_VERSION + for path in os.getenv("PATH", "").split(":"): + for pattern in patterns: + for cmd in glob(os.path.join(path, pattern)): + if os.path.isfile(cmd) and os.access(cmd, os.X_OK): + version = SphinxDependencyChecker.get_python_version(cmd) + if version >= MIN_PYTHON_VERSION: + return(cmd) + + @staticmethod + def check_python(): + + cur_ver = sys.version_info[:3] + if cur_ver >= MIN_PYTHON_VERSION: + return + + python_ver = ver_str(cur_ver) + + new_python_cmd = SphinxDependencyChecker.find_python() + if not new_python_cmd: + print(f"ERROR: Python version {python_ver} is not spported anymore") + print(f" Can't find a new version. This script may fail") + return + + # Restart script using the newer version + script_path = os.path.abspath(sys.argv[0]) + args = [new_python_cmd, script_path] + sys.argv[1:] + + print(f"Python {python_ver} not supported. Changing to {new_python_cmd}") + + try: + os.execv(new_python_cmd, args) + except OSError as e: + sys.exit(f"Failed to restart with {new_python_cmd}: {e}") + @staticmethod def run(*args, **kwargs): """Excecute a command, hiding its output by default""" @@ -1107,6 +1169,7 @@ def main(): checker = SphinxDependencyChecker(args) + checker.check_python() checker.check_needs() From ea5dd67722c1ac8ae65ae5a9390452931890f52e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:23 +0200 Subject: [PATCH 00720/11391] scripts: sphinx-pre-install: drop obsolete routines Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/afb97854f05b0852f4c6c1fcee102e9697c14cd8.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index 3912359d2bae..b639acd455cc 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -114,27 +114,6 @@ class SphinxDependencyChecker: return None - @staticmethod - def find_python_no_venv(): - # FIXME: does it makes sense now that this script is in Python? - - result = SphinxDependencyChecker.run(["pwd"], capture_output=True, - text=True) - cur_dir = result.stdout.strip() - - python_names = ["python3", "python"] - - for d in os.environ.get("PATH", "").split(":"): - if f"{cur_dir}/sphinx" in d: - continue - - for p in python_names: - if os.access(os.path.join(d, p), os.X_OK): - return os.path.join(d, p) - - # Python not found at the PATH - return python_names[-1] - @staticmethod def get_python_version(cmd): @@ -940,7 +919,7 @@ class SphinxDependencyChecker: else: print("\nSphinx needs to be installed either:\n1) via pip/pypi with:\n") - self.python_cmd = self.find_python_no_venv() + self.python_cmd = os.path.abspath(sys.argv[0]) print(f"\t{virtualenv_cmd} {self.virtenv_dir}") print(f"\t. {self.virtenv_dir}/bin/activate") From f25bf12afc03ce88ca82fd2ed67fbee5c1ed0cd8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:24 +0200 Subject: [PATCH 00721/11391] scripts: sphinx-pre-install: drop support for old virtualenv Up to Python 3.2, the virtual environment were created via virtualenv binary. As we dropped support for such old version, clean up the code. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/31afe394bcfd8f7e450263c1922d2c73b91d36d8.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 69 +++++++++-------------------------- 1 file changed, 18 insertions(+), 51 deletions(-) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index b639acd455cc..0a73b1b33842 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -80,7 +80,6 @@ class SphinxDependencyChecker: self.need_symlink = 0 self.need_sphinx = 0 self.need_pip = 0 - self.need_virtualenv = 0 self.rec_sphinx_upgrade = 0 self.verbose_warn_install = 1 @@ -919,12 +918,14 @@ class SphinxDependencyChecker: else: print("\nSphinx needs to be installed either:\n1) via pip/pypi with:\n") - self.python_cmd = os.path.abspath(sys.argv[0]) - - print(f"\t{virtualenv_cmd} {self.virtenv_dir}") - print(f"\t. {self.virtenv_dir}/bin/activate") - print(f"\tpip install -r {self.requirement_file}") - self.deactivate_help() + if not virtualenv_cmd: + print(" Currently not possible.\n") + print(" Please upgrade Python to a newer version and run this script again") + else: + print(f"\t{virtualenv_cmd} {self.virtenv_dir}") + print(f"\t. {self.virtenv_dir}/bin/activate") + print(f"\tpip install -r {self.requirement_file}") + self.deactivate_help() print("\n2) As a package with:") @@ -953,6 +954,7 @@ class SphinxDependencyChecker: def check_needs(self): self.get_system_release() + self.python_cmd = sys.executable # Check if Sphinx is already accessible from current environment self.check_sphinx() @@ -965,56 +967,21 @@ class SphinxDependencyChecker: ver = ver_str(self.cur_version) print(f"Sphinx version: {ver}\n") - # FIXME: Check python command line, trying first python3 - self.python_cmd = self.which("python3") - if not self.python_cmd: - self.python_cmd = self.check_program("python", 0) - # Check the type of virtual env, depending on Python version - if self.python_cmd: - if self.virtualenv: - try: - result = self.run( - [self.python_cmd, "--version"], - capture_output=True, - text=True, - check=True, - ) + virtualenv_cmd = None - output = result.stdout + result.stderr - - match = re.search(r"(\d+)\.(\d+)\.", output) - if match: - major = int(match.group(1)) - minor = int(match.group(2)) - - if major < 3: - sys.exit("Python 3 is required to build the kernel docs") - if major == 3 and minor < 3: - self.need_virtualenv = True - else: - sys.exit(f"Warning: couldn't identify {self.python_cmd} version!") - - except subprocess.CalledProcessError as e: - sys.exit(f"Error checking Python version: {e}") - else: - self.add_package("python-sphinx", 0) + if sys.version_info < MIN_PYTHON_VERSION: + min_ver = ver_str(MIN_PYTHON_VERSION) + print(f"ERROR: at least python {min_ver} is required to build the kernel docs") + self.need_sphinx = 1 self.venv_ver = self.recommend_sphinx_upgrade() - virtualenv_cmd = "" - if self.need_pip: - # Set virtualenv command line, if python < 3.3 - # FIXME: can be removed as we're now with an upper min requirement - # but then we need to check python version - if self.need_virtualenv: - virtualenv_cmd = self.which("virtualenv-3") - if not virtualenv_cmd: - virtualenv_cmd = self.which("virtualenv-3.5") - if not virtualenv_cmd: - self.check_program("virtualenv", 0) - virtualenv_cmd = "virtualenv" + if sys.version_info < MIN_PYTHON_VERSION: + self.need_pip = False + print("Warning: python version is not supported.") + else: virtualenv_cmd = f"{self.python_cmd} -m venv" self.check_python_module("ensurepip", 0) From 2cb4877b74349e33be9e209fbcce6114c9a38b9f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:25 +0200 Subject: [PATCH 00722/11391] scripts: sphinx-pre-install: Address issues with OpenSUSE Leap 15.x On openSUSE Leap 15.6, which is the current LTS version, has two Sphinx packages. The normal one requires Python 3.6, which we don't support anymore. However, it also has Python 3.11 with a newer Sphinx version (7.2.6). Suggest the newer version: Detected OS: openSUSE Leap 15.6. ERROR: at least python 3.7 is required to build the kernel docs Warning: python version is not supported. Warning: better to also install "convert". Warning: better to also install "dot". ERROR: please install "yaml", otherwise, build won't work. You should run: sudo zypper install --no-recommends ImageMagick graphviz python311-pyyaml Sphinx needs to be installed either: 1) via pip/pypi with: Currently not possible. Please upgrade Python to a newer version and run this script again 2) As a package with: sudo zypper install --no-recommends python311-Sphinx Please note that Sphinx >= 3.0 will currently produce false-positive warning when the same name is used for more than one type (functions, structs, enums,...). This is known Sphinx bug. For more details, see: https://github.com/sphinx-doc/sphinx/pull/8313 Can't build as 2 mandatory dependencies are missing Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/a1600e292b63f96f40163e350238812158ebd6c2.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index 0a73b1b33842..eca42d90ed01 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -556,6 +556,22 @@ class SphinxDependencyChecker: progs["latexmk"] = "texlive-latexmk-bin" + match = re.search(r"(Leap)\s+(\d+).(\d)", self.system_release) + if match: + rel = int(match.group(2)) + + # Leap 15.x uses Python 3.6, which is not compatible with + # the build system anymore. Suggest Python 3.11 + if rel == 15: + if not self.which(self.python_cmd): + self.add_package(self.python_cmd, 0) + + progs.update({ + "python-sphinx": "python311-Sphinx", + "virtualenv": "python311-virtualenv", + "yaml": "python311-pyyaml", + }) + # FIXME: add support for installing CJK fonts # # I tried hard, but was unable to find a way to install From c5ffae0fa965884d09458002e3d990c039602809 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:26 +0200 Subject: [PATCH 00723/11391] scripts: sphinx-pre-install: fix opensuse Leap hint for PyYAML On Leap, the name of the package is python311-PyYAML. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/0266c5e28e136c62de33d2d7f7d5e69b273e0d01.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index eca42d90ed01..65438c198674 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -569,7 +569,7 @@ class SphinxDependencyChecker: progs.update({ "python-sphinx": "python311-Sphinx", "virtualenv": "python311-virtualenv", - "yaml": "python311-pyyaml", + "yaml": "python311-PyYAML", }) # FIXME: add support for installing CJK fonts From 582b0f95c92e0a0ec79d23ed434786251bd4378b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:27 +0200 Subject: [PATCH 00724/11391] scripts: sphinx-pre-install: fix support for gentoo Some gentoo packages have changes. Fix it. While here, improve emerge portage use logic. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/283987633aae7d99e0eff41e24eb6285c1b6b335.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index 65438c198674..b793796329c8 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -669,12 +669,13 @@ class SphinxDependencyChecker: def give_gentoo_hints(self): progs = { - "convert": "media-gfx/imagemagick", - "dot": "media-gfx/graphviz", - "rsvg-convert": "gnome-base/librsvg", - "virtualenv": "dev-python/virtualenv", - "xelatex": "dev-texlive/texlive-xetex media-fonts/dejavu", - "yaml": "dev-python/pyyaml", + "convert": "media-gfx/imagemagick", + "dot": "media-gfx/graphviz", + "rsvg-convert": "gnome-base/librsvg", + "virtualenv": "dev-python/virtualenv", + "xelatex": "dev-texlive/texlive-xetex media-fonts/dejavu", + "yaml": "dev-python/pyyaml", + "python-sphinx": "dev-python/sphinx", } if self.pdf: @@ -699,21 +700,17 @@ class SphinxDependencyChecker: print("You should run:") print("\n") - imagemagick = "media-gfx/imagemagick svg png" - cairo = "media-gfx/graphviz cairo pdf" - portage_imagemagick = "/etc/portage/package.use/imagemagick" - portage_cairo = "/etc/portage/package.use/graphviz" - result = self.run(["grep", "imagemagick", portage_imagemagick], - stdout=subprocess.PIPE, text=True) - if not result.stdout.strip(): - print(f"\tsudo su -c 'echo \"{imagemagick}\" > {portage_imagemagick}'") + portages = [ + "media-gfx/imagemagick", + "media-gfx/graphviz", + ] - result = self.run(["grep", "graphviz", portage_cairo], - stdout=subprocess.PIPE, text=True) - - if not result.stdout.strip(): - print(f"\tsudo su -c 'echo \"{cairo}\" > {portage_cairo}'") + for p in portages: + result = self.run(["grep", p, "/etc/portage/package.use/*"], + stdout=subprocess.PIPE, text=True) + if not result.stdout.strip(): + print(f"\tsudo emerge -av1 {p}") print(f"\tsudo emerge --ask {self.install}") From 94a161d998a103346088d97da6d1cfec4df97ddc Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:28 +0200 Subject: [PATCH 00725/11391] scripts: sphinx-pre-install: Address issues with OpenSUSE Tumbleweed On Tumbleweed, package names are named after python-313*, as it also has older python versions on it. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/fe0b5f7c18d7b32e0229c0890371e1441ffea294.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index b793796329c8..0e165ad05fdb 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -571,6 +571,14 @@ class SphinxDependencyChecker: "virtualenv": "python311-virtualenv", "yaml": "python311-PyYAML", }) + else: + # Tumbleweed defaults to Python 3.11 + + progs.update({ + "python-sphinx": "python313-Sphinx", + "virtualenv": "python313-virtualenv", + "yaml": "python313-PyYAML", + }) # FIXME: add support for installing CJK fonts # From 12bdcf898977172a93fc30668f8918da83c51f86 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:29 +0200 Subject: [PATCH 00726/11391] scripts: sphinx-pre-install: only show portage hints once On gentoo, doesn't repeat instructions about how to enable portage. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/d4e7ef1d5e1f0412eb9f9ae4913dc64c0821e002.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index 0e165ad05fdb..808d31bfa790 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -89,6 +89,9 @@ class SphinxDependencyChecker: self.python_cmd = "" self.activate_cmd = "" + # Certain hints are meant to be shown only once + self.first_hint = True + self.min_version = (0, 0, 0) self.cur_version = (0, 0, 0) self.latest_avail_ver = (0, 0, 0) @@ -714,11 +717,14 @@ class SphinxDependencyChecker: "media-gfx/graphviz", ] - for p in portages: - result = self.run(["grep", p, "/etc/portage/package.use/*"], - stdout=subprocess.PIPE, text=True) - if not result.stdout.strip(): - print(f"\tsudo emerge -av1 {p}") + if self.first_hint: + for p in portages: + result = self.run(["grep", p, "/etc/portage/package.use/*"], + stdout=subprocess.PIPE, text=True) + if not result.stdout.strip(): + print(f"\tsudo emerge -av1 {p}") + + self.first_hint = False print(f"\tsudo emerge --ask {self.install}") From 8f6f54c464d7fccfb8da46ca0afcb0860e6d73bb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:30 +0200 Subject: [PATCH 00727/11391] scripts: sphinx-pre-install: cleanup rhel support Rhel < 8.0 is not supported anymore. Drop support for it. Rhel 8 is problematic: at least on the tests I did with a docker repo, it didn't work, but it could be due to the issue that it is actually different than a real One. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/62fe8ab243ad39f4964f1f74b965e43dc8f10e23.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index 808d31bfa790..42f55e67256d 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -487,15 +487,31 @@ class SphinxDependencyChecker: progs["virtualenv"] = "python-virtualenv" - if rel and rel < 8: + if not rel or rel < 8: old = 1 self.pdf = False - # RHEL 7 is in ELS, currently up to Jun, 2026 + print("ERROR: Distro not supported. Too old?") + return + + # TODO: check if RHEL8 still works. + # On my tests with docker "redhat/ubi8" image, there's no + # python3-sphinx (or similar) package. It comes with Python 3.6, + # but there are other python packages over there, so it may be + # possible to work with venv. + + if self.first_hint: + print("Note: RHEL-based distros typically require extra repositories.\n" \ + "For most, enabling epel and crb are enough:\n" \ + "\tsudo dnf install -y epel-release", \ + "\tsudo dnf config-manager --set-enabled crb\n" \ + "Yet, some may have other required repositories. Those commands could be useful:" \ + "\tsudo dnf repolist all" \ + "\tsudo repoquery --available --info ", + "\tsudo dnf config-manager --set-enabled '*' # enable all - probably not what you want") + + self.first_hint = False - print("Note: texlive packages on RHEL/CENTOS <= 7 are incomplete. Can't support PDF output") - print("If you want to build PDF, please read:") - print("\thttps://www.systutorials.com/241660/how-to-install-tex-live-on-centos-7-linux/") if self.pdf: pdf_pkgs = [ From 637fa6b38113fddca7da2f0507f709f46a44047a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:31 +0200 Subject: [PATCH 00728/11391] scripts: sphinx-pre-install: output Python and docutils version Specially when debugging issues, knowing the versions is important. Add it to the script output. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/96142ec916b9064c859b200639c3595115080322.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index 42f55e67256d..de5bcfd052b5 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -154,6 +154,20 @@ class SphinxDependencyChecker: cur_ver = sys.version_info[:3] if cur_ver >= MIN_PYTHON_VERSION: + ver = ver_str(cur_ver) + print(f"Python version: {ver}") + + # This could be useful for debugging purposes + if SphinxDependencyChecker.which("docutils"): + result = SphinxDependencyChecker.run(["docutils", "--version"], + capture_output=True, text=True) + ver = result.stdout.strip() + match = re.search(r"(\d+\.\d+\.\d+)", ver) + if match: + ver = match.group(1) + + print(f"Docutils version: {ver}") + return python_ver = ver_str(cur_ver) From cccc5389811a34eccbd0f531c89d284f1cebdd70 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:32 +0200 Subject: [PATCH 00729/11391] scripts: sphinx-pre-install: add a missing f-string marker I forgot one f-string marker, with turned to be affecting 3 lines, because of cut-and-paste ;-) Use the proper f-string marker to print Sphinx version at the hint lines. Yet, we don't want to print as a tuple, so call ver_str() for it. Ideally, we would be placing it directly at the f-string, but Python 3.6 f-string support was pretty much limited. Only 3.12 (PEP 701) makes it similar to Perl, allowing expressions inside it. It sounds that function call itself was introduced on 3.7. As we explicitly want this one to run on 3.6, as latest Leap comes with it, we can't use function calls on f-string. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/b0ad1795446b17a00ba2dd83f366e784253668e6.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index de5bcfd052b5..6a244105f7ef 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -914,12 +914,15 @@ class SphinxDependencyChecker: if self.cur_version != (0, 0, 0) and self.cur_version >= RECOMMENDED_VERSION: return + if self.latest_avail_ver: + latest_avail_ver = ver_str(self.latest_avail_ver) + if not self.need_sphinx: # sphinx-build is present and its version is >= $min_version # only recommend enabling a newer virtenv version if makes sense. if self.latest_avail_ver and self.latest_avail_ver > self.cur_version: - print("\nYou may also use the newer Sphinx version {self.latest_avail_ver} with:") + print(f"\nYou may also use the newer Sphinx version {latest_avail_ver} with:") if f"{self.virtenv_prefix}" in os.getcwd(): print("\tdeactivate") print(f"\t. {self.activate_cmd}") @@ -940,7 +943,7 @@ class SphinxDependencyChecker: # installed one via virtenv with a newer version. # So, print commands to enable it if self.latest_avail_ver > self.cur_version: - print("\nYou may also use the Sphinx virtualenv version {self.latest_avail_ver} with:") + print(f"\nYou may also use the Sphinx virtualenv version {latest_avail_ver} with:") if f"{self.virtenv_prefix}" in os.getcwd(): print("\tdeactivate") print(f"\t. {self.activate_cmd}") @@ -954,7 +957,7 @@ class SphinxDependencyChecker: # Suggest newer versions if current ones are too old if self.latest_avail_ver and self.latest_avail_ver >= self.min_version: if self.latest_avail_ver >= RECOMMENDED_VERSION: - print("\nNeed to activate Sphinx (version {self.latest_avail_ver}) on virtualenv with:") + print(f"\nNeed to activate Sphinx (version {latest_avail_ver}) on virtualenv with:") print(f"\t. {self.activate_cmd}") self.deactivate_help() return From 8b18e86f6c0063e33096bf84ffcd9fb9ced4844d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:33 +0200 Subject: [PATCH 00730/11391] scripts: sphinx-pre-install: fix Leap support for rsvg-convert There is a test logic meant to be for Leap, renaming rsvg-convert package. Well, at least on latest Leap releases, this is wrong, causing install to fail. Drop it. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/6fcc94533d860e2f6f4f2c7d6ceb6cca70f48bb6.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index 6a244105f7ef..6b5f9eda91bb 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -566,10 +566,6 @@ class SphinxDependencyChecker: "yaml": "python3-pyyaml", } - # On Tumbleweed, this package is also named rsvg-convert - if not re.search(r"Tumbleweed", self.system_release): - progs["rsvg-convert"] = "rsvg-view" - suse_tex_pkgs = [ "texlive-babel-english", "texlive-caption", From e53e6d395fe036bb2c24dc79dc728e9a82ee0b82 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:34 +0200 Subject: [PATCH 00731/11391] scripts: sphinx-pre-install: fix rhel recomendations Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/393a299a850ba9d94c6a8965e78db4da2dbf7e37.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index 6b5f9eda91bb..1f64909953b9 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -519,9 +519,9 @@ class SphinxDependencyChecker: "For most, enabling epel and crb are enough:\n" \ "\tsudo dnf install -y epel-release", \ "\tsudo dnf config-manager --set-enabled crb\n" \ - "Yet, some may have other required repositories. Those commands could be useful:" \ - "\tsudo dnf repolist all" \ - "\tsudo repoquery --available --info ", + "Yet, some may have other required repositories. Those commands could be useful:\n" \ + "\tsudo dnf repolist all\n" \ + "\tsudo dnf repoquery --available --info \n", "\tsudo dnf config-manager --set-enabled '*' # enable all - probably not what you want") self.first_hint = False From 42e3f9f360e70bea4ee7d4e895f042d86ee11500 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:35 +0200 Subject: [PATCH 00732/11391] scripts: sphinx-pre-install: remove Scientific Linux According with its website: https://scientificlinux.org/ Scientific Linux reached end of life in June 30, 2024. Also, it was based on RHEL 7, which is not compatible with our build system anymore. So, drop support for it. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/dde5e0c95017022840f8a522ce44759e51f52aa1.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index 1f64909953b9..cd9c83b17971 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -769,7 +769,6 @@ class SphinxDependencyChecker: re.compile("openEuler"): self.give_redhat_hints, re.compile("Oracle Linux Server"): self.give_redhat_hints, re.compile("Rocky Linux"): self.give_redhat_hints, - re.compile("Scientific Linux"): self.give_redhat_hints, re.compile("Springdale Open Enterprise"): self.give_redhat_hints, re.compile("Ubuntu"): self.give_debian_hints, From 1a7da749f18335d7996df3004225ca7418a1052d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:36 +0200 Subject: [PATCH 00733/11391] scripts: sphinx-pre-install: improve Gentoo package deps logic It took me a lot of time, but I guess understand now what it takes to install a package on Gentoo. Handling dependencies is a nightmare, as Gentoo refuses to emerge some packages if there's no package.use file describing them. To make it worse, compilation flags shall also be present there for some packages. If USE is not perfect, error/warning messages like those are shown: gnome-base/librsvg dev-texlive/texlive-xetex media-fonts/dejavu dev-python/pyyaml ... !!! The following binary packages have been ignored due to non matching USE: =media-gfx/graphviz-12.2.1-r1 X pdf -python_single_target_python3_13 qt6 svg =media-gfx/graphviz-12.2.1-r1 X pdf python_single_target_python3_12 -python_single_target_python3_13 qt6 svg =media-gfx/graphviz-12.2.1-r1 X pdf qt6 svg =media-gfx/graphviz-12.2.1-r1 X pdf -python_single_target_python3_10 qt6 svg =media-gfx/graphviz-12.2.1-r1 X pdf -python_single_target_python3_10 python_single_target_python3_12 -python_single_target_python3_13 qt6 svg =media-fonts/noto-cjk-20190416 X =app-text/texlive-core-2024-r1 X cjk -xetex =app-text/texlive-core-2024-r1 X -xetex =app-text/texlive-core-2024-r1 -xetex =dev-libs/zziplib-0.13.79-r1 sdl If emerge is allowed, it will simply ignore the above packages, creating an incomplete installation, which will later fail when one tries to build docs with images or build PDFs. After the fix, command line commands to produce the needed USE chain will be emitted, if they don't exist yet. sudo su -c 'echo "media-gfx/graphviz" > /etc/portage/package.use/graphviz' sudo su -c 'echo "media-gfx/imagemagick" > /etc/portage/package.use/imagemagick' sudo su -c 'echo "media-libs/harfbuzz icu" > /etc/portage/package.use/media-libs' sudo su -c 'echo "media-fonts/noto-cjk" > /etc/portage/package.use/media-fonts' sudo su -c 'echo "app-text/texlive-core xetex" > /etc/portage/package.use/texlive' sudo su -c 'echo "dev-libs/zziplib sdl" > /etc/portage/package.use/zziblib' The new logic tries to be smart enough to detect for missing files and missing arguments. Yet, as Gentoo seems to require users to manage those package.use files by hand, the logic isn't perfect: users may still need to verify for conflicts on different use files. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/365fe5e7d568da932dcffde65f48f2c1256cb773.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 86 +++++++++++++++++++++++++++++++---- 1 file changed, 76 insertions(+), 10 deletions(-) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index cd9c83b17971..94f3d2e32fd6 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -737,22 +737,88 @@ class SphinxDependencyChecker: print("You should run:") print("\n") + # Handling dependencies is a nightmare, as Gentoo refuses to emerge + # some packages if there's no package.use file describing them. + # To make it worse, compilation flags shall also be present there + # for some packages. If USE is not perfect, error/warning messages + # like those are shown: + # + # !!! The following binary packages have been ignored due to non matching USE: + # + # =media-gfx/graphviz-12.2.1-r1 X pdf -python_single_target_python3_13 qt6 svg + # =media-gfx/graphviz-12.2.1-r1 X pdf python_single_target_python3_12 -python_single_target_python3_13 qt6 svg + # =media-gfx/graphviz-12.2.1-r1 X pdf qt6 svg + # =media-gfx/graphviz-12.2.1-r1 X pdf -python_single_target_python3_10 qt6 svg + # =media-gfx/graphviz-12.2.1-r1 X pdf -python_single_target_python3_10 python_single_target_python3_12 -python_single_target_python3_13 qt6 svg + # =media-fonts/noto-cjk-20190416 X + # =app-text/texlive-core-2024-r1 X cjk -xetex + # =app-text/texlive-core-2024-r1 X -xetex + # =app-text/texlive-core-2024-r1 -xetex + # =dev-libs/zziplib-0.13.79-r1 sdl + # + # And will ignore such packages, installing the remaining ones. That + # affects mostly the image extension and PDF generation. - portages = [ - "media-gfx/imagemagick", - "media-gfx/graphviz", - ] + # Package dependencies and the minimal needed args: + portages = { + "graphviz": "media-gfx/graphviz", + "imagemagick": "media-gfx/imagemagick", + "media-libs": "media-libs/harfbuzz icu", + "media-fonts": "media-fonts/noto-cjk", + "texlive": "app-text/texlive-core xetex", + "zziblib": "dev-libs/zziplib sdl", + } if self.first_hint: - for p in portages: - result = self.run(["grep", p, "/etc/portage/package.use/*"], - stdout=subprocess.PIPE, text=True) - if not result.stdout.strip(): - print(f"\tsudo emerge -av1 {p}") + use_base = "/etc/portage/package.use" + files = glob(f"{use_base}/*") + + for fname, portage in portages.items(): + install = False + + while install == False: + if not files: + # No files under package.usage. Install all + install = True + break + + args = portage.split(" ") + + name = args.pop(0) + + cmd = ["grep", "-l", "-E", rf"^{name}\b" ] + files + result = self.run(cmd, stdout=subprocess.PIPE, text=True) + if result.returncode or not result.stdout.strip(): + # File containing portage name not found + install = True + break + + # Ensure that needed USE flags are present + if args: + match_fname = result.stdout.strip() + with open(match_fname, 'r', encoding='utf8', + errors='backslashreplace') as fp: + for line in fp: + for arg in args: + if arg.startswith("-"): + continue + + if not re.search(rf"\s*{arg}\b", line): + # Needed file argument not found + install = True + break + + # Everything looks ok, don't install + break + + # emit a code to setup missing USE + if install: + print(f"\tsudo su -c 'echo \"{portage}\" > {use_base}/{fname}'") self.first_hint = False - print(f"\tsudo emerge --ask {self.install}") + # Now, we can use emerge and let it respect USE + print(f"\tsudo emerge --ask --changed-use --binpkg-respect-use=y {self.install}") # # Dispatch the check to an os_specific hinter From fb08659be07e646f8103449e02d5e58b32c284d9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:37 +0200 Subject: [PATCH 00734/11391] scripts: sphinx-pre-install: fix OpenMandriva support OpenMandriva Lx 4.3 has different package names for ImageMagick and yaml. Fix them to ensure that system setup will pass. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/0b4e7aa88c96e6a5b8f2e6f381b3e21124680d33.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index 94f3d2e32fd6..2f6036eadc94 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -647,6 +647,11 @@ class SphinxDependencyChecker: packager_cmd = "dnf install" noto_sans = "noto-sans-cjk-fonts" tex_pkgs = ["texlive-collection-fontsextra"] + + # Tested on OpenMandriva Lx 4.3 + progs["convert"] = "imagemagick" + progs["yaml"] = "python-pyyaml" + else: packager_cmd = "urpmi" noto_sans = "google-noto-sans-cjk-ttc-fonts" From 1ad72e9dfa5ef24ca489b7cbaa5f6f85b1fe87d8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:38 +0200 Subject: [PATCH 00735/11391] scripts: sphinx-pre-install: move package instructions to a new func Currently, if Python < 3.7, package install will fail. That happens with OpenSuse Leap and RHEL-based ver 8 distros. OpenSuse allows installing Sphinx with Python 3.11, but RHEL-based distros don't. Prepare to recomend only venv on such cases. For now, just split the recomendation on a new function that will check for a paramtere to be called. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/4fb2181c960e89774309a833f80209a1a3ab10d2.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 44 +++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index 2f6036eadc94..2360ca2ed21c 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -89,6 +89,9 @@ class SphinxDependencyChecker: self.python_cmd = "" self.activate_cmd = "" + # Some distros may not have a Sphinx shipped package compatible with + # our minimal requirements + self.package_supported = True # Certain hints are meant to be shown only once self.first_hint = True @@ -969,6 +972,27 @@ class SphinxDependencyChecker: return self.latest_avail_ver + def recommend_package(self): + + print("\n2) As a package with:") + + old_need = self.need + old_optional = self.optional + self.missing = {} + self.pdf = False + self.optional = 0 + self.install = "" + old_verbose = self.verbose_warn_install + self.verbose_warn_install = 0 + + self.add_package("python-sphinx", 0) + + self.check_distros() + + self.need = old_need + self.optional = old_optional + self.verbose_warn_install = old_verbose + def recommend_sphinx_version(self, virtualenv_cmd): # The logic here is complex, as it have to deal with different versions: # - minimal supported version; @@ -1053,24 +1077,8 @@ class SphinxDependencyChecker: print(f"\tpip install -r {self.requirement_file}") self.deactivate_help() - print("\n2) As a package with:") - - old_need = self.need - old_optional = self.optional - self.missing = {} - self.pdf = False - self.optional = 0 - self.install = "" - old_verbose = self.verbose_warn_install - self.verbose_warn_install = 0 - - self.add_package("python-sphinx", 0) - - self.check_distros() - - self.need = old_need - self.optional = old_optional - self.verbose_warn_install = old_verbose + if self.package_supported: + self.recommend_package() print("\n" \ " Please note that Sphinx >= 3.0 will currently produce false-positive\n" \ From 6db1d3977baf7ac895033624897d38fb60cbe3f7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:39 +0200 Subject: [PATCH 00736/11391] scripts: sphinx-pre-install: adjust a warning message There is one extra space at the first line. Also, as now we only support Python 3.4+, update the text. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/74a17edd70364ca623a54b62bd97a344bb474988.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index 2360ca2ed21c..365590f81551 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -1081,8 +1081,8 @@ class SphinxDependencyChecker: self.recommend_package() print("\n" \ - " Please note that Sphinx >= 3.0 will currently produce false-positive\n" \ - " warning when the same name is used for more than one type (functions,\n" \ + " Please note that Sphinx currentlys produce false-positive\n" \ + " warnings when the same name is used for more than one type (functions,\n" \ " structs, enums,...). This is known Sphinx bug. For more details, see:\n" \ "\thttps://github.com/sphinx-doc/sphinx/pull/8313") From 8cd256524a920782268a0dd7e3e0404c34bfc65f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:40 +0200 Subject: [PATCH 00737/11391] scripts: sphinx-pre-install: better handle Python min version Don't do any recommendations about Sphinx install with too old python versions. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/013aeb848ecc3f6b69b4518cf3d335bd2353b6e1.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index 365590f81551..a5c777e529ec 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -92,6 +92,10 @@ class SphinxDependencyChecker: # Some distros may not have a Sphinx shipped package compatible with # our minimal requirements self.package_supported = True + + # Recommend a new python version + self.recommend_python = None + # Certain hints are meant to be shown only once self.first_hint = True @@ -511,11 +515,11 @@ class SphinxDependencyChecker: print("ERROR: Distro not supported. Too old?") return - # TODO: check if RHEL8 still works. - # On my tests with docker "redhat/ubi8" image, there's no - # python3-sphinx (or similar) package. It comes with Python 3.6, - # but there are other python packages over there, so it may be - # possible to work with venv. + # RHEL 8 uses Python 3.6, which is not compatible with + # the build system anymore. Suggest Python 3.11 + if rel == 8: + self.add_package("python39", 0) + self.recommend_python = True if self.first_hint: print("Note: RHEL-based distros typically require extra repositories.\n" \ @@ -596,6 +600,7 @@ class SphinxDependencyChecker: # the build system anymore. Suggest Python 3.11 if rel == 15: if not self.which(self.python_cmd): + self.recommend_python = True self.add_package(self.python_cmd, 0) progs.update({ @@ -1000,6 +1005,11 @@ class SphinxDependencyChecker: # - recommended version. # It also needs to work fine with both distro's package and venv/virtualenv + if self.recommend_python: + print("\nPython version is incompatible with doc build.\n" \ + "Please upgrade it and re-run.\n") + return + # Version is OK. Nothing to do. if self.cur_version != (0, 0, 0) and self.cur_version >= RECOMMENDED_VERSION: return From 9ecda2e10101537e97bcb2b05049e58306ac4e1b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:41 +0200 Subject: [PATCH 00738/11391] scripts: sphinx-pre-install: convert is_optional to a class When is_optional was added in Perl, it was a boolean. With time, it ended becoming a sort of enum, which makes the module harder to maintain. Convert it to a enum-like class and add more options to it. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/42290a24f3b1dbea9ebe19747cf5622bb2f2cf5c.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 194 +++++++++++++++++++++++----------- 1 file changed, 131 insertions(+), 63 deletions(-) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index a5c777e529ec..0963da21c27b 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -32,6 +32,53 @@ RECOMMENDED_VERSION = parse_version("3.4.3") MIN_PYTHON_VERSION = parse_version("3.7") +class DepType: + + # Internal types of dependencies. + _SYS_TYPE = 0 + _PHY_TYPE = 1 + _PDF_TYPE = 2 + + # Let's define keys as a tuple with the type and mandatory/optional. + # This way, checking for optional or type is easy. + + SYSTEM_MANDATORY = (_SYS_TYPE, True) + PYTHON_MANDATORY = (_PHY_TYPE, True) + PDF_MANDATORY = (_PDF_TYPE, True) + + # Currently we're not using all optional types, but let's keep all + # combinations here, as we may end needing them in the future. Also, + # it allows a name() function that handles all possibilities. + SYSTEM_OPTIONAL = (_SYS_TYPE, False) + PYTHON_OPTIONAL = (_PHY_TYPE, False) + PDF_OPTIONAL = (_PDF_TYPE, True) + + @staticmethod + def name(dtype): + if dtype[0] == DepType._SYS_TYPE: + msg = "build" + elif dtype[0] == DepType._PHY_TYPE: + msg = "Python" + else: + msg = "PDF" + + if dtype[1]: + return f"ERROR: {msg} mandatory deps missing" + else: + out = f"Warning: {msg} optional deps missing" + + @staticmethod + def is_optional(dtype): + return not dtype[1] + + @staticmethod + def is_pdf(dtype): + if (dtype[0] == DepType._PDF_TYPE): + return True + + return False + + class SphinxDependencyChecker: # List of required texlive packages on Fedora and OpenSuse texlive = { @@ -223,56 +270,68 @@ class SphinxDependencyChecker: # Methods to check if a feature exists # - # Note: is_optional has 3 states: - # - 0: mandatory - # - 1: optional, but nice to have - # - 2: LaTeX optional - pdf builds without it, but may have visual impact - def check_missing(self, progs): - for prog, is_optional in sorted(self.missing.items()): + run = {} + + for prog, dtype in sorted(self.missing.items()): # At least on some LTS distros like CentOS 7, texlive doesn't # provide all packages we need. When such distros are # detected, we have to disable PDF output. # # So, we need to ignore the packages that distros would # need for LaTeX to work - if is_optional == 2 and not self.pdf: + if DepType.is_pdf(dtype) and not self.pdf: self.optional -= 1 continue - if self.verbose_warn_install: - if is_optional: - print(f'Warning: better to also install "{prog}".') - else: - print(f'ERROR: please install "{prog}", otherwise, build won\'t work.') + if not dtype in run: + run[dtype] = [] - self.install += " " + progs.get(prog, prog) + run[dtype].append(prog) + + output_msg = "" + + for dtype in sorted(run.keys()): + progs = " ".join(run[dtype]) + + if self.verbose_warn_install: + try: + name = DepType.name(dtype) + output_msg += f'{name}:\t{progs}\n' + except KeyError: + raise KeyError(f"ERROR!!!: invalid dtype for {progs}: {dtype}") + + self.install += " " + progs + + if output_msg: + print(f"\n{output_msg}\n") self.install = self.install.lstrip() - def add_package(self, package, is_optional): - self.missing[package] = is_optional + def add_package(self, package, dtype): + is_optional = DepType.is_optional(dtype) + self.missing[package] = dtype if is_optional: self.optional += 1 else: self.need += 1 - def check_missing_file(self, files, package, is_optional): + def check_missing_file(self, files, package, dtype): for f in files: if os.path.exists(f): return - self.add_package(package, is_optional) + self.add_package(package, dtype) - def check_program(self, prog, is_optional): + def check_program(self, prog, dtype): found = self.which(prog) if found: return found - self.add_package(prog, is_optional) + self.add_package(prog, dtype) return None - def check_perl_module(self, prog, is_optional): + def check_perl_module(self, prog, dtype): # While testing with lxc download template, one of the # distros (Oracle) didn't have perl - nor even an option to install # before installing oraclelinux-release-el9 package. @@ -281,46 +340,52 @@ class SphinxDependencyChecker: # add it as a mandatory package, as some parts of the doc builder # needs it. if not self.which("perl"): - self.add_package("perl", 0) - self.add_package(prog, is_optional) + self.add_package("perl", DepType.SYSTEM_MANDATORY) + self.add_package(prog, dtype) return try: self.run(["perl", f"-M{prog}", "-e", "1"], check=True) except subprocess.CalledProcessError: - self.add_package(prog, is_optional) + self.add_package(prog, dtype) - def check_python_module(self, module, is_optional): - # FIXME: is it needed at the Python version? Maybe due to venv? - if not self.python_cmd: - return + def check_python_module(self, module, is_optional=False): + if is_optional: + dtype = DepType.PYTHON_OPTIONAL + else: + dtype = DepType.PYTHON_MANDATORY try: self.run([self.python_cmd, "-c", f"import {module}"], check=True) except subprocess.CalledProcessError: - self.add_package(module, is_optional) + self.add_package(module, dtype) - def check_rpm_missing(self, pkgs, is_optional): + def check_rpm_missing(self, pkgs, dtype): for prog in pkgs: try: self.run(["rpm", "-q", prog], check=True) except subprocess.CalledProcessError: - self.add_package(prog, is_optional) + self.add_package(prog, dtype) - def check_pacman_missing(self, pkgs, is_optional): + def check_pacman_missing(self, pkgs, dtype): for prog in pkgs: try: self.run(["pacman", "-Q", prog], check=True) except subprocess.CalledProcessError: - self.add_package(prog, is_optional) + self.add_package(prog, dtype) + + def check_missing_tex(self, is_optional=False): + if is_optional: + dtype = DepType.PDF_OPTIONAL + else: + dtype = DepType.PDF_MANDATORY - def check_missing_tex(self, is_optional): kpsewhich = self.which("kpsewhich") for prog, package in self.texlive.items(): # If kpsewhich is not there, just add it to deps if not kpsewhich: - self.add_package(package, is_optional) + self.add_package(package, dtype) continue # Check if the package is needed @@ -331,11 +396,11 @@ class SphinxDependencyChecker: # Didn't find. Add it if not result.stdout.strip(): - self.add_package(package, is_optional) + self.add_package(package, dtype) except subprocess.CalledProcessError: # kpsewhich returned an error. Add it, just in case - self.add_package(package, is_optional) + self.add_package(package, dtype) def get_sphinx_fname(self): if "SPHINXBUILD" in os.environ: @@ -446,9 +511,9 @@ class SphinxDependencyChecker: } for package, files in pdf_pkgs.items(): - self.check_missing_file(files, package, 2) + self.check_missing_file(files, package, DepType.PDF_MANDATORY) - self.check_program("dvipng", 2) + self.check_program("dvipng", DepType.PDF_MANDATORY) self.check_missing(progs) @@ -518,7 +583,7 @@ class SphinxDependencyChecker: # RHEL 8 uses Python 3.6, which is not compatible with # the build system anymore. Suggest Python 3.11 if rel == 8: - self.add_package("python39", 0) + self.add_package("python39", DepType.SYSTEM_MANDATORY) self.recommend_python = True if self.first_hint: @@ -540,13 +605,13 @@ class SphinxDependencyChecker: "/usr/share/fonts/google-noto-sans-cjk-fonts/NotoSansCJK-Regular.ttc", ] - self.check_missing_file(pdf_pkgs, noto_sans_redhat, 2) + self.check_missing_file(pdf_pkgs, noto_sans_redhat, DepType.PDF_MANDATORY) if not old: - self.check_rpm_missing(fedora26_opt_pkgs, 2) - self.check_rpm_missing(fedora_tex_pkgs, 2) + self.check_rpm_missing(fedora26_opt_pkgs, DepType.PDF_MANDATORY) + self.check_rpm_missing(fedora_tex_pkgs, DepType.PDF_MANDATORY) - self.check_missing_tex(2) + self.check_missing_tex() self.check_missing(progs) @@ -601,7 +666,7 @@ class SphinxDependencyChecker: if rel == 15: if not self.which(self.python_cmd): self.recommend_python = True - self.add_package(self.python_cmd, 0) + self.add_package(self.python_cmd, DepType.SYSTEM_MANDATORY) progs.update({ "python-sphinx": "python311-Sphinx", @@ -623,9 +688,9 @@ class SphinxDependencyChecker: # "Noto Sans CJK SC" on openSUSE if self.pdf: - self.check_rpm_missing(suse_tex_pkgs, 2) + self.check_rpm_missing(suse_tex_pkgs, DepType.PDF_MANDATORY) if self.pdf: - self.check_missing_tex(2) + self.check_missing_tex() self.check_missing(progs) if not self.need and not self.optional: @@ -672,8 +737,8 @@ class SphinxDependencyChecker: "/usr/share/fonts/TTF/NotoSans-Regular.ttf", ] - self.check_missing_file(pdf_pkgs, noto_sans, 2) - self.check_rpm_missing(tex_pkgs, 2) + self.check_missing_file(pdf_pkgs, noto_sans, DepType.PDF_MANDATORY) + self.check_rpm_missing(tex_pkgs, DepType.PDF_MANDATORY) self.check_missing(progs) @@ -701,7 +766,7 @@ class SphinxDependencyChecker: ] if self.pdf: - self.check_pacman_missing(archlinux_tex_pkgs, 2) + self.check_pacman_missing(archlinux_tex_pkgs, DepType.PDF_MANDATORY) self.check_missing_file( ["/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc"], @@ -739,7 +804,7 @@ class SphinxDependencyChecker: ], } for package, files in pdf_pkgs.items(): - self.check_missing_file(files, package, 2) + self.check_missing_file(files, package, DepType.PDF_MANDATORY) self.check_missing(progs) @@ -878,7 +943,7 @@ class SphinxDependencyChecker: # progs = {"sphinx-build": "sphinx"} if self.pdf: - self.check_missing_tex(2) + self.check_missing_tex() self.check_missing(progs) @@ -990,7 +1055,7 @@ class SphinxDependencyChecker: old_verbose = self.verbose_warn_install self.verbose_warn_install = 0 - self.add_package("python-sphinx", 0) + self.add_package("python-sphinx", DepType.PYTHON_MANDATORY) self.check_distros() @@ -1010,6 +1075,7 @@ class SphinxDependencyChecker: "Please upgrade it and re-run.\n") return + # Version is OK. Nothing to do. if self.cur_version != (0, 0, 0) and self.cur_version >= RECOMMENDED_VERSION: return @@ -1128,21 +1194,23 @@ class SphinxDependencyChecker: else: virtualenv_cmd = f"{self.python_cmd} -m venv" - self.check_python_module("ensurepip", 0) + self.check_python_module("ensurepip") # Check for needed programs/tools - self.check_perl_module("Pod::Usage", 0) - self.check_python_module("yaml", 0) - self.check_program("make", 0) - self.check_program("gcc", 0) - self.check_program("dot", 1) - self.check_program("convert", 1) + self.check_perl_module("Pod::Usage", DepType.SYSTEM_MANDATORY) + + self.check_program("make", DepType.SYSTEM_MANDATORY) + self.check_program("gcc", DepType.SYSTEM_MANDATORY) + + self.check_program("dot", DepType.SYSTEM_OPTIONAL) + self.check_program("convert", DepType.SYSTEM_OPTIONAL) + + self.check_python_module("yaml") if self.pdf: - # Extra PDF files - should use 2 for LaTeX is_optional - self.check_program("xelatex", 2) - self.check_program("rsvg-convert", 2) - self.check_program("latexmk", 2) + self.check_program("xelatex", DepType.PDF_MANDATORY) + self.check_program("rsvg-convert", DepType.PDF_MANDATORY) + self.check_program("latexmk", DepType.PDF_MANDATORY) # Do distro-specific checks and output distro-install commands self.check_distros() From 272f5e0390dd9b5f62b480eae482a67d2493630e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:42 +0200 Subject: [PATCH 00739/11391] scripts: sphinx-pre-install: better handle RHEL-based distros Better implement support for RHEL-based distros. While here, get rid of a Fedora 28 support which cause troubles with server distros. Also, get rid of yum, as RHEL8 already suppords dnf, and this is not the minimal version we may still support. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/4d1b27d3a381f011e150bb50176babba83af9e1a.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index 0963da21c27b..592223fa686f 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -536,10 +536,6 @@ class SphinxDependencyChecker: "yaml": "python3-pyyaml", } - fedora26_opt_pkgs = [ - "graphviz-gd", # Fedora 26: needed for PDF support - ] - fedora_tex_pkgs = [ "dejavu-sans-fonts", "dejavu-sans-mono-fonts", @@ -549,9 +545,8 @@ class SphinxDependencyChecker: "texlive-xecjk", ] - old = 0 + fedora = False rel = None - pkg_manager = "dnf" match = re.search(r"(release|Linux)\s+(\d+)", self.system_release) if match: @@ -559,12 +554,12 @@ class SphinxDependencyChecker: if not rel: print("Couldn't identify release number") - old = 1 self.pdf = False elif re.search("Fedora", self.system_release): # Fedora 38 and upper use this CJK font noto_sans_redhat = "google-noto-sans-cjk-fonts" + fedora = True else: # Almalinux, CentOS, RHEL, ... @@ -574,9 +569,6 @@ class SphinxDependencyChecker: progs["virtualenv"] = "python-virtualenv" if not rel or rel < 8: - old = 1 - self.pdf = False - print("ERROR: Distro not supported. Too old?") return @@ -607,11 +599,16 @@ class SphinxDependencyChecker: self.check_missing_file(pdf_pkgs, noto_sans_redhat, DepType.PDF_MANDATORY) - if not old: - self.check_rpm_missing(fedora26_opt_pkgs, DepType.PDF_MANDATORY) - self.check_rpm_missing(fedora_tex_pkgs, DepType.PDF_MANDATORY) + self.check_rpm_missing(fedora_tex_pkgs, DepType.PDF_MANDATORY) + + self.check_missing_tex(DepType.PDF_MANDATORY) + + # There's no texlive-ctex on RHEL 8 repositories. This will + # likely affect CJK pdf build only. + if not fedora and rel == 8: + if "texlive-ctex" in self.missing: + del self.missing["texlive-ctex"] - self.check_missing_tex() self.check_missing(progs) @@ -621,11 +618,7 @@ class SphinxDependencyChecker: if self.verbose_warn_install: print("You should run:") - if old: - # dnf is there since Fedora 18+ and RHEL 8 - pkg_manager = "yum" - - print(f"\n\tsudo {pkg_manager} install -y {self.install}") + print(f"\n\tsudo dnf install -y {self.install}") def give_opensuse_hints(self): progs = { From 2cab00fb178a31bca45adc1ff5f0994679d116a4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:43 +0200 Subject: [PATCH 00740/11391] scripts: sphinx-pre-install: move missing logic to a separate class Better manage dependencies by placing them on a distro-independent class. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/f4f5bf276e07dc494f5dc83c4c2d087be7f790e6.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 251 +++++++++++++++++++--------------- 1 file changed, 138 insertions(+), 113 deletions(-) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index 592223fa686f..47dce1fcddfb 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -32,7 +32,7 @@ RECOMMENDED_VERSION = parse_version("3.4.3") MIN_PYTHON_VERSION = parse_version("3.7") -class DepType: +class DepManager: # Internal types of dependencies. _SYS_TYPE = 0 @@ -53,11 +53,18 @@ class DepType: PYTHON_OPTIONAL = (_PHY_TYPE, False) PDF_OPTIONAL = (_PDF_TYPE, True) + def __init__(self, pdf): + self.missing = {} + self.run = {} + self.need = 0 + self.optional = 0 + self.pdf = pdf + @staticmethod def name(dtype): - if dtype[0] == DepType._SYS_TYPE: + if dtype[0] == DepManager._SYS_TYPE: msg = "build" - elif dtype[0] == DepType._PHY_TYPE: + elif dtype[0] == DepManager._PHY_TYPE: msg = "Python" else: msg = "PDF" @@ -73,11 +80,75 @@ class DepType: @staticmethod def is_pdf(dtype): - if (dtype[0] == DepType._PDF_TYPE): + if (dtype[0] == DepManager._PDF_TYPE): return True return False + def add_package(self, package, dtype): + is_optional = DepManager.is_optional(dtype) + self.missing[package] = dtype + if is_optional: + self.optional += 1 + else: + self.need += 1 + + def del_package(self, package): + if package in self.missing: + del self.missing[package] + + def clear_deps(self): + """ + Clear dependencies without changing needed/optional. + + This is an ackward way to have a separate section to recommend + a package after system main dependencies. + + TODO: rework the logic to prevent needing it + """ + + self.missing = {} + + def check_missing(self, progs): + self.run = {} + + for prog, dtype in sorted(self.missing.items()): + # At least on some LTS distros like CentOS 7, texlive doesn't + # provide all packages we need. When such distros are + # detected, we have to disable PDF output. + # + # So, we need to ignore the packages that distros would + # need for LaTeX to work + if DepManager.is_pdf(dtype) and not self.pdf: + self.optional -= 1 + continue + + if not dtype in self.run: + self.run[dtype] = [] + + self.run[dtype].append(progs.get(prog, prog)) + + install = [] + for dtype in self.run.keys(): + install += self.run[dtype] + + return " ".join(sorted(set(install))) + + def warn_install(self): + + output_msg = "" + + for dtype in sorted(self.run.keys()): + progs = " ".join(sorted(set(self.run[dtype]))) + + try: + name = DepManager.name(dtype) + output_msg += f'{name}:\t{progs}\n' + except KeyError: + raise KeyError(f"ERROR!!!: invalid dtype for {progs}: {dtype}") + + if output_msg: + print(f"\n{output_msg}\n") class SphinxDependencyChecker: # List of required texlive packages on Fedora and OpenSuse @@ -120,10 +191,8 @@ class SphinxDependencyChecker: self.virtualenv = args.virtualenv self.version_check = args.version_check - self.missing = {} + self.deps = DepManager(self.pdf) - self.need = 0 - self.optional = 0 self.need_symlink = 0 self.need_sphinx = 0 self.need_pip = 0 @@ -270,64 +339,18 @@ class SphinxDependencyChecker: # Methods to check if a feature exists # - def check_missing(self, progs): - run = {} - - for prog, dtype in sorted(self.missing.items()): - # At least on some LTS distros like CentOS 7, texlive doesn't - # provide all packages we need. When such distros are - # detected, we have to disable PDF output. - # - # So, we need to ignore the packages that distros would - # need for LaTeX to work - if DepType.is_pdf(dtype) and not self.pdf: - self.optional -= 1 - continue - - if not dtype in run: - run[dtype] = [] - - run[dtype].append(prog) - - output_msg = "" - - for dtype in sorted(run.keys()): - progs = " ".join(run[dtype]) - - if self.verbose_warn_install: - try: - name = DepType.name(dtype) - output_msg += f'{name}:\t{progs}\n' - except KeyError: - raise KeyError(f"ERROR!!!: invalid dtype for {progs}: {dtype}") - - self.install += " " + progs - - if output_msg: - print(f"\n{output_msg}\n") - - self.install = self.install.lstrip() - - def add_package(self, package, dtype): - is_optional = DepType.is_optional(dtype) - self.missing[package] = dtype - if is_optional: - self.optional += 1 - else: - self.need += 1 - def check_missing_file(self, files, package, dtype): for f in files: if os.path.exists(f): return - self.add_package(package, dtype) + self.deps.add_package(package, dtype) def check_program(self, prog, dtype): found = self.which(prog) if found: return found - self.add_package(prog, dtype) + self.deps.add_package(prog, dtype) return None @@ -340,52 +363,52 @@ class SphinxDependencyChecker: # add it as a mandatory package, as some parts of the doc builder # needs it. if not self.which("perl"): - self.add_package("perl", DepType.SYSTEM_MANDATORY) - self.add_package(prog, dtype) + self.deps.add_package("perl", DepManager.SYSTEM_MANDATORY) + self.deps.add_package(prog, dtype) return try: self.run(["perl", f"-M{prog}", "-e", "1"], check=True) except subprocess.CalledProcessError: - self.add_package(prog, dtype) + self.deps.add_package(prog, dtype) def check_python_module(self, module, is_optional=False): if is_optional: - dtype = DepType.PYTHON_OPTIONAL + dtype = DepManager.PYTHON_OPTIONAL else: - dtype = DepType.PYTHON_MANDATORY + dtype = DepManager.PYTHON_MANDATORY try: self.run([self.python_cmd, "-c", f"import {module}"], check=True) except subprocess.CalledProcessError: - self.add_package(module, dtype) + self.deps.add_package(module, dtype) def check_rpm_missing(self, pkgs, dtype): for prog in pkgs: try: self.run(["rpm", "-q", prog], check=True) except subprocess.CalledProcessError: - self.add_package(prog, dtype) + self.deps.add_package(prog, dtype) def check_pacman_missing(self, pkgs, dtype): for prog in pkgs: try: self.run(["pacman", "-Q", prog], check=True) except subprocess.CalledProcessError: - self.add_package(prog, dtype) + self.deps.add_package(prog, dtype) def check_missing_tex(self, is_optional=False): if is_optional: - dtype = DepType.PDF_OPTIONAL + dtype = DepManager.PDF_OPTIONAL else: - dtype = DepType.PDF_MANDATORY + dtype = DepManager.PDF_MANDATORY kpsewhich = self.which("kpsewhich") for prog, package in self.texlive.items(): # If kpsewhich is not there, just add it to deps if not kpsewhich: - self.add_package(package, dtype) + self.deps.add_package(package, dtype) continue # Check if the package is needed @@ -396,11 +419,11 @@ class SphinxDependencyChecker: # Didn't find. Add it if not result.stdout.strip(): - self.add_package(package, dtype) + self.deps.add_package(package, dtype) except subprocess.CalledProcessError: # kpsewhich returned an error. Add it, just in case - self.add_package(package, dtype) + self.deps.add_package(package, dtype) def get_sphinx_fname(self): if "SPHINXBUILD" in os.environ: @@ -478,6 +501,17 @@ class SphinxDependencyChecker: return f.read().strip() return "" + def check_missing(self, progs): + self.install += self.deps.check_missing(progs) + if self.verbose_warn_install: + self.deps.warn_install() + + if not self.deps.need and not self.deps.optional: + return False + + return True + + # # Distro-specific hints methods # @@ -511,13 +545,11 @@ class SphinxDependencyChecker: } for package, files in pdf_pkgs.items(): - self.check_missing_file(files, package, DepType.PDF_MANDATORY) + self.check_missing_file(files, package, DepManager.PDF_MANDATORY) - self.check_program("dvipng", DepType.PDF_MANDATORY) + self.check_program("dvipng", DepManager.PDF_MANDATORY) - self.check_missing(progs) - - if not self.need and not self.optional: + if self.check_missing(progs): return if self.verbose_warn_install: @@ -575,7 +607,7 @@ class SphinxDependencyChecker: # RHEL 8 uses Python 3.6, which is not compatible with # the build system anymore. Suggest Python 3.11 if rel == 8: - self.add_package("python39", DepType.SYSTEM_MANDATORY) + self.deps.add_package("python39", DepManager.SYSTEM_MANDATORY) self.recommend_python = True if self.first_hint: @@ -597,22 +629,18 @@ class SphinxDependencyChecker: "/usr/share/fonts/google-noto-sans-cjk-fonts/NotoSansCJK-Regular.ttc", ] - self.check_missing_file(pdf_pkgs, noto_sans_redhat, DepType.PDF_MANDATORY) + self.check_missing_file(pdf_pkgs, noto_sans_redhat, DepManager.PDF_MANDATORY) - self.check_rpm_missing(fedora_tex_pkgs, DepType.PDF_MANDATORY) + self.check_rpm_missing(fedora_tex_pkgs, DepManager.PDF_MANDATORY) - self.check_missing_tex(DepType.PDF_MANDATORY) + self.check_missing_tex(DepManager.PDF_MANDATORY) # There's no texlive-ctex on RHEL 8 repositories. This will # likely affect CJK pdf build only. if not fedora and rel == 8: - if "texlive-ctex" in self.missing: - del self.missing["texlive-ctex"] + self.deps.del_package("texlive-ctex") - - self.check_missing(progs) - - if not self.need and not self.optional: + if self.check_missing(progs): return if self.verbose_warn_install: @@ -659,7 +687,7 @@ class SphinxDependencyChecker: if rel == 15: if not self.which(self.python_cmd): self.recommend_python = True - self.add_package(self.python_cmd, DepType.SYSTEM_MANDATORY) + self.deps.add_package(self.python_cmd, DepManager.SYSTEM_MANDATORY) progs.update({ "python-sphinx": "python311-Sphinx", @@ -681,12 +709,11 @@ class SphinxDependencyChecker: # "Noto Sans CJK SC" on openSUSE if self.pdf: - self.check_rpm_missing(suse_tex_pkgs, DepType.PDF_MANDATORY) + self.check_rpm_missing(suse_tex_pkgs, DepManager.PDF_MANDATORY) if self.pdf: self.check_missing_tex() - self.check_missing(progs) - if not self.need and not self.optional: + if self.check_missing(progs): return if self.verbose_warn_install: @@ -730,13 +757,12 @@ class SphinxDependencyChecker: "/usr/share/fonts/TTF/NotoSans-Regular.ttf", ] - self.check_missing_file(pdf_pkgs, noto_sans, DepType.PDF_MANDATORY) - self.check_rpm_missing(tex_pkgs, DepType.PDF_MANDATORY) + self.check_missing_file(pdf_pkgs, noto_sans, DepManager.PDF_MANDATORY) + self.check_rpm_missing(tex_pkgs, DepManager.PDF_MANDATORY) - self.check_missing(progs) - - if not self.need and not self.optional: + if self.check_missing(progs): return + if self.verbose_warn_install: print("You should run:") print(f"\n\tsudo {packager_cmd} {self.install}") @@ -759,7 +785,7 @@ class SphinxDependencyChecker: ] if self.pdf: - self.check_pacman_missing(archlinux_tex_pkgs, DepType.PDF_MANDATORY) + self.check_pacman_missing(archlinux_tex_pkgs, DepManager.PDF_MANDATORY) self.check_missing_file( ["/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc"], @@ -767,10 +793,9 @@ class SphinxDependencyChecker: 2, ) - self.check_missing(progs) - - if not self.need and not self.optional: + if self.check_missing(progs): return + if self.verbose_warn_install: print("You should run:") print(f"\n\tsudo pacman -S {self.install}") @@ -797,11 +822,9 @@ class SphinxDependencyChecker: ], } for package, files in pdf_pkgs.items(): - self.check_missing_file(files, package, DepType.PDF_MANDATORY) + self.check_missing_file(files, package, DepManager.PDF_MANDATORY) - self.check_missing(progs) - - if not self.need and not self.optional: + if self.check_missing(progs): return if self.verbose_warn_install: @@ -1039,16 +1062,18 @@ class SphinxDependencyChecker: print("\n2) As a package with:") - old_need = self.need - old_optional = self.optional - self.missing = {} + old_need = self.deps.need + old_optional = self.deps.optional + self.pdf = False self.optional = 0 self.install = "" old_verbose = self.verbose_warn_install self.verbose_warn_install = 0 - self.add_package("python-sphinx", DepType.PYTHON_MANDATORY) + self.deps.clear_deps() + + self.deps.add_package("python-sphinx", DepManager.PYTHON_MANDATORY) self.check_distros() @@ -1111,7 +1136,7 @@ class SphinxDependencyChecker: print("\n") else: if self.need_sphinx: - self.need += 1 + self.deps.need += 1 # Suggest newer versions if current ones are too old if self.latest_avail_ver and self.latest_avail_ver >= self.min_version: @@ -1190,20 +1215,20 @@ class SphinxDependencyChecker: self.check_python_module("ensurepip") # Check for needed programs/tools - self.check_perl_module("Pod::Usage", DepType.SYSTEM_MANDATORY) + self.check_perl_module("Pod::Usage", DepManager.SYSTEM_MANDATORY) - self.check_program("make", DepType.SYSTEM_MANDATORY) - self.check_program("gcc", DepType.SYSTEM_MANDATORY) + self.check_program("make", DepManager.SYSTEM_MANDATORY) + self.check_program("gcc", DepManager.SYSTEM_MANDATORY) - self.check_program("dot", DepType.SYSTEM_OPTIONAL) - self.check_program("convert", DepType.SYSTEM_OPTIONAL) + self.check_program("dot", DepManager.SYSTEM_OPTIONAL) + self.check_program("convert", DepManager.SYSTEM_OPTIONAL) self.check_python_module("yaml") if self.pdf: - self.check_program("xelatex", DepType.PDF_MANDATORY) - self.check_program("rsvg-convert", DepType.PDF_MANDATORY) - self.check_program("latexmk", DepType.PDF_MANDATORY) + self.check_program("xelatex", DepManager.PDF_MANDATORY) + self.check_program("rsvg-convert", DepManager.PDF_MANDATORY) + self.check_program("latexmk", DepManager.PDF_MANDATORY) # Do distro-specific checks and output distro-install commands self.check_distros() From 1e9ba3b6d4cef8b1b87d6226ab7026c9745cc1d7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:44 +0200 Subject: [PATCH 00741/11391] scripts: sphinx-pre-install: move ancillary checkers to a separate class The code there are just a bunch of static functions that are used by the main class. group them altogether to better organize the code. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/e2671eb14fae7a8510f5305ac44ad8063e237a5f.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 160 +++++++++++++++++----------------- 1 file changed, 81 insertions(+), 79 deletions(-) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index 47dce1fcddfb..b00e50028f4d 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -150,85 +150,11 @@ class DepManager: if output_msg: print(f"\n{output_msg}\n") -class SphinxDependencyChecker: - # List of required texlive packages on Fedora and OpenSuse - texlive = { - "amsfonts.sty": "texlive-amsfonts", - "amsmath.sty": "texlive-amsmath", - "amssymb.sty": "texlive-amsfonts", - "amsthm.sty": "texlive-amscls", - "anyfontsize.sty": "texlive-anyfontsize", - "atbegshi.sty": "texlive-oberdiek", - "bm.sty": "texlive-tools", - "capt-of.sty": "texlive-capt-of", - "cmap.sty": "texlive-cmap", - "ctexhook.sty": "texlive-ctex", - "ecrm1000.tfm": "texlive-ec", - "eqparbox.sty": "texlive-eqparbox", - "eu1enc.def": "texlive-euenc", - "fancybox.sty": "texlive-fancybox", - "fancyvrb.sty": "texlive-fancyvrb", - "float.sty": "texlive-float", - "fncychap.sty": "texlive-fncychap", - "footnote.sty": "texlive-mdwtools", - "framed.sty": "texlive-framed", - "luatex85.sty": "texlive-luatex85", - "multirow.sty": "texlive-multirow", - "needspace.sty": "texlive-needspace", - "palatino.sty": "texlive-psnfss", - "parskip.sty": "texlive-parskip", - "polyglossia.sty": "texlive-polyglossia", - "tabulary.sty": "texlive-tabulary", - "threeparttable.sty": "texlive-threeparttable", - "titlesec.sty": "texlive-titlesec", - "ucs.sty": "texlive-ucs", - "upquote.sty": "texlive-upquote", - "wrapfig.sty": "texlive-wrapfig", - } - - def __init__(self, args): - self.pdf = args.pdf - self.virtualenv = args.virtualenv - self.version_check = args.version_check - - self.deps = DepManager(self.pdf) - - self.need_symlink = 0 - self.need_sphinx = 0 - self.need_pip = 0 - self.rec_sphinx_upgrade = 0 - self.verbose_warn_install = 1 - - self.system_release = "" - self.install = "" - self.virtenv_dir = "" - self.python_cmd = "" - self.activate_cmd = "" - - # Some distros may not have a Sphinx shipped package compatible with - # our minimal requirements - self.package_supported = True - - # Recommend a new python version - self.recommend_python = None - - # Certain hints are meant to be shown only once - self.first_hint = True - - self.min_version = (0, 0, 0) - self.cur_version = (0, 0, 0) - self.latest_avail_ver = (0, 0, 0) - self.venv_ver = (0, 0, 0) - - prefix = os.environ.get("srctree", ".") + "/" - - self.conf = prefix + "Documentation/conf.py" - self.requirement_file = prefix + "Documentation/sphinx/requirements.txt" - self.virtenv_prefix = ["sphinx_", "Sphinx_" ] - - # - # Ancillary methods that don't depend on self - # +class AncillaryCheckers: + """ + Ancillary methods that checks for missing dependencies for different + types of types, like binaries, python modules, rpm deps, etc. + """ @staticmethod def which(prog): @@ -335,6 +261,82 @@ class SphinxDependencyChecker: return subprocess.run(*args, **kwargs) +class SphinxDependencyChecker(AncillaryCheckers): + # List of required texlive packages on Fedora and OpenSuse + texlive = { + "amsfonts.sty": "texlive-amsfonts", + "amsmath.sty": "texlive-amsmath", + "amssymb.sty": "texlive-amsfonts", + "amsthm.sty": "texlive-amscls", + "anyfontsize.sty": "texlive-anyfontsize", + "atbegshi.sty": "texlive-oberdiek", + "bm.sty": "texlive-tools", + "capt-of.sty": "texlive-capt-of", + "cmap.sty": "texlive-cmap", + "ctexhook.sty": "texlive-ctex", + "ecrm1000.tfm": "texlive-ec", + "eqparbox.sty": "texlive-eqparbox", + "eu1enc.def": "texlive-euenc", + "fancybox.sty": "texlive-fancybox", + "fancyvrb.sty": "texlive-fancyvrb", + "float.sty": "texlive-float", + "fncychap.sty": "texlive-fncychap", + "footnote.sty": "texlive-mdwtools", + "framed.sty": "texlive-framed", + "luatex85.sty": "texlive-luatex85", + "multirow.sty": "texlive-multirow", + "needspace.sty": "texlive-needspace", + "palatino.sty": "texlive-psnfss", + "parskip.sty": "texlive-parskip", + "polyglossia.sty": "texlive-polyglossia", + "tabulary.sty": "texlive-tabulary", + "threeparttable.sty": "texlive-threeparttable", + "titlesec.sty": "texlive-titlesec", + "ucs.sty": "texlive-ucs", + "upquote.sty": "texlive-upquote", + "wrapfig.sty": "texlive-wrapfig", + } + + def __init__(self, args): + self.pdf = args.pdf + self.virtualenv = args.virtualenv + self.version_check = args.version_check + + self.deps = DepManager(self.pdf) + + self.need_symlink = 0 + self.need_sphinx = 0 + self.need_pip = 0 + self.rec_sphinx_upgrade = 0 + self.verbose_warn_install = 1 + + self.system_release = "" + self.install = "" + self.virtenv_dir = "" + self.python_cmd = "" + self.activate_cmd = "" + + # Some distros may not have a Sphinx shipped package compatible with + # our minimal requirements + self.package_supported = True + + # Recommend a new python version + self.recommend_python = None + + # Certain hints are meant to be shown only once + self.first_hint = True + + self.min_version = (0, 0, 0) + self.cur_version = (0, 0, 0) + self.latest_avail_ver = (0, 0, 0) + self.venv_ver = (0, 0, 0) + + prefix = os.environ.get("srctree", ".") + "/" + + self.conf = prefix + "Documentation/conf.py" + self.requirement_file = prefix + "Documentation/sphinx/requirements.txt" + self.virtenv_prefix = ["sphinx_", "Sphinx_" ] + # # Methods to check if a feature exists # From 9bb5f0dc18d037635f4c5075747de1e47493b538 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:45 +0200 Subject: [PATCH 00742/11391] scripts: sphinx-pre-install: add more generic checkers on a class Better organize the code by moving the more generic methods to MissingCheckers. Such class contain only binary and package dependent missing checkers, but no distro-specific data or code. All distro-specific data/code remains at SphinxDependencyChecker class. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/11a252fe816bd7c85583d26ade0666eb2b481bf0.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 142 ++++++++++++++++++---------------- 1 file changed, 76 insertions(+), 66 deletions(-) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index b00e50028f4d..9127487bd4d7 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -150,7 +150,7 @@ class DepManager: if output_msg: print(f"\n{output_msg}\n") -class AncillaryCheckers: +class AncillaryMethods: """ Ancillary methods that checks for missing dependencies for different types of types, like binaries, python modules, rpm deps, etc. @@ -261,81 +261,24 @@ class AncillaryCheckers: return subprocess.run(*args, **kwargs) -class SphinxDependencyChecker(AncillaryCheckers): - # List of required texlive packages on Fedora and OpenSuse - texlive = { - "amsfonts.sty": "texlive-amsfonts", - "amsmath.sty": "texlive-amsmath", - "amssymb.sty": "texlive-amsfonts", - "amsthm.sty": "texlive-amscls", - "anyfontsize.sty": "texlive-anyfontsize", - "atbegshi.sty": "texlive-oberdiek", - "bm.sty": "texlive-tools", - "capt-of.sty": "texlive-capt-of", - "cmap.sty": "texlive-cmap", - "ctexhook.sty": "texlive-ctex", - "ecrm1000.tfm": "texlive-ec", - "eqparbox.sty": "texlive-eqparbox", - "eu1enc.def": "texlive-euenc", - "fancybox.sty": "texlive-fancybox", - "fancyvrb.sty": "texlive-fancyvrb", - "float.sty": "texlive-float", - "fncychap.sty": "texlive-fncychap", - "footnote.sty": "texlive-mdwtools", - "framed.sty": "texlive-framed", - "luatex85.sty": "texlive-luatex85", - "multirow.sty": "texlive-multirow", - "needspace.sty": "texlive-needspace", - "palatino.sty": "texlive-psnfss", - "parskip.sty": "texlive-parskip", - "polyglossia.sty": "texlive-polyglossia", - "tabulary.sty": "texlive-tabulary", - "threeparttable.sty": "texlive-threeparttable", - "titlesec.sty": "texlive-titlesec", - "ucs.sty": "texlive-ucs", - "upquote.sty": "texlive-upquote", - "wrapfig.sty": "texlive-wrapfig", - } +class MissingCheckers(AncillaryMethods): - def __init__(self, args): + def __init__(self, args, texlive): self.pdf = args.pdf self.virtualenv = args.virtualenv self.version_check = args.version_check + self.texlive = texlive self.deps = DepManager(self.pdf) self.need_symlink = 0 self.need_sphinx = 0 - self.need_pip = 0 - self.rec_sphinx_upgrade = 0 + self.verbose_warn_install = 1 - self.system_release = "" - self.install = "" self.virtenv_dir = "" - self.python_cmd = "" - self.activate_cmd = "" - # Some distros may not have a Sphinx shipped package compatible with - # our minimal requirements - self.package_supported = True - - # Recommend a new python version - self.recommend_python = None - - # Certain hints are meant to be shown only once - self.first_hint = True - - self.min_version = (0, 0, 0) - self.cur_version = (0, 0, 0) - self.latest_avail_ver = (0, 0, 0) - self.venv_ver = (0, 0, 0) - - prefix = os.environ.get("srctree", ".") + "/" - - self.conf = prefix + "Documentation/conf.py" - self.requirement_file = prefix + "Documentation/sphinx/requirements.txt" - self.virtenv_prefix = ["sphinx_", "Sphinx_" ] + self.install = "" # # Methods to check if a feature exists @@ -460,9 +403,9 @@ class SphinxDependencyChecker(AncillaryCheckers): if match: return parse_version(match.group(1)) - def check_sphinx(self): + def check_sphinx(self, conf): try: - with open(self.conf, "r", encoding="utf-8") as f: + with open(conf, "r", encoding="utf-8") as f: for line in f: match = re.match(r"^\s*needs_sphinx\s*=\s*[\'\"]([\d\.]+)[\'\"]", line) if match: @@ -513,6 +456,73 @@ class SphinxDependencyChecker(AncillaryCheckers): return True +class SphinxDependencyChecker(MissingCheckers): + + def __init__(self, args): + # List of required texlive packages on Fedora and OpenSuse + texlive = { + "amsfonts.sty": "texlive-amsfonts", + "amsmath.sty": "texlive-amsmath", + "amssymb.sty": "texlive-amsfonts", + "amsthm.sty": "texlive-amscls", + "anyfontsize.sty": "texlive-anyfontsize", + "atbegshi.sty": "texlive-oberdiek", + "bm.sty": "texlive-tools", + "capt-of.sty": "texlive-capt-of", + "cmap.sty": "texlive-cmap", + "ctexhook.sty": "texlive-ctex", + "ecrm1000.tfm": "texlive-ec", + "eqparbox.sty": "texlive-eqparbox", + "eu1enc.def": "texlive-euenc", + "fancybox.sty": "texlive-fancybox", + "fancyvrb.sty": "texlive-fancyvrb", + "float.sty": "texlive-float", + "fncychap.sty": "texlive-fncychap", + "footnote.sty": "texlive-mdwtools", + "framed.sty": "texlive-framed", + "luatex85.sty": "texlive-luatex85", + "multirow.sty": "texlive-multirow", + "needspace.sty": "texlive-needspace", + "palatino.sty": "texlive-psnfss", + "parskip.sty": "texlive-parskip", + "polyglossia.sty": "texlive-polyglossia", + "tabulary.sty": "texlive-tabulary", + "threeparttable.sty": "texlive-threeparttable", + "titlesec.sty": "texlive-titlesec", + "ucs.sty": "texlive-ucs", + "upquote.sty": "texlive-upquote", + "wrapfig.sty": "texlive-wrapfig", + } + + super().__init__(args, texlive) + + self.need_pip = 0 + self.rec_sphinx_upgrade = 0 + + self.system_release = "" + self.python_cmd = "" + self.activate_cmd = "" + + # Some distros may not have a Sphinx shipped package compatible with + # our minimal requirements + self.package_supported = True + + # Recommend a new python version + self.recommend_python = None + + # Certain hints are meant to be shown only once + self.first_hint = True + + self.min_version = (0, 0, 0) + self.cur_version = (0, 0, 0) + self.latest_avail_ver = (0, 0, 0) + self.venv_ver = (0, 0, 0) + + prefix = os.environ.get("srctree", ".") + "/" + + self.conf = prefix + "Documentation/conf.py" + self.requirement_file = prefix + "Documentation/sphinx/requirements.txt" + self.virtenv_prefix = ["sphinx_", "Sphinx_" ] # # Distro-specific hints methods @@ -1187,7 +1197,7 @@ class SphinxDependencyChecker(AncillaryCheckers): self.python_cmd = sys.executable # Check if Sphinx is already accessible from current environment - self.check_sphinx() + self.check_sphinx(self.conf) if self.system_release: print(f"Detected OS: {self.system_release}.") From fb22e438b23eabd828a0ca1076be5ecf9b0262db Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:46 +0200 Subject: [PATCH 00743/11391] scripts: sphinx-pre-install: move get_system_release() The code at get_system_release() is actually a helper function, independent from the actual Sphinx verification checker. Move it to MissingCheckers class, where other checkers are present. With that, the entire distro-specific handler logic, with all its complexity is confined at SphinxDependencyChecker class. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/4b42a85bbb6575bb34a58cf66019038c4afa1d5b.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 115 +++++++++++++++++----------------- 1 file changed, 59 insertions(+), 56 deletions(-) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index 9127487bd4d7..593982f350b3 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -456,6 +456,64 @@ class MissingCheckers(AncillaryMethods): return True + def get_system_release(self): + """ + Determine the system type. There's no unique way that would work + with all distros with a minimal package install. So, several + methods are used here. + + By default, it will use lsb_release function. If not available, it will + fail back to reading the known different places where the distro name + is stored. + + Several modern distros now have /etc/os-release, which usually have + a decent coverage. + """ + + system_release = "" + + if self.which("lsb_release"): + result = self.run(["lsb_release", "-d"], capture_output=True, text=True) + system_release = result.stdout.replace("Description:", "").strip() + + release_files = [ + "/etc/system-release", + "/etc/redhat-release", + "/etc/lsb-release", + "/etc/gentoo-release", + ] + + if not system_release: + for f in release_files: + system_release = self.catcheck(f) + if system_release: + break + + # This seems more common than LSB these days + if not system_release: + os_var = {} + try: + with open("/etc/os-release", "r", encoding="utf-8") as f: + for line in f: + match = re.match(r"^([\w\d\_]+)=\"?([^\"]*)\"?\n", line) + if match: + os_var[match.group(1)] = match.group(2) + + system_release = os_var.get("NAME", "") + if "VERSION_ID" in os_var: + system_release += " " + os_var["VERSION_ID"] + elif "VERSION" in os_var: + system_release += " " + os_var["VERSION"] + except IOError: + pass + + if not system_release: + system_release = self.catcheck("/etc/issue") + + system_release = system_release.strip() + + return system_release + class SphinxDependencyChecker(MissingCheckers): def __init__(self, args): @@ -499,7 +557,7 @@ class SphinxDependencyChecker(MissingCheckers): self.need_pip = 0 self.rec_sphinx_upgrade = 0 - self.system_release = "" + self.system_release = self.get_system_release() self.python_cmd = "" self.activate_cmd = "" @@ -1193,7 +1251,6 @@ class SphinxDependencyChecker(MissingCheckers): "\thttps://github.com/sphinx-doc/sphinx/pull/8313") def check_needs(self): - self.get_system_release() self.python_cmd = sys.executable # Check if Sphinx is already accessible from current environment @@ -1270,60 +1327,6 @@ class SphinxDependencyChecker(MissingCheckers): print("Needed package dependencies are met.") - def get_system_release(self): - """ - Determine the system type. There's no unique way that would work - with all distros with a minimal package install. So, several - methods are used here. - - By default, it will use lsb_release function. If not available, it will - fail back to reading the known different places where the distro name - is stored. - - Several modern distros now have /etc/os-release, which usually have - a decent coverage. - """ - - if self.which("lsb_release"): - result = self.run(["lsb_release", "-d"], capture_output=True, text=True) - self.system_release = result.stdout.replace("Description:", "").strip() - - release_files = [ - "/etc/system-release", - "/etc/redhat-release", - "/etc/lsb-release", - "/etc/gentoo-release", - ] - - if not self.system_release: - for f in release_files: - self.system_release = self.catcheck(f) - if self.system_release: - break - - # This seems more common than LSB these days - if not self.system_release: - os_var = {} - try: - with open("/etc/os-release", "r", encoding="utf-8") as f: - for line in f: - match = re.match(r"^([\w\d\_]+)=\"?([^\"]*)\"?\n", line) - if match: - os_var[match.group(1)] = match.group(2) - - self.system_release = os_var.get("NAME", "") - if "VERSION_ID" in os_var: - self.system_release += " " + os_var["VERSION_ID"] - elif "VERSION" in os_var: - self.system_release += " " + os_var["VERSION"] - except IOError: - pass - - if not self.system_release: - self.system_release = self.catcheck("/etc/issue") - - self.system_release = self.system_release.strip() - DESCRIPTION = """ Process some flags related to Sphinx installation and documentation build. """ From f477c6d71d3947ab8f2e9e7d5fd8448f7a26c1ab Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:47 +0200 Subject: [PATCH 00744/11391] scripts: sphinx-pre-install: add documentation for the ancillary classes. While here, rename a parameter to have its usage better documented. No functional changes. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/7421112b14edf5c21cc4cf0f2ee320fcaf874b40.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 162 +++++++++++++++++++++++++++++----- 1 file changed, 140 insertions(+), 22 deletions(-) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index 593982f350b3..1dc3f19804ab 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -33,35 +33,62 @@ MIN_PYTHON_VERSION = parse_version("3.7") class DepManager: + """ + Manage package dependencies. There are three types of dependencies: - # Internal types of dependencies. + - System: dependencies required for docs build; + - Python: python dependencies for a native distro Sphinx install; + - PDF: dependencies needed by PDF builds. + + Each dependency can be mandatory or optional. Not installing an optional + dependency won't break the build, but will cause degradation at the + docs output. + """ + + # Internal types of dependencies. Don't use them outside DepManager class. _SYS_TYPE = 0 _PHY_TYPE = 1 _PDF_TYPE = 2 - # Let's define keys as a tuple with the type and mandatory/optional. - # This way, checking for optional or type is easy. + # Dependencies visible outside the class. + # The keys are tuple with: (type, is_mandatory flag). + # + # Currently we're not using all optional dep types. Yet, we'll keep all + # possible combinations here. They're not many, and that makes easier + # if later needed and for the name() method below SYSTEM_MANDATORY = (_SYS_TYPE, True) PYTHON_MANDATORY = (_PHY_TYPE, True) PDF_MANDATORY = (_PDF_TYPE, True) - # Currently we're not using all optional types, but let's keep all - # combinations here, as we may end needing them in the future. Also, - # it allows a name() function that handles all possibilities. SYSTEM_OPTIONAL = (_SYS_TYPE, False) PYTHON_OPTIONAL = (_PHY_TYPE, False) PDF_OPTIONAL = (_PDF_TYPE, True) def __init__(self, pdf): + """ + Initialize internal vars: + + - missing: missing dependencies list, containing a distro-independent + name for a missing dependency and its type. + - missing_pkg: ancillary dict containing missing dependencies in + distro namespace, organized by type. + - need: total number of needed dependencies. Never cleaned. + - optional: total number of optional dependencies. Never cleaned. + - pdf: PDF support is enabled? + """ self.missing = {} - self.run = {} + self.missing_pkg = {} self.need = 0 self.optional = 0 self.pdf = pdf @staticmethod def name(dtype): + """ + Ancillary routine to output a warn/error message reporting + missing dependencies. + """ if dtype[0] == DepManager._SYS_TYPE: msg = "build" elif dtype[0] == DepManager._PHY_TYPE: @@ -76,16 +103,22 @@ class DepManager: @staticmethod def is_optional(dtype): + """Ancillary routine to report if a dependency is optional""" return not dtype[1] @staticmethod def is_pdf(dtype): + """Ancillary routine to report if a dependency is for PDF generation""" if (dtype[0] == DepManager._PDF_TYPE): return True return False def add_package(self, package, dtype): + """ + Add a package at the self.missing() dictionary. + Doesn't update missing_pkg. + """ is_optional = DepManager.is_optional(dtype) self.missing[package] = dtype if is_optional: @@ -94,6 +127,10 @@ class DepManager: self.need += 1 def del_package(self, package): + """ + Remove a package at the self.missing() dictionary. + Doesn't update missing_pkg. + """ if package in self.missing: del self.missing[package] @@ -104,13 +141,22 @@ class DepManager: This is an ackward way to have a separate section to recommend a package after system main dependencies. - TODO: rework the logic to prevent needing it + TODO: rework the logic to prevent needing it. """ self.missing = {} + self.missing_pkg = {} def check_missing(self, progs): - self.run = {} + """ + Update self.missing_pkg, using progs dict to convert from the + agnostic package name to distro-specific one. + + Returns an string with the packages to be installed, sorted and + with eventual duplicates removed. + """ + + self.missing_pkg = {} for prog, dtype in sorted(self.missing.items()): # At least on some LTS distros like CentOS 7, texlive doesn't @@ -123,23 +169,26 @@ class DepManager: self.optional -= 1 continue - if not dtype in self.run: - self.run[dtype] = [] + if not dtype in self.missing_pkg: + self.missing_pkg[dtype] = [] - self.run[dtype].append(progs.get(prog, prog)) + self.missing_pkg[dtype].append(progs.get(prog, prog)) install = [] - for dtype in self.run.keys(): - install += self.run[dtype] + for dtype in self.missing_pkg.keys(): + install += self.missing_pkg[dtype] return " ".join(sorted(set(install))) def warn_install(self): + """ + Emit warnings/errors related to missing packages. + """ output_msg = "" - for dtype in sorted(self.run.keys()): - progs = " ".join(sorted(set(self.run[dtype]))) + for dtype in sorted(self.missing_pkg.keys()): + progs = " ".join(sorted(set(self.missing_pkg[dtype]))) try: name = DepManager.name(dtype) @@ -158,6 +207,11 @@ class AncillaryMethods: @staticmethod def which(prog): + """ + Our own implementation of which(). We could instead use + shutil.which(), but this function is simple enough. + Probably faster to use this implementation than to import shutil. + """ for path in os.environ.get("PATH", "").split(":"): full_path = os.path.join(path, prog) if os.access(full_path, os.X_OK): @@ -167,6 +221,10 @@ class AncillaryMethods: @staticmethod def get_python_version(cmd): + """ + Get python version from a Python binary. As we need to detect if + are out there newer python binaries, we can't rely on sys.release here. + """ result = SphinxDependencyChecker.run([cmd, "--version"], capture_output=True, text=True) @@ -181,7 +239,13 @@ class AncillaryMethods: @staticmethod def find_python(): + """ + Detect if are out there any python 3.xy version newer than the + current one. + Note: this routine is limited to up to 2 digits for python3. We + may need to update it one day, hopefully on a distant future. + """ patterns = [ "python3.[0-9]", "python3.[0-9][0-9]", @@ -200,7 +264,10 @@ class AncillaryMethods: @staticmethod def check_python(): - + """ + Check if the current python binary satisfies our minimal requirement + for Sphinx build. If not, re-run with a newer version if found. + """ cur_ver = sys.version_info[:3] if cur_ver >= MIN_PYTHON_VERSION: ver = ver_str(cur_ver) @@ -240,7 +307,10 @@ class AncillaryMethods: @staticmethod def run(*args, **kwargs): - """Excecute a command, hiding its output by default""" + """ + Excecute a command, hiding its output by default. + Preserve comatibility with older Python versions. + """ capture_output = kwargs.pop('capture_output', False) @@ -262,8 +332,15 @@ class AncillaryMethods: return subprocess.run(*args, **kwargs) class MissingCheckers(AncillaryMethods): + """ + Contains some ancillary checkers for different types of binaries and + package managers. + """ def __init__(self, args, texlive): + """ + Initialize its internal variables + """ self.pdf = args.pdf self.virtualenv = args.virtualenv self.version_check = args.version_check @@ -280,17 +357,20 @@ class MissingCheckers(AncillaryMethods): self.install = "" - # - # Methods to check if a feature exists - # - def check_missing_file(self, files, package, dtype): + """ + Does the file exists? If not, add it to missing dependencies. + """ for f in files: if os.path.exists(f): return self.deps.add_package(package, dtype) def check_program(self, prog, dtype): + """ + Does the program exists and it is at the PATH? + If not, add it to missing dependencies. + """ found = self.which(prog) if found: return found @@ -300,6 +380,18 @@ class MissingCheckers(AncillaryMethods): return None def check_perl_module(self, prog, dtype): + """ + Does perl have a dependency? Is it available? + If not, add it to missing dependencies. + + Right now, we still need Perl for doc build, as it is required + by some tools called at docs or kernel build time, like: + + scripts/documentation-file-ref-check + + Also, checkpatch is on Perl. + """ + # While testing with lxc download template, one of the # distros (Oracle) didn't have perl - nor even an option to install # before installing oraclelinux-release-el9 package. @@ -318,6 +410,10 @@ class MissingCheckers(AncillaryMethods): self.deps.add_package(prog, dtype) def check_python_module(self, module, is_optional=False): + """ + Does a python module exists outside venv? If not, add it to missing + dependencies. + """ if is_optional: dtype = DepManager.PYTHON_OPTIONAL else: @@ -329,6 +425,9 @@ class MissingCheckers(AncillaryMethods): self.deps.add_package(module, dtype) def check_rpm_missing(self, pkgs, dtype): + """ + Does a rpm package exists? If not, add it to missing dependencies. + """ for prog in pkgs: try: self.run(["rpm", "-q", prog], check=True) @@ -336,6 +435,9 @@ class MissingCheckers(AncillaryMethods): self.deps.add_package(prog, dtype) def check_pacman_missing(self, pkgs, dtype): + """ + Does a pacman package exists? If not, add it to missing dependencies. + """ for prog in pkgs: try: self.run(["pacman", "-Q", prog], check=True) @@ -343,6 +445,9 @@ class MissingCheckers(AncillaryMethods): self.deps.add_package(prog, dtype) def check_missing_tex(self, is_optional=False): + """ + Does a LaTeX package exists? If not, add it to missing dependencies. + """ if is_optional: dtype = DepManager.PDF_OPTIONAL else: @@ -371,6 +476,9 @@ class MissingCheckers(AncillaryMethods): self.deps.add_package(package, dtype) def get_sphinx_fname(self): + """ + Gets the binary filename for sphinx-build. + """ if "SPHINXBUILD" in os.environ: return os.environ["SPHINXBUILD"] @@ -386,6 +494,9 @@ class MissingCheckers(AncillaryMethods): return "" def get_sphinx_version(self, cmd): + """ + Gets sphinx-build version. + """ try: result = self.run([cmd, "--version"], stdout=subprocess.PIPE, @@ -404,6 +515,9 @@ class MissingCheckers(AncillaryMethods): return parse_version(match.group(1)) def check_sphinx(self, conf): + """ + Checks Sphinx minimal requirements + """ try: with open(conf, "r", encoding="utf-8") as f: for line in f: @@ -441,6 +555,10 @@ class MissingCheckers(AncillaryMethods): sys.exit(0) def catcheck(self, filename): + """ + Reads a file if it exists, returning as string. + If not found, returns an empty string. + """ if os.path.exists(filename): with open(filename, "r", encoding="utf-8") as f: return f.read().strip() From 6d5f4f3da1a82786650d38067bb4c5e4ed84dc61 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:48 +0200 Subject: [PATCH 00745/11391] scripts: sphinx-pre-install: add docstring documentation This program is somewhat complex. Add some docstring documentation, explaining what each function and class is supposed to do. Most of the focus here were to describe the ancillary functions used to detect dependency needs. The main SphinxDependencyChecker still requires a lot of care, and probably need to be reorganized to clearly split the 4 types of output it produces: - Need to upgrade Python binary; - System install needs; - Virtual env install needs; - Python install needs via system packages, to run Sphinx natively. Yet, for now, I'm happy of having it a lot better documented than its Perl version. - While here, rename a parameter to have its usage better documented. No functional changes. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/0cadab2cab3f78ae6d9f378e92a45125fbc5188f.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 110 +++++++++++++++++++++++++++++++--- 1 file changed, 102 insertions(+), 8 deletions(-) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index 1dc3f19804ab..1c96f6692e9a 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -9,6 +9,22 @@ # Don't add changes not compatible with it, it is meant to report # incompatible python versions. +""" +Dependency checker for Sphinx documentation Kernel build. + +This module provides tools to check for all required dependencies needed to +build documentation using Sphinx, including system packages, Python modules +and LaTeX packages for PDF generation. + +It detect packages for a subset of Linux distributions used by Kernel +maintainers, showing hints and missing dependencies. + +The main class SphinxDependencyChecker handles the dependency checking logic +and provides recommendations for installing missing packages. It supports both +system package installations and Python virtual environments. By default, +system pacage install is recommended. +""" + import argparse import os import re @@ -75,7 +91,7 @@ class DepManager: distro namespace, organized by type. - need: total number of needed dependencies. Never cleaned. - optional: total number of optional dependencies. Never cleaned. - - pdf: PDF support is enabled? + - pdf: Is PDF support enabled? """ self.missing = {} self.missing_pkg = {} @@ -565,6 +581,13 @@ class MissingCheckers(AncillaryMethods): return "" def check_missing(self, progs): + """ + Check for missing dependencies using the provided program mapping. + + The actual distro-specific programs are mapped via progs argument. + + Returns True if there are missing dependencies, False otherwise. + """ self.install += self.deps.check_missing(progs) if self.verbose_warn_install: self.deps.warn_install() @@ -633,8 +656,18 @@ class MissingCheckers(AncillaryMethods): return system_release class SphinxDependencyChecker(MissingCheckers): + """ + Main class for checking Sphinx documentation build dependencies. + - Check for missing system packages; + - Check for missing Python modules; + - Check for missing LaTeX packages needed by PDF generation; + - Propose Sphinx install via Python Virtual environment; + - Propose Sphinx install via distro-specific package install. + """ def __init__(self, args): + """Initialize checker variables""" + # List of required texlive packages on Fedora and OpenSuse texlive = { "amsfonts.sty": "texlive-amsfonts", @@ -705,6 +738,9 @@ class SphinxDependencyChecker(MissingCheckers): # def give_debian_hints(self): + """ + Provide package installation hints for Debian-based distros. + """ progs = { "Pod::Usage": "perl-modules", "convert": "imagemagick", @@ -745,6 +781,10 @@ class SphinxDependencyChecker(MissingCheckers): print(f"\n\tsudo apt-get install {self.install}") def give_redhat_hints(self): + """ + Provide package installation hints for RedHat-based distros + (Fedora, RHEL and RHEL-based variants). + """ progs = { "Pod::Usage": "perl-Pod-Usage", "convert": "ImageMagick", @@ -837,6 +877,10 @@ class SphinxDependencyChecker(MissingCheckers): print(f"\n\tsudo dnf install -y {self.install}") def give_opensuse_hints(self): + """ + Provide package installation hints for openSUSE-based distros + (Leap and Tumbleweed). + """ progs = { "Pod::Usage": "perl-Pod-Usage", "convert": "ImageMagick", @@ -909,6 +953,9 @@ class SphinxDependencyChecker(MissingCheckers): print(f"\n\tsudo zypper install --no-recommends {self.install}") def give_mageia_hints(self): + """ + Provide package installation hints for Mageia and OpenMandriva. + """ progs = { "Pod::Usage": "perl-Pod-Usage", "convert": "ImageMagick", @@ -956,6 +1003,9 @@ class SphinxDependencyChecker(MissingCheckers): print(f"\n\tsudo {packager_cmd} {self.install}") def give_arch_linux_hints(self): + """ + Provide package installation hints for ArchLinux. + """ progs = { "convert": "imagemagick", "dot": "graphviz", @@ -989,6 +1039,9 @@ class SphinxDependencyChecker(MissingCheckers): print(f"\n\tsudo pacman -S {self.install}") def give_gentoo_hints(self): + """ + Provide package installation hints for Gentoo. + """ progs = { "convert": "media-gfx/imagemagick", "dot": "media-gfx/graphviz", @@ -1107,7 +1160,12 @@ class SphinxDependencyChecker(MissingCheckers): # def check_distros(self): - # OS-specific hints logic + """ + OS-specific hints logic. Seeks for a hinter. If found, provide + package-manager-specific install commands. + + Otherwise, just lists the missing dependencies. + """ os_hints = { re.compile("Red Hat Enterprise Linux"): self.give_redhat_hints, re.compile("Fedora"): self.give_redhat_hints, @@ -1159,10 +1217,22 @@ class SphinxDependencyChecker(MissingCheckers): # Common dependencies # def deactivate_help(self): + """ + Print a helper message to disable a virtual environment. + """ + print("\n If you want to exit the virtualenv, you can use:") print("\tdeactivate") def get_virtenv(self): + """ + Give a hint about how to activate an already-existing virtual + environment containing sphinx-build. + + Returns a tuble with (activate_cmd_path, sphinx_version) with + the newest available virtual env. + """ + cwd = os.getcwd() activates = [] @@ -1207,6 +1277,14 @@ class SphinxDependencyChecker(MissingCheckers): return ("", ver) def recommend_sphinx_upgrade(self): + """ + Check if Sphinx needs to be upgraded. + + Returns a tuple with the higest available Sphinx version if found. + Otherwise, returns None to indicate either that no upgrade is needed + or no venv was found. + """ + # Avoid running sphinx-builds from venv if cur_version is good if self.cur_version and self.cur_version >= RECOMMENDED_VERSION: self.latest_avail_ver = self.cur_version @@ -1247,6 +1325,9 @@ class SphinxDependencyChecker(MissingCheckers): return self.latest_avail_ver def recommend_package(self): + """ + Recommend installing Sphinx as a distro-specific package. + """ print("\n2) As a package with:") @@ -1270,11 +1351,19 @@ class SphinxDependencyChecker(MissingCheckers): self.verbose_warn_install = old_verbose def recommend_sphinx_version(self, virtualenv_cmd): - # The logic here is complex, as it have to deal with different versions: - # - minimal supported version; - # - minimal PDF version; - # - recommended version. - # It also needs to work fine with both distro's package and venv/virtualenv + """ + Provide recommendations for installing or upgrading Sphinx based + on current version. + + The logic here is complex, as it have to deal with different versions: + + - minimal supported version; + - minimal PDF version; + - recommended version. + + It also needs to work fine with both distro's package and + venv/virtualenv + """ if self.recommend_python: print("\nPython version is incompatible with doc build.\n" \ @@ -1369,6 +1458,10 @@ class SphinxDependencyChecker(MissingCheckers): "\thttps://github.com/sphinx-doc/sphinx/pull/8313") def check_needs(self): + """ + Main method that checks needed dependencies and provides + recommendations. + """ self.python_cmd = sys.executable # Check if Sphinx is already accessible from current environment @@ -1451,6 +1544,7 @@ Process some flags related to Sphinx installation and documentation build. def main(): + """Main function""" parser = argparse.ArgumentParser(description=DESCRIPTION) parser.add_argument( @@ -1481,6 +1575,6 @@ def main(): checker.check_python() checker.check_needs() - +# Call main if not used as module if __name__ == "__main__": main() From 8b45effaa2ce2790e3b391e1ac4bb668e0d37560 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:49 +0200 Subject: [PATCH 00746/11391] scripts: sphinx-pre-install: fix several codingstyle issues Address most pylint issues. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/5139b18535e1436e4b1773706224a9ec3a386697.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 52 +++++++++++++++++------------------ 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index 1c96f6692e9a..1b11162da9fb 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -2,8 +2,8 @@ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (c) 2017-2025 Mauro Carvalho Chehab # -# pylint: disable=C0103,C0114,C0115,C0116,C0301 -# pylint: disable=R0902,R0904,R0912,R0915,R1705,R1710,E1121 +# pylint: disable=C0103,C0114,C0115,C0116,C0301,C0302 +# pylint: disable=R0902,R0904,R0911,R0912,R0914,R0915,R1705,R1710,E1121 # Note: this script requires at least Python 3.6 to run. # Don't add changes not compatible with it, it is meant to report @@ -115,7 +115,7 @@ class DepManager: if dtype[1]: return f"ERROR: {msg} mandatory deps missing" else: - out = f"Warning: {msg} optional deps missing" + return f"Warning: {msg} optional deps missing" @staticmethod def is_optional(dtype): @@ -125,7 +125,7 @@ class DepManager: @staticmethod def is_pdf(dtype): """Ancillary routine to report if a dependency is for PDF generation""" - if (dtype[0] == DepManager._PDF_TYPE): + if dtype[0] == DepManager._PDF_TYPE: return True return False @@ -191,8 +191,8 @@ class DepManager: self.missing_pkg[dtype].append(progs.get(prog, prog)) install = [] - for dtype in self.missing_pkg.keys(): - install += self.missing_pkg[dtype] + for dtype, pkgs in self.missing_pkg.items(): + install += pkgs return " ".join(sorted(set(install))) @@ -267,8 +267,6 @@ class AncillaryMethods: "python3.[0-9][0-9]", ] - new_python_cmd = None - # Seek for a python binary newer than MIN_PYTHON_VERSION for path in os.getenv("PATH", "").split(":"): for pattern in patterns: @@ -276,7 +274,7 @@ class AncillaryMethods: if os.path.isfile(cmd) and os.access(cmd, os.X_OK): version = SphinxDependencyChecker.get_python_version(cmd) if version >= MIN_PYTHON_VERSION: - return(cmd) + return cmd @staticmethod def check_python(): @@ -306,8 +304,8 @@ class AncillaryMethods: new_python_cmd = SphinxDependencyChecker.find_python() if not new_python_cmd: - print(f"ERROR: Python version {python_ver} is not spported anymore") - print(f" Can't find a new version. This script may fail") + print(f"ERROR: Python version {python_ver} is not spported anymore\n") + print(" Can't find a new version. This script may fail") return # Restart script using the newer version @@ -362,6 +360,9 @@ class MissingCheckers(AncillaryMethods): self.version_check = args.version_check self.texlive = texlive + self.min_version = (0, 0, 0) + self.cur_version = (0, 0, 0) + self.deps = DepManager(self.pdf) self.need_symlink = 0 @@ -370,8 +371,10 @@ class MissingCheckers(AncillaryMethods): self.verbose_warn_install = 1 self.virtenv_dir = "" - self.install = "" + self.python_cmd = "" + + self.virtenv_prefix = ["sphinx_", "Sphinx_" ] def check_missing_file(self, files, package, dtype): """ @@ -542,10 +545,10 @@ class MissingCheckers(AncillaryMethods): self.min_version = parse_version(match.group(1)) break except IOError: - sys.exit(f"Can't open {self.conf}") + sys.exit(f"Can't open {conf}") if not self.min_version: - sys.exit(f"Can't get needs_sphinx version from {self.conf}") + sys.exit(f"Can't get needs_sphinx version from {conf}") self.virtenv_dir = self.virtenv_prefix[0] + "latest" @@ -709,7 +712,6 @@ class SphinxDependencyChecker(MissingCheckers): self.rec_sphinx_upgrade = 0 self.system_release = self.get_system_release() - self.python_cmd = "" self.activate_cmd = "" # Some distros may not have a Sphinx shipped package compatible with @@ -722,8 +724,6 @@ class SphinxDependencyChecker(MissingCheckers): # Certain hints are meant to be shown only once self.first_hint = True - self.min_version = (0, 0, 0) - self.cur_version = (0, 0, 0) self.latest_avail_ver = (0, 0, 0) self.venv_ver = (0, 0, 0) @@ -731,7 +731,6 @@ class SphinxDependencyChecker(MissingCheckers): self.conf = prefix + "Documentation/conf.py" self.requirement_file = prefix + "Documentation/sphinx/requirements.txt" - self.virtenv_prefix = ["sphinx_", "Sphinx_" ] # # Distro-specific hints methods @@ -814,6 +813,7 @@ class SphinxDependencyChecker(MissingCheckers): if not rel: print("Couldn't identify release number") + noto_sans_redhat = None self.pdf = False elif re.search("Fedora", self.system_release): # Fedora 38 and upper use this CJK font @@ -1111,7 +1111,7 @@ class SphinxDependencyChecker(MissingCheckers): for fname, portage in portages.items(): install = False - while install == False: + while install is False: if not files: # No files under package.usage. Install all install = True @@ -1335,7 +1335,7 @@ class SphinxDependencyChecker(MissingCheckers): old_optional = self.deps.optional self.pdf = False - self.optional = 0 + self.deps.optional = 0 self.install = "" old_verbose = self.verbose_warn_install self.verbose_warn_install = 0 @@ -1346,8 +1346,8 @@ class SphinxDependencyChecker(MissingCheckers): self.check_distros() - self.need = old_need - self.optional = old_optional + self.deps.need = old_need + self.deps.optional = old_optional self.verbose_warn_install = old_verbose def recommend_sphinx_version(self, virtualenv_cmd): @@ -1528,13 +1528,13 @@ class SphinxDependencyChecker(MissingCheckers): self.recommend_sphinx_version(virtualenv_cmd) print("") - if not self.optional: + if not self.deps.optional: print("All optional dependencies are met.") - if self.need == 1: + if self.deps.need == 1: sys.exit("Can't build as 1 mandatory dependency is missing") - elif self.need: - sys.exit(f"Can't build as {self.need} mandatory dependencies are missing") + elif self.deps.need: + sys.exit(f"Can't build as {self.deps.need} mandatory dependencies are missing") print("Needed package dependencies are met.") From 24a34b3b453dc8fff0366a28c472b603f98a5c20 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:50 +0200 Subject: [PATCH 00747/11391] scripts: sphinx-pre-install: rework install command logic Cleanup the code to remove some redundancy and to let it be clearer about the command install instructions. Ensure that special instructions will be shown only once, before the actual install command. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/a6120449d9cc14346e867d1ef8944ae28ddbf3f6.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.py | 179 ++++++++++++++++------------------ 1 file changed, 82 insertions(+), 97 deletions(-) diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install.py index 1b11162da9fb..7dfe5c2a6cc2 100755 --- a/scripts/sphinx-pre-install.py +++ b/scripts/sphinx-pre-install.py @@ -213,7 +213,7 @@ class DepManager: raise KeyError(f"ERROR!!!: invalid dtype for {progs}: {dtype}") if output_msg: - print(f"\n{output_msg}\n") + print(f"\n{output_msg}") class AncillaryMethods: """ @@ -583,23 +583,6 @@ class MissingCheckers(AncillaryMethods): return f.read().strip() return "" - def check_missing(self, progs): - """ - Check for missing dependencies using the provided program mapping. - - The actual distro-specific programs are mapped via progs argument. - - Returns True if there are missing dependencies, False otherwise. - """ - self.install += self.deps.check_missing(progs) - if self.verbose_warn_install: - self.deps.warn_install() - - if not self.deps.need and not self.deps.optional: - return False - - return True - def get_system_release(self): """ Determine the system type. There's no unique way that would work @@ -722,7 +705,7 @@ class SphinxDependencyChecker(MissingCheckers): self.recommend_python = None # Certain hints are meant to be shown only once - self.first_hint = True + self.distro_msg = None self.latest_avail_ver = (0, 0, 0) self.venv_ver = (0, 0, 0) @@ -732,6 +715,33 @@ class SphinxDependencyChecker(MissingCheckers): self.conf = prefix + "Documentation/conf.py" self.requirement_file = prefix + "Documentation/sphinx/requirements.txt" + def get_install_progs(self, progs, cmd, extra=None): + """ + Check for missing dependencies using the provided program mapping. + + The actual distro-specific programs are mapped via progs argument. + """ + install = self.deps.check_missing(progs) + + if self.verbose_warn_install: + self.deps.warn_install() + + if not install: + return + + if cmd: + if self.verbose_warn_install: + msg = "You should run:" + else: + msg = "" + + if extra: + msg += "\n\t" + extra.replace("\n", "\n\t") + + return(msg + "\n\tsudo " + cmd + " " + install) + + return None + # # Distro-specific hints methods # @@ -772,12 +782,7 @@ class SphinxDependencyChecker(MissingCheckers): self.check_program("dvipng", DepManager.PDF_MANDATORY) - if self.check_missing(progs): - return - - if self.verbose_warn_install: - print("You should run:") - print(f"\n\tsudo apt-get install {self.install}") + return self.get_install_progs(progs, "apt-get install") def give_redhat_hints(self): """ @@ -838,18 +843,16 @@ class SphinxDependencyChecker(MissingCheckers): self.deps.add_package("python39", DepManager.SYSTEM_MANDATORY) self.recommend_python = True - if self.first_hint: - print("Note: RHEL-based distros typically require extra repositories.\n" \ - "For most, enabling epel and crb are enough:\n" \ - "\tsudo dnf install -y epel-release", \ - "\tsudo dnf config-manager --set-enabled crb\n" \ - "Yet, some may have other required repositories. Those commands could be useful:\n" \ - "\tsudo dnf repolist all\n" \ - "\tsudo dnf repoquery --available --info \n", - "\tsudo dnf config-manager --set-enabled '*' # enable all - probably not what you want") - - self.first_hint = False - + if not self.distro_msg: + self.distro_msg = \ + "Note: RHEL-based distros typically require extra repositories.\n" \ + "For most, enabling epel and crb are enough:\n" \ + "\tsudo dnf install -y epel-release\n" \ + "\tsudo dnf config-manager --set-enabled crb\n" \ + "Yet, some may have other required repositories. Those commands could be useful:\n" \ + "\tsudo dnf repolist all\n" \ + "\tsudo dnf repoquery --available --info \n" \ + "\tsudo dnf config-manager --set-enabled '*' # enable all - probably not what you want" if self.pdf: pdf_pkgs = [ @@ -868,13 +871,7 @@ class SphinxDependencyChecker(MissingCheckers): if not fedora and rel == 8: self.deps.del_package("texlive-ctex") - if self.check_missing(progs): - return - - if self.verbose_warn_install: - print("You should run:") - - print(f"\n\tsudo dnf install -y {self.install}") + return self.get_install_progs(progs, "dnf install") def give_opensuse_hints(self): """ @@ -945,12 +942,7 @@ class SphinxDependencyChecker(MissingCheckers): if self.pdf: self.check_missing_tex() - if self.check_missing(progs): - return - - if self.verbose_warn_install: - print("You should run:") - print(f"\n\tsudo zypper install --no-recommends {self.install}") + return self.get_install_progs(progs, "zypper install --no-recommends") def give_mageia_hints(self): """ @@ -995,12 +987,7 @@ class SphinxDependencyChecker(MissingCheckers): self.check_missing_file(pdf_pkgs, noto_sans, DepManager.PDF_MANDATORY) self.check_rpm_missing(tex_pkgs, DepManager.PDF_MANDATORY) - if self.check_missing(progs): - return - - if self.verbose_warn_install: - print("You should run:") - print(f"\n\tsudo {packager_cmd} {self.install}") + return self.get_install_progs(progs, packager_cmd) def give_arch_linux_hints(self): """ @@ -1023,20 +1010,15 @@ class SphinxDependencyChecker(MissingCheckers): ] if self.pdf: - self.check_pacman_missing(archlinux_tex_pkgs, DepManager.PDF_MANDATORY) + self.check_pacman_missing(archlinux_tex_pkgs, + DepManager.PDF_MANDATORY) - self.check_missing_file( - ["/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc"], - "noto-fonts-cjk", - 2, - ) + self.check_missing_file(["/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc"], + "noto-fonts-cjk", + DepManager.PDF_MANDATORY) - if self.check_missing(progs): - return - if self.verbose_warn_install: - print("You should run:") - print(f"\n\tsudo pacman -S {self.install}") + return self.get_install_progs(progs, "pacman -S") def give_gentoo_hints(self): """ @@ -1065,13 +1047,6 @@ class SphinxDependencyChecker(MissingCheckers): for package, files in pdf_pkgs.items(): self.check_missing_file(files, package, DepManager.PDF_MANDATORY) - if self.check_missing(progs): - return - - if self.verbose_warn_install: - print("You should run:") - print("\n") - # Handling dependencies is a nightmare, as Gentoo refuses to emerge # some packages if there's no package.use file describing them. # To make it worse, compilation flags shall also be present there @@ -1104,7 +1079,10 @@ class SphinxDependencyChecker(MissingCheckers): "zziblib": "dev-libs/zziplib sdl", } - if self.first_hint: + extra_cmds = "" + if not self.distro_msg: + self.distro_msg = "Note: Gentoo requires package.use to be adjusted before emerging packages" + use_base = "/etc/portage/package.use" files = glob(f"{use_base}/*") @@ -1148,23 +1126,23 @@ class SphinxDependencyChecker(MissingCheckers): # emit a code to setup missing USE if install: - print(f"\tsudo su -c 'echo \"{portage}\" > {use_base}/{fname}'") - - self.first_hint = False + extra_cmds += (f"sudo su -c 'echo \"{portage}\" > {use_base}/{fname}'\n") # Now, we can use emerge and let it respect USE - print(f"\tsudo emerge --ask --changed-use --binpkg-respect-use=y {self.install}") + return self.get_install_progs(progs, + "emerge --ask --changed-use --binpkg-respect-use=y", + extra_cmds) - # - # Dispatch the check to an os_specific hinter - # - - def check_distros(self): + def get_install(self): """ - OS-specific hints logic. Seeks for a hinter. If found, provide - package-manager-specific install commands. + OS-specific hints logic. Seeks for a hinter. If found, use it to + provide package-manager specific install commands. - Otherwise, just lists the missing dependencies. + Otherwise, outputs install instructions for the meta-packages. + + Returns a string with the command to be executed to install the + the needed packages, if distro found. Otherwise, return just a + list of packages that require installation. """ os_hints = { re.compile("Red Hat Enterprise Linux"): self.give_redhat_hints, @@ -1195,9 +1173,7 @@ class SphinxDependencyChecker(MissingCheckers): # If the OS is detected, use per-OS hint logic for regex, os_hint in os_hints.items(): if regex.search(self.system_release): - os_hint() - - return + return os_hint() # # Fall-back to generic hint code for other distros @@ -1207,11 +1183,12 @@ class SphinxDependencyChecker(MissingCheckers): if self.pdf: self.check_missing_tex() - self.check_missing(progs) + self.distro_msg = \ + f"I don't know distro {self.system_release}.\n" \ + "So, I can't provide you a hint with the install procedure.\n" \ + "There are likely missing dependencies.\n" - print(f"I don't know distro {self.system_release}.") - print("So, I can't provide you a hint with the install procedure.") - print("There are likely missing dependencies.") + return self.get_install_progs(progs, None) # # Common dependencies @@ -1336,7 +1313,6 @@ class SphinxDependencyChecker(MissingCheckers): self.pdf = False self.deps.optional = 0 - self.install = "" old_verbose = self.verbose_warn_install self.verbose_warn_install = 0 @@ -1344,7 +1320,9 @@ class SphinxDependencyChecker(MissingCheckers): self.deps.add_package("python-sphinx", DepManager.PYTHON_MANDATORY) - self.check_distros() + cmd = self.get_install() + if cmd: + print(cmd) self.deps.need = old_need self.deps.optional = old_optional @@ -1511,7 +1489,14 @@ class SphinxDependencyChecker(MissingCheckers): self.check_program("latexmk", DepManager.PDF_MANDATORY) # Do distro-specific checks and output distro-install commands - self.check_distros() + cmd = self.get_install() + if cmd: + print(cmd) + + # If distro requires some special instructions, print here. + # Please notice that get_install() needs to be called first. + if self.distro_msg: + print("\n" + self.distro_msg) if not self.python_cmd: if self.need == 1: From d43cd965f3a646d22851192c659b787dba311d87 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:51 +0200 Subject: [PATCH 00748/11391] docs: Makefile: switch to the new scripts/sphinx-pre-install.py Now that we have a better, improved Python script, use it when checking for documentation build dependencies. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/79508fb071512c33e807f5411bbff1904751b5d3.1754992972.git.mchehab+huawei@kernel.org --- Documentation/Makefile | 14 +++++++------- .../{sphinx-pre-install.py => sphinx-pre-install} | 0 2 files changed, 7 insertions(+), 7 deletions(-) rename scripts/{sphinx-pre-install.py => sphinx-pre-install} (100%) diff --git a/Documentation/Makefile b/Documentation/Makefile index c486fe3cc5e1..b98477df5ddf 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -46,7 +46,7 @@ ifeq ($(HAVE_SPHINX),0) .DEFAULT: $(warning The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed and in PATH, or set the SPHINXBUILD make variable to point to the full path of the '$(SPHINXBUILD)' executable.) @echo - @$(srctree)/scripts/sphinx-pre-install.pl + @$(srctree)/scripts/sphinx-pre-install @echo " SKIP Sphinx $@ target." else # HAVE_SPHINX @@ -121,7 +121,7 @@ $(YNL_RST_DIR)/%.rst: $(YNL_YAML_DIR)/%.yaml $(YNL_TOOL) htmldocs texinfodocs latexdocs epubdocs xmldocs: $(YNL_INDEX) htmldocs: - @$(srctree)/scripts/sphinx-pre-install.pl --version-check + @$(srctree)/scripts/sphinx-pre-install --version-check @+$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,html,$(var),,$(var))) # If Rust support is available and .config exists, add rustdoc generated contents. @@ -135,7 +135,7 @@ endif endif texinfodocs: - @$(srctree)/scripts/sphinx-pre-install.pl --version-check + @$(srctree)/scripts/sphinx-pre-install --version-check @+$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,texinfo,$(var),texinfo,$(var))) # Note: the 'info' Make target is generated by sphinx itself when @@ -147,7 +147,7 @@ linkcheckdocs: @$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,linkcheck,$(var),,$(var))) latexdocs: - @$(srctree)/scripts/sphinx-pre-install.pl --version-check + @$(srctree)/scripts/sphinx-pre-install --version-check @+$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,latex,$(var),latex,$(var))) ifeq ($(HAVE_PDFLATEX),0) @@ -160,7 +160,7 @@ else # HAVE_PDFLATEX pdfdocs: DENY_VF = XDG_CONFIG_HOME=$(FONTS_CONF_DENY_VF) pdfdocs: latexdocs - @$(srctree)/scripts/sphinx-pre-install.pl --version-check + @$(srctree)/scripts/sphinx-pre-install --version-check $(foreach var,$(SPHINXDIRS), \ $(MAKE) PDFLATEX="$(PDFLATEX)" LATEXOPTS="$(LATEXOPTS)" $(DENY_VF) -C $(BUILDDIR)/$(var)/latex || sh $(srctree)/scripts/check-variable-fonts.sh || exit; \ mkdir -p $(BUILDDIR)/$(var)/pdf; \ @@ -170,11 +170,11 @@ pdfdocs: latexdocs endif # HAVE_PDFLATEX epubdocs: - @$(srctree)/scripts/sphinx-pre-install.pl --version-check + @$(srctree)/scripts/sphinx-pre-install --version-check @+$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,epub,$(var),epub,$(var))) xmldocs: - @$(srctree)/scripts/sphinx-pre-install.pl --version-check + @$(srctree)/scripts/sphinx-pre-install --version-check @+$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,xml,$(var),xml,$(var))) endif # HAVE_SPHINX diff --git a/scripts/sphinx-pre-install.py b/scripts/sphinx-pre-install similarity index 100% rename from scripts/sphinx-pre-install.py rename to scripts/sphinx-pre-install From 29e71d96837dd49ab2f35f3524a1ceda0ff21ea7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:52 +0200 Subject: [PATCH 00749/11391] scripts: sphinx-pre-install.pl: get rid of the old script All features were ported to the Python version. Plus, it supports more variants and contain fixes. So, drop the old version. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/6900872e6b89b7ff304e70f5d1c23cbb3c757d28.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install.pl | 1056 --------------------------------- 1 file changed, 1056 deletions(-) delete mode 100755 scripts/sphinx-pre-install.pl diff --git a/scripts/sphinx-pre-install.pl b/scripts/sphinx-pre-install.pl deleted file mode 100755 index 07234d482fa8..000000000000 --- a/scripts/sphinx-pre-install.pl +++ /dev/null @@ -1,1056 +0,0 @@ -#!/usr/bin/env perl -# SPDX-License-Identifier: GPL-2.0-or-later -use strict; - -# Copyright (c) 2017-2020 Mauro Carvalho Chehab -# - -my $prefix = "./"; -$prefix = "$ENV{'srctree'}/" if ($ENV{'srctree'}); - -my $conf = $prefix . "Documentation/conf.py"; -my $requirement_file = $prefix . "Documentation/sphinx/requirements.txt"; -my $virtenv_prefix = "sphinx_"; - -# -# Static vars -# - -my %missing; -my $system_release; -my $need = 0; -my $optional = 0; -my $need_symlink = 0; -my $need_sphinx = 0; -my $need_pip = 0; -my $need_virtualenv = 0; -my $rec_sphinx_upgrade = 0; -my $verbose_warn_install = 1; -my $install = ""; -my $virtenv_dir = ""; -my $python_cmd = ""; -my $activate_cmd; -my $min_version; -my $cur_version; -my $rec_version = "3.4.3"; -my $latest_avail_ver; - -# -# Command line arguments -# - -my $pdf = 1; -my $virtualenv = 1; -my $version_check = 0; - -# -# List of required texlive packages on Fedora and OpenSuse -# - -my %texlive = ( - 'amsfonts.sty' => 'texlive-amsfonts', - 'amsmath.sty' => 'texlive-amsmath', - 'amssymb.sty' => 'texlive-amsfonts', - 'amsthm.sty' => 'texlive-amscls', - 'anyfontsize.sty' => 'texlive-anyfontsize', - 'atbegshi.sty' => 'texlive-oberdiek', - 'bm.sty' => 'texlive-tools', - 'capt-of.sty' => 'texlive-capt-of', - 'cmap.sty' => 'texlive-cmap', - 'ecrm1000.tfm' => 'texlive-ec', - 'eqparbox.sty' => 'texlive-eqparbox', - 'eu1enc.def' => 'texlive-euenc', - 'fancybox.sty' => 'texlive-fancybox', - 'fancyvrb.sty' => 'texlive-fancyvrb', - 'float.sty' => 'texlive-float', - 'fncychap.sty' => 'texlive-fncychap', - 'footnote.sty' => 'texlive-mdwtools', - 'framed.sty' => 'texlive-framed', - 'luatex85.sty' => 'texlive-luatex85', - 'multirow.sty' => 'texlive-multirow', - 'needspace.sty' => 'texlive-needspace', - 'palatino.sty' => 'texlive-psnfss', - 'parskip.sty' => 'texlive-parskip', - 'polyglossia.sty' => 'texlive-polyglossia', - 'tabulary.sty' => 'texlive-tabulary', - 'threeparttable.sty' => 'texlive-threeparttable', - 'titlesec.sty' => 'texlive-titlesec', - 'ucs.sty' => 'texlive-ucs', - 'upquote.sty' => 'texlive-upquote', - 'wrapfig.sty' => 'texlive-wrapfig', - 'ctexhook.sty' => 'texlive-ctex', -); - -# -# Subroutines that checks if a feature exists -# - -sub check_missing(%) -{ - my %map = %{$_[0]}; - - foreach my $prog (sort keys %missing) { - my $is_optional = $missing{$prog}; - - # At least on some LTS distros like CentOS 7, texlive doesn't - # provide all packages we need. When such distros are - # detected, we have to disable PDF output. - # - # So, we need to ignore the packages that distros would - # need for LaTeX to work - if ($is_optional == 2 && !$pdf) { - $optional--; - next; - } - - if ($verbose_warn_install) { - if ($is_optional) { - print "Warning: better to also install \"$prog\".\n"; - } else { - print "ERROR: please install \"$prog\", otherwise, build won't work.\n"; - } - } - if (defined($map{$prog})) { - $install .= " " . $map{$prog}; - } else { - $install .= " " . $prog; - } - } - - $install =~ s/^\s//; -} - -sub add_package($$) -{ - my $package = shift; - my $is_optional = shift; - - $missing{$package} = $is_optional; - if ($is_optional) { - $optional++; - } else { - $need++; - } -} - -sub check_missing_file($$$) -{ - my $files = shift; - my $package = shift; - my $is_optional = shift; - - for (@$files) { - return if(-e $_); - } - - add_package($package, $is_optional); -} - -sub findprog($) -{ - foreach(split(/:/, $ENV{PATH})) { - return "$_/$_[0]" if(-x "$_/$_[0]"); - } -} - -sub find_python_no_venv() -{ - my $prog = shift; - - my $cur_dir = qx(pwd); - $cur_dir =~ s/\s+$//; - - foreach my $dir (split(/:/, $ENV{PATH})) { - next if ($dir =~ m,($cur_dir)/sphinx,); - return "$dir/python3" if(-x "$dir/python3"); - } - foreach my $dir (split(/:/, $ENV{PATH})) { - next if ($dir =~ m,($cur_dir)/sphinx,); - return "$dir/python" if(-x "$dir/python"); - } - return "python"; -} - -sub check_program($$) -{ - my $prog = shift; - my $is_optional = shift; - - return $prog if findprog($prog); - - add_package($prog, $is_optional); -} - -sub check_perl_module($$) -{ - my $prog = shift; - my $is_optional = shift; - - my $err = system("perl -M$prog -e 1 2>/dev/null /dev/null"); - return if ($err == 0); - - add_package($prog, $is_optional); -} - -sub check_python_module($$) -{ - my $prog = shift; - my $is_optional = shift; - - return if (!$python_cmd); - - my $err = system("$python_cmd -c 'import $prog' 2>/dev/null /dev/null"); - return if ($err == 0); - - add_package($prog, $is_optional); -} - -sub check_rpm_missing($$) -{ - my @pkgs = @{$_[0]}; - my $is_optional = $_[1]; - - foreach my $prog(@pkgs) { - my $err = system("rpm -q '$prog' 2>/dev/null >/dev/null"); - add_package($prog, $is_optional) if ($err); - } -} - -sub check_pacman_missing($$) -{ - my @pkgs = @{$_[0]}; - my $is_optional = $_[1]; - - foreach my $prog(@pkgs) { - my $err = system("pacman -Q '$prog' 2>/dev/null >/dev/null"); - add_package($prog, $is_optional) if ($err); - } -} - -sub check_missing_tex($) -{ - my $is_optional = shift; - my $kpsewhich = findprog("kpsewhich"); - - foreach my $prog(keys %texlive) { - my $package = $texlive{$prog}; - if (!$kpsewhich) { - add_package($package, $is_optional); - next; - } - my $file = qx($kpsewhich $prog); - add_package($package, $is_optional) if ($file =~ /^\s*$/); - } -} - -sub get_sphinx_fname() -{ - if ($ENV{'SPHINXBUILD'}) { - return $ENV{'SPHINXBUILD'}; - } - - my $fname = "sphinx-build"; - return $fname if findprog($fname); - - $fname = "sphinx-build-3"; - if (findprog($fname)) { - $need_symlink = 1; - return $fname; - } - - return ""; -} - -sub get_sphinx_version($) -{ - my $cmd = shift; - my $ver; - - open IN, "$cmd --version 2>&1 |"; - while () { - if (m/^\s*sphinx-build\s+([\d\.]+)((\+\/[\da-f]+)|(b\d+))?$/) { - $ver=$1; - last; - } - # Sphinx 1.2.x uses a different format - if (m/^\s*Sphinx.*\s+([\d\.]+)$/) { - $ver=$1; - last; - } - } - close IN; - return $ver; -} - -sub check_sphinx() -{ - open IN, $conf or die "Can't open $conf"; - while () { - if (m/^\s*needs_sphinx\s*=\s*[\'\"]([\d\.]+)[\'\"]/) { - $min_version=$1; - last; - } - } - close IN; - - die "Can't get needs_sphinx version from $conf" if (!$min_version); - - $virtenv_dir = $virtenv_prefix . "latest"; - - my $sphinx = get_sphinx_fname(); - if ($sphinx eq "") { - $need_sphinx = 1; - return; - } - - $cur_version = get_sphinx_version($sphinx); - die "$sphinx didn't return its version" if (!$cur_version); - - if ($cur_version lt $min_version) { - printf "ERROR: Sphinx version is %s. It should be >= %s\n", - $cur_version, $min_version; - $need_sphinx = 1; - return; - } - - return if ($cur_version lt $rec_version); - - # On version check mode, just assume Sphinx has all mandatory deps - exit (0) if ($version_check); -} - -# -# Ancillary subroutines -# - -sub catcheck($) -{ - my $res = ""; - $res = qx(cat $_[0]) if (-r $_[0]); - return $res; -} - -sub which($) -{ - my $file = shift; - my @path = split ":", $ENV{PATH}; - - foreach my $dir(@path) { - my $name = $dir.'/'.$file; - return $name if (-x $name ); - } - return undef; -} - -# -# Subroutines that check distro-specific hints -# - -sub give_debian_hints() -{ - my %map = ( - "python-sphinx" => "python3-sphinx", - "yaml" => "python3-yaml", - "ensurepip" => "python3-venv", - "virtualenv" => "virtualenv", - "dot" => "graphviz", - "convert" => "imagemagick", - "Pod::Usage" => "perl-modules", - "xelatex" => "texlive-xetex", - "rsvg-convert" => "librsvg2-bin", - ); - - if ($pdf) { - check_missing_file(["/usr/share/texlive/texmf-dist/tex/latex/ctex/ctexhook.sty"], - "texlive-lang-chinese", 2); - - check_missing_file(["/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"], - "fonts-dejavu", 2); - - check_missing_file(["/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc", - "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc", - "/usr/share/fonts/opentype/noto/NotoSerifCJK-Regular.ttc"], - "fonts-noto-cjk", 2); - } - - check_program("dvipng", 2) if ($pdf); - check_missing(\%map); - - return if (!$need && !$optional); - printf("You should run:\n") if ($verbose_warn_install); - printf("\n\tsudo apt-get install $install\n"); -} - -sub give_redhat_hints() -{ - my %map = ( - "python-sphinx" => "python3-sphinx", - "yaml" => "python3-pyyaml", - "virtualenv" => "python3-virtualenv", - "dot" => "graphviz", - "convert" => "ImageMagick", - "Pod::Usage" => "perl-Pod-Usage", - "xelatex" => "texlive-xetex-bin", - "rsvg-convert" => "librsvg2-tools", - ); - - my @fedora26_opt_pkgs = ( - "graphviz-gd", # Fedora 26: needed for PDF support - ); - - my @fedora_tex_pkgs = ( - "texlive-collection-fontsrecommended", - "texlive-collection-latex", - "texlive-xecjk", - "dejavu-sans-fonts", - "dejavu-serif-fonts", - "dejavu-sans-mono-fonts", - ); - - # - # Checks valid for RHEL/CentOS version 7.x. - # - my $old = 0; - my $rel; - my $noto_sans_redhat = "google-noto-sans-cjk-ttc-fonts"; - $rel = $2 if ($system_release =~ /(release|Linux)\s+(\d+)/); - - if (!($system_release =~ /Fedora/)) { - $map{"virtualenv"} = "python-virtualenv"; - - if ($rel && $rel < 8) { - $old = 1; - $pdf = 0; - - printf("Note: texlive packages on RHEL/CENTOS <= 7 are incomplete. Can't support PDF output\n"); - printf("If you want to build PDF, please read:\n"); - printf("\thttps://www.systutorials.com/241660/how-to-install-tex-live-on-centos-7-linux/\n"); - } - } else { - if ($rel && $rel < 26) { - $old = 1; - } - if ($rel && $rel >= 38) { - $noto_sans_redhat = "google-noto-sans-cjk-fonts"; - } - } - if (!$rel) { - printf("Couldn't identify release number\n"); - $old = 1; - $pdf = 0; - } - - if ($pdf) { - check_missing_file(["/usr/share/fonts/google-noto-cjk/NotoSansCJK-Regular.ttc", - "/usr/share/fonts/google-noto-sans-cjk-fonts/NotoSansCJK-Regular.ttc"], - $noto_sans_redhat, 2); - } - - check_rpm_missing(\@fedora26_opt_pkgs, 2) if ($pdf && !$old); - check_rpm_missing(\@fedora_tex_pkgs, 2) if ($pdf); - check_missing_tex(2) if ($pdf); - check_missing(\%map); - - return if (!$need && !$optional); - - if (!$old) { - # dnf, for Fedora 18+ - printf("You should run:\n") if ($verbose_warn_install); - printf("\n\tsudo dnf install -y $install\n"); - } else { - # yum, for RHEL (and clones) or Fedora version < 18 - printf("You should run:\n") if ($verbose_warn_install); - printf("\n\tsudo yum install -y $install\n"); - } -} - -sub give_opensuse_hints() -{ - my %map = ( - "python-sphinx" => "python3-sphinx", - "yaml" => "python3-pyyaml", - "virtualenv" => "python3-virtualenv", - "dot" => "graphviz", - "convert" => "ImageMagick", - "Pod::Usage" => "perl-Pod-Usage", - "xelatex" => "texlive-xetex-bin", - ); - - # On Tumbleweed, this package is also named rsvg-convert - $map{"rsvg-convert"} = "rsvg-view" if (!($system_release =~ /Tumbleweed/)); - - my @suse_tex_pkgs = ( - "texlive-babel-english", - "texlive-caption", - "texlive-colortbl", - "texlive-courier", - "texlive-dvips", - "texlive-helvetic", - "texlive-makeindex", - "texlive-metafont", - "texlive-metapost", - "texlive-palatino", - "texlive-preview", - "texlive-times", - "texlive-zapfchan", - "texlive-zapfding", - ); - - $map{"latexmk"} = "texlive-latexmk-bin"; - - # FIXME: add support for installing CJK fonts - # - # I tried hard, but was unable to find a way to install - # "Noto Sans CJK SC" on openSUSE - - check_rpm_missing(\@suse_tex_pkgs, 2) if ($pdf); - check_missing_tex(2) if ($pdf); - check_missing(\%map); - - return if (!$need && !$optional); - printf("You should run:\n") if ($verbose_warn_install); - printf("\n\tsudo zypper install --no-recommends $install\n"); -} - -sub give_mageia_hints() -{ - my %map = ( - "python-sphinx" => "python3-sphinx", - "yaml" => "python3-yaml", - "virtualenv" => "python3-virtualenv", - "dot" => "graphviz", - "convert" => "ImageMagick", - "Pod::Usage" => "perl-Pod-Usage", - "xelatex" => "texlive", - "rsvg-convert" => "librsvg2", - ); - - my @tex_pkgs = ( - "texlive-fontsextra", - ); - - $map{"latexmk"} = "texlive-collection-basic"; - - my $packager_cmd; - my $noto_sans; - if ($system_release =~ /OpenMandriva/) { - $packager_cmd = "dnf install"; - $noto_sans = "noto-sans-cjk-fonts"; - @tex_pkgs = ( "texlive-collection-fontsextra" ); - } else { - $packager_cmd = "urpmi"; - $noto_sans = "google-noto-sans-cjk-ttc-fonts"; - } - - - if ($pdf) { - check_missing_file(["/usr/share/fonts/google-noto-cjk/NotoSansCJK-Regular.ttc", - "/usr/share/fonts/TTF/NotoSans-Regular.ttf"], - $noto_sans, 2); - } - - check_rpm_missing(\@tex_pkgs, 2) if ($pdf); - check_missing(\%map); - - return if (!$need && !$optional); - printf("You should run:\n") if ($verbose_warn_install); - printf("\n\tsudo $packager_cmd $install\n"); -} - -sub give_arch_linux_hints() -{ - my %map = ( - "yaml" => "python-yaml", - "virtualenv" => "python-virtualenv", - "dot" => "graphviz", - "convert" => "imagemagick", - "xelatex" => "texlive-xetex", - "latexmk" => "texlive-core", - "rsvg-convert" => "extra/librsvg", - ); - - my @archlinux_tex_pkgs = ( - "texlive-core", - "texlive-latexextra", - "ttf-dejavu", - ); - check_pacman_missing(\@archlinux_tex_pkgs, 2) if ($pdf); - - if ($pdf) { - check_missing_file(["/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc"], - "noto-fonts-cjk", 2); - } - - check_missing(\%map); - - return if (!$need && !$optional); - printf("You should run:\n") if ($verbose_warn_install); - printf("\n\tsudo pacman -S $install\n"); -} - -sub give_gentoo_hints() -{ - my %map = ( - "yaml" => "dev-python/pyyaml", - "virtualenv" => "dev-python/virtualenv", - "dot" => "media-gfx/graphviz", - "convert" => "media-gfx/imagemagick", - "xelatex" => "dev-texlive/texlive-xetex media-fonts/dejavu", - "rsvg-convert" => "gnome-base/librsvg", - ); - - check_missing_file(["/usr/share/fonts/dejavu/DejaVuSans.ttf"], - "media-fonts/dejavu", 2) if ($pdf); - - if ($pdf) { - check_missing_file(["/usr/share/fonts/noto-cjk/NotoSansCJKsc-Regular.otf", - "/usr/share/fonts/noto-cjk/NotoSerifCJK-Regular.ttc"], - "media-fonts/noto-cjk", 2); - } - - check_missing(\%map); - - return if (!$need && !$optional); - - printf("You should run:\n") if ($verbose_warn_install); - printf("\n"); - - my $imagemagick = "media-gfx/imagemagick svg png"; - my $cairo = "media-gfx/graphviz cairo pdf"; - my $portage_imagemagick = "/etc/portage/package.use/imagemagick"; - my $portage_cairo = "/etc/portage/package.use/graphviz"; - - if (qx(grep imagemagick $portage_imagemagick 2>/dev/null) eq "") { - printf("\tsudo su -c 'echo \"$imagemagick\" > $portage_imagemagick'\n") - } - if (qx(grep graphviz $portage_cairo 2>/dev/null) eq "") { - printf("\tsudo su -c 'echo \"$cairo\" > $portage_cairo'\n"); - } - - printf("\tsudo emerge --ask $install\n"); - -} - -sub check_distros() -{ - # Distro-specific hints - if ($system_release =~ /Red Hat Enterprise Linux/) { - give_redhat_hints; - return; - } - if ($system_release =~ /CentOS/) { - give_redhat_hints; - return; - } - if ($system_release =~ /Scientific Linux/) { - give_redhat_hints; - return; - } - if ($system_release =~ /Oracle Linux Server/) { - give_redhat_hints; - return; - } - if ($system_release =~ /Fedora/) { - give_redhat_hints; - return; - } - if ($system_release =~ /Ubuntu/) { - give_debian_hints; - return; - } - if ($system_release =~ /Debian/) { - give_debian_hints; - return; - } - if ($system_release =~ /openSUSE/) { - give_opensuse_hints; - return; - } - if ($system_release =~ /Mageia/) { - give_mageia_hints; - return; - } - if ($system_release =~ /OpenMandriva/) { - give_mageia_hints; - return; - } - if ($system_release =~ /Arch Linux/) { - give_arch_linux_hints; - return; - } - if ($system_release =~ /Gentoo/) { - give_gentoo_hints; - return; - } - - # - # Fall-back to generic hint code for other distros - # That's far from ideal, specially for LaTeX dependencies. - # - my %map = ( - "sphinx-build" => "sphinx" - ); - check_missing_tex(2) if ($pdf); - check_missing(\%map); - print "I don't know distro $system_release.\n"; - print "So, I can't provide you a hint with the install procedure.\n"; - print "There are likely missing dependencies.\n"; -} - -# -# Common dependencies -# - -sub deactivate_help() -{ - printf "\n If you want to exit the virtualenv, you can use:\n"; - printf "\tdeactivate\n"; -} - -sub get_virtenv() -{ - my $ver; - my $min_activate = "$ENV{'PWD'}/${virtenv_prefix}${min_version}/bin/activate"; - my @activates = glob "$ENV{'PWD'}/${virtenv_prefix}*/bin/activate"; - - @activates = sort {$b cmp $a} @activates; - - foreach my $f (@activates) { - next if ($f lt $min_activate); - - my $sphinx_cmd = $f; - $sphinx_cmd =~ s/activate/sphinx-build/; - next if (! -f $sphinx_cmd); - - my $ver = get_sphinx_version($sphinx_cmd); - - if (!$ver) { - $f =~ s#/bin/activate##; - print("Warning: virtual environment $f is not working.\nPython version upgrade? Remove it with:\n\n\trm -rf $f\n\n"); - } - - if ($need_sphinx && ($ver ge $min_version)) { - return ($f, $ver); - } elsif ($ver gt $cur_version) { - return ($f, $ver); - } - } - return ("", ""); -} - -sub recommend_sphinx_upgrade() -{ - my $venv_ver; - - # Avoid running sphinx-builds from venv if $cur_version is good - if ($cur_version && ($cur_version ge $rec_version)) { - $latest_avail_ver = $cur_version; - return; - } - - # Get the highest version from sphinx_*/bin/sphinx-build and the - # corresponding command to activate the venv/virtenv - ($activate_cmd, $venv_ver) = get_virtenv(); - - # Store the highest version from Sphinx existing virtualenvs - if (($activate_cmd ne "") && ($venv_ver gt $cur_version)) { - $latest_avail_ver = $venv_ver; - } else { - $latest_avail_ver = $cur_version if ($cur_version); - } - - # As we don't know package version of Sphinx, and there's no - # virtual environments, don't check if upgrades are needed - if (!$virtualenv) { - return if (!$latest_avail_ver); - } - - # Either there are already a virtual env or a new one should be created - $need_pip = 1; - - return if (!$latest_avail_ver); - - # Return if the reason is due to an upgrade or not - if ($latest_avail_ver lt $rec_version) { - $rec_sphinx_upgrade = 1; - } - - return $latest_avail_ver; -} - -# -# The logic here is complex, as it have to deal with different versions: -# - minimal supported version; -# - minimal PDF version; -# - recommended version. -# It also needs to work fine with both distro's package and venv/virtualenv -sub recommend_sphinx_version($) -{ - my $virtualenv_cmd = shift; - - # Version is OK. Nothing to do. - if ($cur_version && ($cur_version ge $rec_version)) { - return; - }; - - if (!$need_sphinx) { - # sphinx-build is present and its version is >= $min_version - - #only recommend enabling a newer virtenv version if makes sense. - if ($latest_avail_ver gt $cur_version) { - printf "\nYou may also use the newer Sphinx version $latest_avail_ver with:\n"; - printf "\tdeactivate\n" if ($ENV{'PWD'} =~ /${virtenv_prefix}/); - printf "\t. $activate_cmd\n"; - deactivate_help(); - - return; - } - return if ($latest_avail_ver ge $rec_version); - } - - if (!$virtualenv) { - # No sphinx either via package or via virtenv. As we can't - # Compare the versions here, just return, recommending the - # user to install it from the package distro. - return if (!$latest_avail_ver); - - # User doesn't want a virtenv recommendation, but he already - # installed one via virtenv with a newer version. - # So, print commands to enable it - if ($latest_avail_ver gt $cur_version) { - printf "\nYou may also use the Sphinx virtualenv version $latest_avail_ver with:\n"; - printf "\tdeactivate\n" if ($ENV{'PWD'} =~ /${virtenv_prefix}/); - printf "\t. $activate_cmd\n"; - deactivate_help(); - - return; - } - print "\n"; - } else { - $need++ if ($need_sphinx); - } - - # Suggest newer versions if current ones are too old - if ($latest_avail_ver && $latest_avail_ver ge $min_version) { - # If there's a good enough version, ask the user to enable it - if ($latest_avail_ver ge $rec_version) { - printf "\nNeed to activate Sphinx (version $latest_avail_ver) on virtualenv with:\n"; - printf "\t. $activate_cmd\n"; - deactivate_help(); - - return; - } - - # Version is above the minimal required one, but may be - # below the recommended one. So, print warnings/notes - - if ($latest_avail_ver lt $rec_version) { - print "Warning: It is recommended at least Sphinx version $rec_version.\n"; - } - } - - # At this point, either it needs Sphinx or upgrade is recommended, - # both via pip - - if ($rec_sphinx_upgrade) { - if (!$virtualenv) { - print "Instead of install/upgrade Python Sphinx pkg, you could use pip/pypi with:\n\n"; - } else { - print "To upgrade Sphinx, use:\n\n"; - } - } else { - print "\nSphinx needs to be installed either:\n1) via pip/pypi with:\n\n"; - } - - $python_cmd = find_python_no_venv(); - - printf "\t$virtualenv_cmd $virtenv_dir\n"; - - printf "\t. $virtenv_dir/bin/activate\n"; - printf "\tpip install -r $requirement_file\n"; - deactivate_help(); - - printf "\n2) As a package with:\n"; - - my $old_need = $need; - my $old_optional = $optional; - %missing = (); - $pdf = 0; - $optional = 0; - $install = ""; - $verbose_warn_install = 0; - - add_package("python-sphinx", 0); - - check_distros(); - - $need = $old_need; - $optional = $old_optional; - - printf "\n Please note that Sphinx >= 3.0 will currently produce false-positive\n"; - printf " warning when the same name is used for more than one type (functions,\n"; - printf " structs, enums,...). This is known Sphinx bug. For more details, see:\n"; - printf "\thttps://github.com/sphinx-doc/sphinx/pull/8313\n"; -} - -sub check_needs() -{ - # Check if Sphinx is already accessible from current environment - check_sphinx(); - - if ($system_release) { - print "Detected OS: $system_release.\n"; - } else { - print "Unknown OS\n"; - } - printf "Sphinx version: %s\n\n", $cur_version if ($cur_version); - - # Check python command line, trying first python3 - $python_cmd = findprog("python3"); - $python_cmd = check_program("python", 0) if (!$python_cmd); - - # Check the type of virtual env, depending on Python version - if ($python_cmd) { - if ($virtualenv) { - my $tmp = qx($python_cmd --version 2>&1); - if ($tmp =~ m/(\d+\.)(\d+\.)/) { - if ($1 < 3) { - # Fail if it finds python2 (or worse) - die "Python 3 is required to build the kernel docs\n"; - } - if ($1 == 3 && $2 < 3) { - # Need Python 3.3 or upper for venv - $need_virtualenv = 1; - } - } else { - die "Warning: couldn't identify $python_cmd version!"; - } - } else { - add_package("python-sphinx", 0); - } - } - - my $venv_ver = recommend_sphinx_upgrade(); - - my $virtualenv_cmd; - - if ($need_pip) { - # Set virtualenv command line, if python < 3.3 - if ($need_virtualenv) { - $virtualenv_cmd = findprog("virtualenv-3"); - $virtualenv_cmd = findprog("virtualenv-3.5") if (!$virtualenv_cmd); - if (!$virtualenv_cmd) { - check_program("virtualenv", 0); - $virtualenv_cmd = "virtualenv"; - } - } else { - $virtualenv_cmd = "$python_cmd -m venv"; - check_python_module("ensurepip", 0); - } - } - - # Check for needed programs/tools - check_perl_module("Pod::Usage", 0); - check_python_module("yaml", 0); - check_program("make", 0); - check_program("gcc", 0); - check_program("dot", 1); - check_program("convert", 1); - - # Extra PDF files - should use 2 for is_optional - check_program("xelatex", 2) if ($pdf); - check_program("rsvg-convert", 2) if ($pdf); - check_program("latexmk", 2) if ($pdf); - - # Do distro-specific checks and output distro-install commands - check_distros(); - - if (!$python_cmd) { - if ($need == 1) { - die "Can't build as $need mandatory dependency is missing"; - } elsif ($need) { - die "Can't build as $need mandatory dependencies are missing"; - } - } - - # Check if sphinx-build is called sphinx-build-3 - if ($need_symlink) { - printf "\tsudo ln -sf %s /usr/bin/sphinx-build\n\n", - which("sphinx-build-3"); - } - - recommend_sphinx_version($virtualenv_cmd); - printf "\n"; - - print "All optional dependencies are met.\n" if (!$optional); - - if ($need == 1) { - die "Can't build as $need mandatory dependency is missing"; - } elsif ($need) { - die "Can't build as $need mandatory dependencies are missing"; - } - - print "Needed package dependencies are met.\n"; -} - -# -# Main -# - -while (@ARGV) { - my $arg = shift(@ARGV); - - if ($arg eq "--no-virtualenv") { - $virtualenv = 0; - } elsif ($arg eq "--no-pdf"){ - $pdf = 0; - } elsif ($arg eq "--version-check"){ - $version_check = 1; - } else { - print "Usage:\n\t$0 <--no-virtualenv> <--no-pdf> <--version-check>\n\n"; - print "Where:\n"; - print "\t--no-virtualenv\t- Recommend installing Sphinx instead of using a virtualenv\n"; - print "\t--version-check\t- if version is compatible, don't check for missing dependencies\n"; - print "\t--no-pdf\t- don't check for dependencies required to build PDF docs\n\n"; - exit -1; - } -} - -# -# Determine the system type. There's no standard unique way that would -# work with all distros with a minimal package install. So, several -# methods are used here. -# -# By default, it will use lsb_release function. If not available, it will -# fail back to reading the known different places where the distro name -# is stored -# - -$system_release = qx(lsb_release -d) if which("lsb_release"); -$system_release =~ s/Description:\s*// if ($system_release); -$system_release = catcheck("/etc/system-release") if !$system_release; -$system_release = catcheck("/etc/redhat-release") if !$system_release; -$system_release = catcheck("/etc/lsb-release") if !$system_release; -$system_release = catcheck("/etc/gentoo-release") if !$system_release; - -# This seems more common than LSB these days -if (!$system_release) { - my %os_var; - if (open IN, "cat /etc/os-release|") { - while () { - if (m/^([\w\d\_]+)=\"?([^\"]*)\"?\n/) { - $os_var{$1}=$2; - } - } - $system_release = $os_var{"NAME"}; - if (defined($os_var{"VERSION_ID"})) { - $system_release .= " " . $os_var{"VERSION_ID"} if (defined($os_var{"VERSION_ID"})); - } else { - $system_release .= " " . $os_var{"VERSION"}; - } - } -} -$system_release = catcheck("/etc/issue") if !$system_release; -$system_release =~ s/\s+$//; - -check_needs; From df4d2f966354297c94ba5e198533cc31548a12a8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:53 +0200 Subject: [PATCH 00750/11391] scripts: sphinx-pre-install: update mandatory system deps To build docs, gcc is not needed. Also, Kernel can be built nowadays with clang. So, drop it. On the other hand, which is needed. Add a system dependency for it. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/4ec979e4692c9e4acd6c31424c0e2f4bf5b80e71.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/sphinx-pre-install b/scripts/sphinx-pre-install index 7dfe5c2a6cc2..fc9dc45054d7 100755 --- a/scripts/sphinx-pre-install +++ b/scripts/sphinx-pre-install @@ -1476,7 +1476,7 @@ class SphinxDependencyChecker(MissingCheckers): self.check_perl_module("Pod::Usage", DepManager.SYSTEM_MANDATORY) self.check_program("make", DepManager.SYSTEM_MANDATORY) - self.check_program("gcc", DepManager.SYSTEM_MANDATORY) + self.check_program("which", DepManager.SYSTEM_MANDATORY) self.check_program("dot", DepManager.SYSTEM_OPTIONAL) self.check_program("convert", DepManager.SYSTEM_OPTIONAL) From 9f51a1d6966760dadf62ff1f62c614a342fb7e62 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:54 +0200 Subject: [PATCH 00751/11391] scripts: sphinx-pre-install: add support for RHEL8-based distros On RHEL8, only installing with a venv is supported, as there's no Sphinx package using Python 3.7 or upper. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/bcdde20edab07be6bf447eac18eecdd88c7f947c.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/scripts/sphinx-pre-install b/scripts/sphinx-pre-install index fc9dc45054d7..324baa98a395 100755 --- a/scripts/sphinx-pre-install +++ b/scripts/sphinx-pre-install @@ -691,7 +691,7 @@ class SphinxDependencyChecker(MissingCheckers): super().__init__(args, texlive) - self.need_pip = 0 + self.need_pip = False self.rec_sphinx_upgrade = 0 self.system_release = self.get_system_release() @@ -840,9 +840,15 @@ class SphinxDependencyChecker(MissingCheckers): # RHEL 8 uses Python 3.6, which is not compatible with # the build system anymore. Suggest Python 3.11 if rel == 8: - self.deps.add_package("python39", DepManager.SYSTEM_MANDATORY) + self.check_program("python3.9", DepManager.SYSTEM_MANDATORY) + progs["python3.9"] = "python39" + progs["yaml"] = "python39-pyyaml" + self.recommend_python = True + # There's no python39-sphinx package. Only pip is supported + self.package_supported = False + if not self.distro_msg: self.distro_msg = \ "Note: RHEL-based distros typically require extra repositories.\n" \ @@ -915,8 +921,9 @@ class SphinxDependencyChecker(MissingCheckers): # the build system anymore. Suggest Python 3.11 if rel == 15: if not self.which(self.python_cmd): + self.check_program("python3.11", DepManager.SYSTEM_MANDATORY) + progs["python3.11"] = "python311" self.recommend_python = True - self.deps.add_package(self.python_cmd, DepManager.SYSTEM_MANDATORY) progs.update({ "python-sphinx": "python311-Sphinx", @@ -1289,7 +1296,7 @@ class SphinxDependencyChecker(MissingCheckers): return self.latest_avail_ver # Either there are already a virtual env or a new one should be created - self.need_pip = 1 + self.need_pip = True if not self.latest_avail_ver: return None @@ -1344,10 +1351,11 @@ class SphinxDependencyChecker(MissingCheckers): """ if self.recommend_python: - print("\nPython version is incompatible with doc build.\n" \ - "Please upgrade it and re-run.\n") - return - + cur_ver = sys.version_info[:3] + if cur_ver < MIN_PYTHON_VERSION: + print(f"\nPython version {cur_ver} is incompatible with doc build.\n" \ + "Please upgrade it and re-run.\n") + return # Version is OK. Nothing to do. if self.cur_version != (0, 0, 0) and self.cur_version >= RECOMMENDED_VERSION: @@ -1467,7 +1475,6 @@ class SphinxDependencyChecker(MissingCheckers): if sys.version_info < MIN_PYTHON_VERSION: self.need_pip = False print("Warning: python version is not supported.") - else: virtualenv_cmd = f"{self.python_cmd} -m venv" self.check_python_module("ensurepip") From 491a99511eaf333855caf28170cfb3f6f4460b54 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:55 +0200 Subject: [PATCH 00752/11391] scripts: sphinx-pre-install: add a warning for Debian-based distros On Some Debian-based distros, ImageMagick package has a broken policy that causes LaTeX to fail while building docs. Add a note about that. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/628d01784e8c24e3d93c69c436f12398e00165b3.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/sphinx-pre-install b/scripts/sphinx-pre-install index 324baa98a395..09a337509b23 100755 --- a/scripts/sphinx-pre-install +++ b/scripts/sphinx-pre-install @@ -782,6 +782,11 @@ class SphinxDependencyChecker(MissingCheckers): self.check_program("dvipng", DepManager.PDF_MANDATORY) + if not self.distro_msg: + self.distro_msg = \ + "Note: ImageMagick is broken on some distros, affecting PDF output. For more details:\n" \ + "\thttps://askubuntu.com/questions/1158894/imagemagick-still-broken-using-with-usr-bin-convert" + return self.get_install_progs(progs, "apt-get install") def give_redhat_hints(self): @@ -1193,7 +1198,7 @@ class SphinxDependencyChecker(MissingCheckers): self.distro_msg = \ f"I don't know distro {self.system_release}.\n" \ "So, I can't provide you a hint with the install procedure.\n" \ - "There are likely missing dependencies.\n" + "There are likely missing dependencies." return self.get_install_progs(progs, None) From 6170b1eacac881af5732af78f33b76bd560c441b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2025 17:52:56 +0200 Subject: [PATCH 00753/11391] scripts: sphinx-pre-install: some adjustments related to venv While nothing was really needed for virtualenv to work on most distros, we had an issue with OpenMandriva. While checking for it, it was noticed that there was no check if python-virtualenv was installed. This didn't solve the issues we faced there: at least with the half-broken OpenMandriva Lx 4.0 docker container we used, ensurepip was not available anywhere, causing venv to fail. Add a distro-specific note about that. Note: at least at the time we did our tests, OpenMandriva Lx 4.0 docker was shipped with wrong dnf repositories. Also, there was no repos available for it anymore. So, we had to do some hacks to upgrade to 4.3 before being able to run any tests. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/e3a0e5eccd50eb506846e3e8487a2d9124ef83e2.1754992972.git.mchehab+huawei@kernel.org --- scripts/sphinx-pre-install | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/scripts/sphinx-pre-install b/scripts/sphinx-pre-install index 09a337509b23..b8474848df4e 100755 --- a/scripts/sphinx-pre-install +++ b/scripts/sphinx-pre-install @@ -983,6 +983,22 @@ class SphinxDependencyChecker(MissingCheckers): # Tested on OpenMandriva Lx 4.3 progs["convert"] = "imagemagick" progs["yaml"] = "python-pyyaml" + progs["python-virtualenv"] = "python-virtualenv" + progs["python-sphinx"] = "python-sphinx" + + self.check_program("python-virtualenv", DepManager.PYTHON_MANDATORY) + + # On my tests with openMandriva LX 4.0 docker image, upgraded + # to 4.3, python-virtualenv package is broken: it is missing + # ensurepip. Without it, the alternative would be to run: + # python3 -m venv --without-pip ~/sphinx_latest, but running + # pip there won't install sphinx at venv. + # + # Add a note about that. + + if not self.distro_msg: + self.distro_msg = \ + "Note: for venv, ensurepip could be broken, preventing its install method." else: packager_cmd = "urpmi" From 46ab4278e9bbb16e3dc8cec52fcdcadc95936a89 Mon Sep 17 00:00:00 2001 From: Shankari Anand Date: Wed, 16 Jul 2025 14:39:41 +0530 Subject: [PATCH 00754/11391] drm: nova: update ARef import from sync::aref Update nova to import `ARef` from `sync::aref` instead of `types`. This aligns with the ongoing effort to move `ARef` and `AlwaysRefCounted` to sync. Suggested-by: Benno Lossin Link: https://github.com/Rust-for-Linux/linux/issues/1173 Signed-off-by: Shankari Anand Link: https://lore.kernel.org/r/20250716090941.811418-1-shankari.ak0208@gmail.com [ Alter subject and commit message to be nova specific. - Danilo ] Signed-off-by: Danilo Krummrich --- drivers/gpu/drm/nova/driver.rs | 4 +++- drivers/gpu/drm/nova/gem.rs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nova/driver.rs b/drivers/gpu/drm/nova/driver.rs index b28b2e05cc15..91b7380f83ab 100644 --- a/drivers/gpu/drm/nova/driver.rs +++ b/drivers/gpu/drm/nova/driver.rs @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 -use kernel::{auxiliary, c_str, device::Core, drm, drm::gem, drm::ioctl, prelude::*, types::ARef}; +use kernel::{ + auxiliary, c_str, device::Core, drm, drm::gem, drm::ioctl, prelude::*, sync::aref::ARef, +}; use crate::file::File; use crate::gem::NovaObject; diff --git a/drivers/gpu/drm/nova/gem.rs b/drivers/gpu/drm/nova/gem.rs index 33b62d21400c..cd82773dab92 100644 --- a/drivers/gpu/drm/nova/gem.rs +++ b/drivers/gpu/drm/nova/gem.rs @@ -4,7 +4,7 @@ drm, drm::{gem, gem::BaseObject}, prelude::*, - types::ARef, + sync::aref::ARef, }; use crate::{ From 7cedf7345cce7a12c28cce8df0bdc8a62d4ca438 Mon Sep 17 00:00:00 2001 From: Hui Zhu Date: Thu, 31 Jul 2025 10:50:06 +0800 Subject: [PATCH 00755/11391] rust: alloc: kvec: add doc example for as_slice method Add a practical usage example to the documentation of KVec::as_slice() showing how to: Create a new KVec. Push elements into it. Convert to a slice via as_slice(). Co-developed-by: Geliang Tang Signed-off-by: Geliang Tang Signed-off-by: Hui Zhu Reviewed-by: Alice Ryhl Reviewed-by: Kunwu Chan Reviewed-by: David Gow Link: https://lore.kernel.org/r/4e7f396f38ed8a780f863384bfc3d7de135ef3ea.1753929369.git.zhuhui@kylinos.cn Signed-off-by: Danilo Krummrich --- rust/kernel/alloc/kvec.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs index 3c72e0bdddb8..fa04cc0987d6 100644 --- a/rust/kernel/alloc/kvec.rs +++ b/rust/kernel/alloc/kvec.rs @@ -224,6 +224,16 @@ unsafe fn dec_len(&mut self, count: usize) -> &mut [T] { } /// Returns a slice of the entire vector. + /// + /// # Examples + /// + /// ``` + /// let mut v = KVec::new(); + /// v.push(1, GFP_KERNEL)?; + /// v.push(2, GFP_KERNEL)?; + /// assert_eq!(v.as_slice(), &[1, 2]); + /// # Ok::<(), Error>(()) + /// ``` #[inline] pub fn as_slice(&self) -> &[T] { self From a55498c7d8a651ca5c7b8169e84d48af77e60723 Mon Sep 17 00:00:00 2001 From: Hui Zhu Date: Thu, 31 Jul 2025 10:50:07 +0800 Subject: [PATCH 00756/11391] rust: alloc: kvec: simplify KUnit test module name to "rust_kvec" Remove redundant "_kunit" suffix from test module name. The naming is now consistent with other Rust components as the test context is already implied by the #[kunit_tests] macro and test module location. Co-developed-by: Geliang Tang Signed-off-by: Geliang Tang Signed-off-by: Hui Zhu Reviewed-by: David Gow Link: https://lore.kernel.org/r/4eb554c3bf03dd4f9e6dea659497938baab61dba.1753929369.git.zhuhui@kylinos.cn Signed-off-by: Danilo Krummrich --- rust/kernel/alloc/kvec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs index fa04cc0987d6..7316f48aaa90 100644 --- a/rust/kernel/alloc/kvec.rs +++ b/rust/kernel/alloc/kvec.rs @@ -1304,7 +1304,7 @@ fn drop(&mut self) { } } -#[macros::kunit_tests(rust_kvec_kunit)] +#[macros::kunit_tests(rust_kvec)] mod tests { use super::*; use crate::prelude::*; From d903f5c60a0ea95aa03d5158d38bb057da6eae3e Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Mon, 4 Aug 2025 17:20:40 -0500 Subject: [PATCH 00757/11391] 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 00758/11391] 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 00759/11391] 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 37533933bfe92cd5a99ef4743f31dac62ccc8de0 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 13 Aug 2025 18:15:01 +0200 Subject: [PATCH 00760/11391] regulator: 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-16-wsa+renesas@sang-engineering.com Signed-off-by: Mark Brown --- drivers/regulator/qcom-refgen-regulator.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/regulator/qcom-refgen-regulator.c b/drivers/regulator/qcom-refgen-regulator.c index cfa72ce85bc8..299ac3c8c3bc 100644 --- a/drivers/regulator/qcom-refgen-regulator.c +++ b/drivers/regulator/qcom-refgen-regulator.c @@ -94,7 +94,6 @@ static const struct regmap_config qcom_refgen_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .fast_io = true, }; static int qcom_refgen_probe(struct platform_device *pdev) From 4c70fb2624ab1588faa58dcd407d4c61d64b288d Mon Sep 17 00:00:00 2001 From: Chen Ridong Date: Wed, 13 Aug 2025 08:29:01 +0000 Subject: [PATCH 00761/11391] cpuset: remove redundant CS_ONLINE flag The CS_ONLINE flag was introduced prior to the CSS_ONLINE flag in the cpuset subsystem. Currently, the flag setting sequence is as follows: 1. cpuset_css_online() sets CS_ONLINE 2. css->flags gets CSS_ONLINE set ... 3. cgroup->kill_css sets CSS_DYING 4. cpuset_css_offline() clears CS_ONLINE 5. css->flags clears CSS_ONLINE The is_cpuset_online() check currently occurs between steps 1 and 3. However, it would be equally safe to perform this check between steps 2 and 3, as CSS_ONLINE provides the same synchronization guarantee as CS_ONLINE. Since CS_ONLINE is redundant with CSS_ONLINE and provides no additional synchronization benefits, we can safely remove it to simplify the code. Signed-off-by: Chen Ridong Acked-by: Waiman Long Signed-off-by: Tejun Heo --- include/linux/cgroup.h | 5 +++++ kernel/cgroup/cpuset-internal.h | 3 +-- kernel/cgroup/cpuset.c | 4 +--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index b18fb5fcb38e..ae73dbb19165 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -354,6 +354,11 @@ static inline bool css_is_dying(struct cgroup_subsys_state *css) return css->flags & CSS_DYING; } +static inline bool css_is_online(struct cgroup_subsys_state *css) +{ + return css->flags & CSS_ONLINE; +} + static inline bool css_is_self(struct cgroup_subsys_state *css) { if (css == &css->cgroup->self) { diff --git a/kernel/cgroup/cpuset-internal.h b/kernel/cgroup/cpuset-internal.h index 383963e28ac6..75b3aef39231 100644 --- a/kernel/cgroup/cpuset-internal.h +++ b/kernel/cgroup/cpuset-internal.h @@ -38,7 +38,6 @@ enum prs_errcode { /* bits in struct cpuset flags field */ typedef enum { - CS_ONLINE, CS_CPU_EXCLUSIVE, CS_MEM_EXCLUSIVE, CS_MEM_HARDWALL, @@ -202,7 +201,7 @@ static inline struct cpuset *parent_cs(struct cpuset *cs) /* convenient tests for these bits */ static inline bool is_cpuset_online(struct cpuset *cs) { - return test_bit(CS_ONLINE, &cs->flags) && !css_is_dying(&cs->css); + return css_is_online(&cs->css) && !css_is_dying(&cs->css); } static inline int is_cpu_exclusive(const struct cpuset *cs) diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index 27adb04df675..3466ebbf1016 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -207,7 +207,7 @@ static inline void notify_partition_change(struct cpuset *cs, int old_prs) * parallel, we may leave an offline CPU in cpu_allowed or some other masks. */ static struct cpuset top_cpuset = { - .flags = BIT(CS_ONLINE) | BIT(CS_CPU_EXCLUSIVE) | + .flags = BIT(CS_CPU_EXCLUSIVE) | BIT(CS_MEM_EXCLUSIVE) | BIT(CS_SCHED_LOAD_BALANCE), .partition_root_state = PRS_ROOT, .relax_domain_level = -1, @@ -3496,7 +3496,6 @@ static int cpuset_css_online(struct cgroup_subsys_state *css) cpus_read_lock(); mutex_lock(&cpuset_mutex); - set_bit(CS_ONLINE, &cs->flags); if (is_spread_page(parent)) set_bit(CS_SPREAD_PAGE, &cs->flags); if (is_spread_slab(parent)) @@ -3571,7 +3570,6 @@ static void cpuset_css_offline(struct cgroup_subsys_state *css) cpuset_update_flag(CS_SCHED_LOAD_BALANCE, cs, 0); cpuset_dec(); - clear_bit(CS_ONLINE, &cs->flags); mutex_unlock(&cpuset_mutex); cpus_read_unlock(); From d0a2dee7d4585a7ebab45bf63eebeb8b6944e88f Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 13 Aug 2025 07:11:01 +0200 Subject: [PATCH 00762/11391] 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 00763/11391] 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 00764/11391] 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 00765/11391] 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 00766/11391] 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 @@ static void efx_io_resume(struct pci_dev *pdev) /* 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 @@ static void ef4_io_resume(struct pci_dev *pdev) /* 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 @@ static void efx_io_resume(struct pci_dev *pdev) /* 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 00767/11391] 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 00768/11391] 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 0e62438e476494a1891a8822b9785bc6e73e9c3f Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Wed, 13 Aug 2025 17:39:01 +0800 Subject: [PATCH 00769/11391] ASoC: Intel: sst: Remove redundant semicolons Remove unnecessary semicolons. Signed-off-by: Liao Yuanhong Link: https://patch.msgid.link/20250813093903.551388-1-liaoyuanhong@vivo.com Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/atom/sst/sst.c b/sound/soc/intel/atom/sst/sst.c index e0357d257c6c..3c47c8de04b7 100644 --- a/sound/soc/intel/atom/sst/sst.c +++ b/sound/soc/intel/atom/sst/sst.c @@ -64,7 +64,7 @@ static irqreturn_t intel_sst_interrupt_mrfld(int irq, void *context) header.p.header_high.part.done = 0; sst_shim_write64(drv->shim, drv->ipc_reg.ipcx, header.full); - /* write 1 to clear status register */; + /* write 1 to clear status register */ isr.part.done_interrupt = 1; sst_shim_write64(drv->shim, SST_ISRX, isr.full); spin_unlock(&drv->ipc_spin_lock); From ab81f2f79c683c94bac622aafafbe8232e547159 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 13 Aug 2025 17:56:25 +0200 Subject: [PATCH 00770/11391] 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 d4b7080be277ca400b443ac211b79450f4befddc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 13 Aug 2025 08:16:56 +0200 Subject: [PATCH 00771/11391] kbuild: uapi: rerun header tests when headers_check.pl changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the checks change they need to be rerun. Add a Makefile dependency so this happens. Signed-off-by: Thomas Weißschuh Reviewed-by: Nicolas Schier Link: https://lore.kernel.org/r/20250813-kbuild-hdrtest-fixes-v2-1-8a7921ca3a03@linutronix.de Signed-off-by: Nathan Chancellor --- usr/include/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr/include/Makefile b/usr/include/Makefile index f02f41941b60..c7f164952b33 100644 --- a/usr/include/Makefile +++ b/usr/include/Makefile @@ -85,7 +85,7 @@ quiet_cmd_hdrtest = HDRTEST $< $(PERL) $(src)/headers_check.pl $(obj) $<; \ touch $@ -$(obj)/%.hdrtest: $(obj)/%.h FORCE +$(obj)/%.hdrtest: $(obj)/%.h $(src)/headers_check.pl FORCE $(call if_changed_dep,hdrtest) # Since GNU Make 4.3, $(patsubst $(obj)/%/,%,$(wildcard $(obj)/*/)) works. From 3788d69db18d310afa9892642520fb9b47edf829 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 13 Aug 2025 08:16:57 +0200 Subject: [PATCH 00772/11391] kbuild: uapi: fail header test on compiler warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Compiler warnings also indicate issues with the headers. Make sure they don't go unnoticed. Signed-off-by: Thomas Weißschuh Reviewed-by: Nicolas Schier Link: https://lore.kernel.org/r/20250813-kbuild-hdrtest-fixes-v2-2-8a7921ca3a03@linutronix.de Signed-off-by: Nathan Chancellor --- usr/include/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr/include/Makefile b/usr/include/Makefile index c7f164952b33..61a7dd4fc05f 100644 --- a/usr/include/Makefile +++ b/usr/include/Makefile @@ -80,7 +80,7 @@ always-y := $(patsubst $(obj)/%.h,%.hdrtest, $(shell find $(obj) -name '*.h' 2>/ # Include the header twice to detect missing include guard. quiet_cmd_hdrtest = HDRTEST $< cmd_hdrtest = \ - $(CC) $(c_flags) -fsyntax-only -x c /dev/null \ + $(CC) $(c_flags) -fsyntax-only -Werror -x c /dev/null \ $(if $(filter-out $(no-header-test), $*.h), -include $< -include $<); \ $(PERL) $(src)/headers_check.pl $(obj) $<; \ touch $@ From 24b1bd64ee4030a306f74811c346db4042f4c98a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 13 Aug 2025 08:16:58 +0200 Subject: [PATCH 00773/11391] kbuild: uapi: upgrade warning on asm/types.h inclusion to error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No usages of '#include in the UAPI headers exist anymore. Make sure it stays this way. Add a semicolon to the end of the previous printf call to keep the syntax valid. Signed-off-by: Thomas Weißschuh Reviewed-by: Nicolas Schier Link: https://lore.kernel.org/r/20250813-kbuild-hdrtest-fixes-v2-3-8a7921ca3a03@linutronix.de Signed-off-by: Nathan Chancellor --- usr/include/headers_check.pl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/usr/include/headers_check.pl b/usr/include/headers_check.pl index 2b70bfa5558e..36307a137cc1 100755 --- a/usr/include/headers_check.pl +++ b/usr/include/headers_check.pl @@ -98,9 +98,8 @@ sub check_asm_types if ($line =~ m/^\s*#\s*include\s+/) { $linux_asm_types = 1; printf STDERR "$filename:$lineno: " . - "include of is preferred over \n" - # Warn until headers are all fixed - #$ret = 1; + "include of is preferred over \n"; + $ret = 1; } } From c3a9d74ee413bdb3007b39e62418f9757a0642e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 13 Aug 2025 08:16:59 +0200 Subject: [PATCH 00774/11391] kbuild: uapi: upgrade check_sizetypes() warning to error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No problematic type usages exist anymore. Make sure it stays this way. Signed-off-by: Thomas Weißschuh Reviewed-by: Nicolas Schier Link: https://lore.kernel.org/r/20250813-kbuild-hdrtest-fixes-v2-4-8a7921ca3a03@linutronix.de Signed-off-by: Nathan Chancellor --- usr/include/headers_check.pl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/usr/include/headers_check.pl b/usr/include/headers_check.pl index 36307a137cc1..36349b21cef5 100755 --- a/usr/include/headers_check.pl +++ b/usr/include/headers_check.pl @@ -159,7 +159,6 @@ sub check_sizetypes "found __[us]{8,16,32,64} type " . "without #include \n"; $linux_types = 2; - # Warn until headers are all fixed - #$ret = 1; + $ret = 1; } } From b8d762c9830538c743066cbfb1f8c8a40f8e9d58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 13 Aug 2025 08:17:00 +0200 Subject: [PATCH 00775/11391] kbuild: uapi: upgrade check_declarations() warning to error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No problematic declarations exist anymore. Make sure it stays this way. Signed-off-by: Thomas Weißschuh Reviewed-by: Nicolas Schier Link: https://lore.kernel.org/r/20250813-kbuild-hdrtest-fixes-v2-5-8a7921ca3a03@linutronix.de Signed-off-by: Nathan Chancellor --- usr/include/headers_check.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/usr/include/headers_check.pl b/usr/include/headers_check.pl index 36349b21cef5..21c2fb9520e6 100755 --- a/usr/include/headers_check.pl +++ b/usr/include/headers_check.pl @@ -74,6 +74,7 @@ sub check_declarations printf STDERR "$filename:$lineno: " . "userspace cannot reference function or " . "variable defined in the kernel\n"; + $ret = 1; } } From 1ad82f9db13d85667366044acdfb02009d576c5a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 1 Aug 2025 20:03:35 +0300 Subject: [PATCH 00776/11391] 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 00777/11391] 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 48124569bbc6bfda1df3e9ee17b19d559f4b1aa3 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 13 Aug 2025 18:15:05 +0200 Subject: [PATCH 00778/11391] spi: 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-20-wsa+renesas@sang-engineering.com Signed-off-by: Mark Brown --- drivers/spi/spi-altera-platform.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/spi-altera-platform.c b/drivers/spi/spi-altera-platform.c index 585393802e9f..e163774fd65b 100644 --- a/drivers/spi/spi-altera-platform.c +++ b/drivers/spi/spi-altera-platform.c @@ -30,7 +30,6 @@ static const struct regmap_config spi_altera_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .fast_io = true, }; static int altera_spi_probe(struct platform_device *pdev) From 8ba38a7a9a699905b84fa97578a8291010dec273 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Tue, 24 Jun 2025 17:59:18 +0300 Subject: [PATCH 00779/11391] 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 00780/11391] 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 00781/11391] 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 2caa6b88e0ba0231fb4ff0ba8e73cedd5fb81fc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Mon, 11 Aug 2025 14:08:04 +0200 Subject: [PATCH 00782/11391] bpf: Don't use %pK through printk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the past %pK was preferable to %p as it would not leak raw pointer values into the kernel log. Since commit ad67b74d2469 ("printk: hash addresses printed with %p") the regular %p has been improved to avoid this issue. Furthermore, restricted pointers ("%pK") were never meant to be used through printk(). They can still unintentionally leak raw pointers or acquire sleeping locks in atomic contexts. Switch to the regular pointer formatting which is safer and easier to reason about. Signed-off-by: Thomas Weißschuh Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20250811-restricted-pointers-bpf-v1-1-a1d7cc3cb9e7@linutronix.de --- include/linux/filter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/filter.h b/include/linux/filter.h index 1e7fd3ee759e..52fecb7a1fe3 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -1296,7 +1296,7 @@ void bpf_jit_prog_release_other(struct bpf_prog *fp, struct bpf_prog *fp_other); static inline void bpf_jit_dump(unsigned int flen, unsigned int proglen, u32 pass, void *image) { - pr_err("flen=%u proglen=%u pass=%u image=%pK from=%s pid=%d\n", flen, + pr_err("flen=%u proglen=%u pass=%u image=%p from=%s pid=%d\n", flen, proglen, pass, image, current->comm, task_pid_nr(current)); if (image) From 07866544e410e4c895a729971e4164861b41fad5 Mon Sep 17 00:00:00 2001 From: Amery Hung Date: Tue, 12 Aug 2025 10:50:39 -0700 Subject: [PATCH 00783/11391] selftests/bpf: Copy test_kmods when installing selftest Commit d6212d82bf26 ("selftests/bpf: Consolidate kernel modules into common directory") consolidated the Makefile of test_kmods. However, since it removed test_kmods from TEST_GEN_PROGS_EXTENDED, the kernel modules required by bpf selftests are now missing from kselftest_install when "make install". Fix it by adding test_kmod to TEST_GEN_FILES. Fixes: d6212d82bf26 ("selftests/bpf: Consolidate kernel modules into common directory") Signed-off-by: Amery Hung Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20250812175039.2323570-1-ameryhung@gmail.com --- tools/testing/selftests/bpf/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 4863106034df..77794efc020e 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -137,7 +137,7 @@ TEST_GEN_PROGS_EXTENDED = \ xdping \ xskxceiver -TEST_GEN_FILES += liburandom_read.so urandom_read sign-file uprobe_multi +TEST_GEN_FILES += $(TEST_KMODS) liburandom_read.so urandom_read sign-file uprobe_multi ifneq ($(V),1) submake_extras := feature_display=0 From 6896c2449a1858acb643014894d01b3a1223d4e5 Mon Sep 17 00:00:00 2001 From: Tiezhu Yang Date: Mon, 11 Aug 2025 15:35:04 +0800 Subject: [PATCH 00784/11391] net: stmmac: Check stmmac_hw_setup() in stmmac_resume() stmmac_hw_setup() may return 0 on success and an appropriate negative integer as defined in errno.h file on failure, just check it and then return early if failed in stmmac_resume(). Signed-off-by: Tiezhu Yang Reviewed-by: Maxime Chevallier Reviewed-by: Huacai Chen Link: https://patch.msgid.link/20250811073506.27513-2-yangtiezhu@loongson.cn Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 4a82045ea6eb..9a77390b7f9d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -7984,7 +7984,14 @@ int stmmac_resume(struct device *dev) stmmac_free_tx_skbufs(priv); stmmac_clear_descriptors(priv, &priv->dma_conf); - stmmac_hw_setup(ndev, false); + ret = stmmac_hw_setup(ndev, false); + if (ret < 0) { + netdev_err(priv->dev, "%s: Hw setup failed\n", __func__); + mutex_unlock(&priv->lock); + rtnl_unlock(); + return ret; + } + stmmac_init_coalesce(priv); phylink_rx_clk_stop_block(priv->phylink); stmmac_set_rx_mode(ndev); From 139235103f6039c2c77cb8f51cb2e7e610fe0114 Mon Sep 17 00:00:00 2001 From: Tiezhu Yang Date: Mon, 11 Aug 2025 15:35:05 +0800 Subject: [PATCH 00785/11391] net: stmmac: Change first parameter of fix_soc_reset() In order to use netdev_err() to print message in the callback function of fix_soc_reset(), change fix_soc_reset() to have "struct stmmac_priv *" as its first parameter. This is preparation for later patch, no functionality change. Suggested-by: Andrew Lunn Signed-off-by: Tiezhu Yang Link: https://patch.msgid.link/20250811073506.27513-3-yangtiezhu@loongson.cn Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c | 6 +++--- drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c | 2 +- drivers/net/ethernet/stmicro/stmmac/hwif.c | 2 +- include/linux/stmmac.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c index 889e2bb6f7f5..c2d9e89f0063 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c @@ -49,7 +49,7 @@ struct imx_dwmac_ops { u32 flags; bool mac_rgmii_txclk_auto_adj; - int (*fix_soc_reset)(void *priv, void __iomem *ioaddr); + int (*fix_soc_reset)(struct stmmac_priv *priv, void __iomem *ioaddr); int (*set_intf_mode)(struct plat_stmmacenet_data *plat_dat); void (*fix_mac_speed)(void *priv, int speed, unsigned int mode); }; @@ -265,9 +265,9 @@ static void imx93_dwmac_fix_speed(void *priv, int speed, unsigned int mode) writel(old_ctrl, dwmac->base_addr + MAC_CTRL_REG); } -static int imx_dwmac_mx93_reset(void *priv, void __iomem *ioaddr) +static int imx_dwmac_mx93_reset(struct stmmac_priv *priv, void __iomem *ioaddr) { - struct plat_stmmacenet_data *plat_dat = priv; + struct plat_stmmacenet_data *plat_dat = priv->plat; u32 value = readl(ioaddr + DMA_BUS_MODE); /* DMA SW reset */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c index 5769165ee5ba..4c477d6ce1e6 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c @@ -509,7 +509,7 @@ static int loongson_dwmac_acpi_config(struct pci_dev *pdev, } /* Loongson's DWMAC device may take nearly two seconds to complete DMA reset */ -static int loongson_dwmac_fix_reset(void *priv, void __iomem *ioaddr) +static int loongson_dwmac_fix_reset(struct stmmac_priv *priv, void __iomem *ioaddr) { u32 value = readl(ioaddr + DMA_BUS_MODE); diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c b/drivers/net/ethernet/stmicro/stmmac/hwif.c index 99635b37044a..3f7c765dcb79 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.c +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c @@ -100,7 +100,7 @@ int stmmac_reset(struct stmmac_priv *priv, void __iomem *ioaddr) return -EINVAL; if (plat && plat->fix_soc_reset) - return plat->fix_soc_reset(plat, ioaddr); + return plat->fix_soc_reset(priv, ioaddr); return stmmac_do_callback(priv, dma, reset, ioaddr); } diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h index 22c24dacbc65..e284f04964bf 100644 --- a/include/linux/stmmac.h +++ b/include/linux/stmmac.h @@ -238,7 +238,7 @@ struct plat_stmmacenet_data { int (*set_clk_tx_rate)(void *priv, struct clk *clk_tx_i, phy_interface_t interface, int speed); void (*fix_mac_speed)(void *priv, int speed, unsigned int mode); - int (*fix_soc_reset)(void *priv, void __iomem *ioaddr); + int (*fix_soc_reset)(struct stmmac_priv *priv, void __iomem *ioaddr); int (*serdes_powerup)(struct net_device *ndev, void *priv); void (*serdes_powerdown)(struct net_device *ndev, void *priv); int (*mac_finish)(struct net_device *ndev, From bfd9d893edfa8278064c4e914e29cf98e290532e Mon Sep 17 00:00:00 2001 From: Tiezhu Yang Date: Mon, 11 Aug 2025 15:35:06 +0800 Subject: [PATCH 00786/11391] net: stmmac: Return early if invalid in loongson_dwmac_fix_reset() If the MAC controller does not connect to any PHY interface, there is a missing clock, then the DMA reset fails. For this case, the DMA_BUS_MODE_SFT_RESET bit is 1 before software reset, just print an error message which gives a hint the PHY clock is missing, and then return -EINVAL immediately to avoid waiting for the timeout when the DMA reset fails in loongson_dwmac_fix_reset(). With this patch, for the normal end user, the computer start faster with reducing boot time for 2 seconds on the specified mainboard. Signed-off-by: Tiezhu Yang Link: https://patch.msgid.link/20250811073506.27513-4-yangtiezhu@loongson.cn Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c index 4c477d6ce1e6..6fca0fca4892 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c @@ -513,6 +513,11 @@ static int loongson_dwmac_fix_reset(struct stmmac_priv *priv, void __iomem *ioad { u32 value = readl(ioaddr + DMA_BUS_MODE); + if (value & DMA_BUS_MODE_SFT_RESET) { + netdev_err(priv->dev, "the PHY clock is missing\n"); + return -EINVAL; + } + value |= DMA_BUS_MODE_SFT_RESET; writel(value, ioaddr + DMA_BUS_MODE); From 4d18083d6b2c02e89d833c92c3fb79e2fe1e6795 Mon Sep 17 00:00:00 2001 From: Wang Liang Date: Tue, 12 Aug 2025 09:59:29 +0800 Subject: [PATCH 00787/11391] vsock: use sizeof(struct sockaddr_storage) instead of magic value Previous commit 230b183921ec ("net: Use standard structures for generic socket address structures.") use 'struct sockaddr_storage address;' to replace 'char address[MAX_SOCK_ADDR];'. The macro MAX_SOCK_ADDR is removed by commit 01893c82b4e6 ("net: Remove MAX_SOCK_ADDR constant"). The comment in vsock_getname() is outdated, use sizeof(struct sockaddr_storage) instead of magic value 128. Signed-off-by: Wang Liang Link: https://patch.msgid.link/20250812015929.1419896-1-wangliang74@huawei.com Signed-off-by: Jakub Kicinski --- net/vmw_vsock/af_vsock.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index ead6a3c14b87..f7b2d61d1d16 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -1028,12 +1028,7 @@ static int vsock_getname(struct socket *sock, vm_addr = &vsk->local_addr; } - /* sys_getsockname() and sys_getpeername() pass us a - * MAX_SOCK_ADDR-sized buffer and don't set addr_len. Unfortunately - * that macro is defined in socket.c instead of .h, so we hardcode its - * value here. - */ - BUILD_BUG_ON(sizeof(*vm_addr) > 128); + BUILD_BUG_ON(sizeof(*vm_addr) > sizeof(struct sockaddr_storage)); memcpy(addr, vm_addr, sizeof(*vm_addr)); err = sizeof(*vm_addr); From 96326447d466ca62b713f660cfc73ef7879151a0 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 12 Aug 2025 06:57:23 +0200 Subject: [PATCH 00788/11391] net: mediatek: wed: Introduce MT7992 WED support to MT7988 SoC Introduce the second WDMA RX ring in WED driver for MT7988 SoC since the Mediatek MT7992 WiFi chipset supports two separated WDMA rings. Add missing MT7988 configurations to properly support WED for MT7992 in MT76 driver. Co-developed-by: Rex Lu Signed-off-by: Rex Lu Signed-off-by: Lorenzo Bianconi Link: https://patch.msgid.link/20250812-mt7992-wed-support-v3-1-9ada78a819a4@kernel.org Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mediatek/mtk_wed.c | 33 +++++++++++++++---- drivers/net/ethernet/mediatek/mtk_wed.h | 2 +- .../net/wireless/mediatek/mt76/mt7915/mmio.c | 6 ++-- .../net/wireless/mediatek/mt76/mt7996/mmio.c | 12 +++---- include/linux/soc/mediatek/mtk_wed.h | 2 +- 5 files changed, 38 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c index 0a80d8f8cff7..3dbb113b792c 100644 --- a/drivers/net/ethernet/mediatek/mtk_wed.c +++ b/drivers/net/ethernet/mediatek/mtk_wed.c @@ -59,7 +59,9 @@ struct mtk_wed_flow_block_priv { static const struct mtk_wed_soc_data mt7622_data = { .regmap = { .tx_bm_tkid = 0x088, - .wpdma_rx_ring0 = 0x770, + .wpdma_rx_ring = { + 0x770, + }, .reset_idx_tx_mask = GENMASK(3, 0), .reset_idx_rx_mask = GENMASK(17, 16), }, @@ -70,7 +72,9 @@ static const struct mtk_wed_soc_data mt7622_data = { static const struct mtk_wed_soc_data mt7986_data = { .regmap = { .tx_bm_tkid = 0x0c8, - .wpdma_rx_ring0 = 0x770, + .wpdma_rx_ring = { + 0x770, + }, .reset_idx_tx_mask = GENMASK(1, 0), .reset_idx_rx_mask = GENMASK(7, 6), }, @@ -81,7 +85,10 @@ static const struct mtk_wed_soc_data mt7986_data = { static const struct mtk_wed_soc_data mt7988_data = { .regmap = { .tx_bm_tkid = 0x0c8, - .wpdma_rx_ring0 = 0x7d0, + .wpdma_rx_ring = { + 0x7d0, + 0x7d8, + }, .reset_idx_tx_mask = GENMASK(1, 0), .reset_idx_rx_mask = GENMASK(7, 6), }, @@ -621,8 +628,8 @@ mtk_wed_amsdu_init(struct mtk_wed_device *dev) return ret; } - /* eagle E1 PCIE1 tx ring 22 flow control issue */ - if (dev->wlan.id == 0x7991) + /* Kite and Eagle E1 PCIE1 tx ring 22 flow control issue */ + if (dev->wlan.id == 0x7991 || dev->wlan.id == 0x7992) wed_clr(dev, MTK_WED_AMSDU_FIFO, MTK_WED_AMSDU_IS_PRIOR0_RING); wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_TX_AMSDU_EN); @@ -1239,7 +1246,11 @@ mtk_wed_set_wpdma(struct mtk_wed_device *dev) return; wed_w32(dev, MTK_WED_WPDMA_RX_GLO_CFG, dev->wlan.wpdma_rx_glo); - wed_w32(dev, dev->hw->soc->regmap.wpdma_rx_ring0, dev->wlan.wpdma_rx); + wed_w32(dev, dev->hw->soc->regmap.wpdma_rx_ring[0], + dev->wlan.wpdma_rx[0]); + if (mtk_wed_is_v3_or_greater(dev->hw)) + wed_w32(dev, dev->hw->soc->regmap.wpdma_rx_ring[1], + dev->wlan.wpdma_rx[1]); if (!dev->wlan.hw_rro) return; @@ -2323,6 +2334,16 @@ mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask) if (!dev->rx_wdma[i].desc) mtk_wed_wdma_rx_ring_setup(dev, i, 16, false); + if (dev->wlan.hw_rro) { + for (i = 0; i < MTK_WED_RX_PAGE_QUEUES; i++) { + u32 addr = MTK_WED_RRO_MSDU_PG_CTRL0(i) + + MTK_WED_RING_OFS_COUNT; + + if (!wed_r32(dev, addr)) + wed_w32(dev, addr, 1); + } + } + mtk_wed_hw_init(dev); mtk_wed_configure_irq(dev, irq_mask); diff --git a/drivers/net/ethernet/mediatek/mtk_wed.h b/drivers/net/ethernet/mediatek/mtk_wed.h index c1f0479d7a71..b49aee9a8b65 100644 --- a/drivers/net/ethernet/mediatek/mtk_wed.h +++ b/drivers/net/ethernet/mediatek/mtk_wed.h @@ -17,7 +17,7 @@ struct mtk_wed_wo; struct mtk_wed_soc_data { struct { u32 tx_bm_tkid; - u32 wpdma_rx_ring0; + u32 wpdma_rx_ring[MTK_WED_RX_QUEUES]; u32 reset_idx_tx_mask; u32 reset_idx_rx_mask; } regmap; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c index 4a82f8e4c118..36488aa6cc20 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c @@ -664,8 +664,8 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr, MT_RXQ_WED_RING_BASE; wed->wlan.wpdma_rx_glo = pci_resource_start(pci_dev, 0) + MT_WPDMA_GLO_CFG; - wed->wlan.wpdma_rx = pci_resource_start(pci_dev, 0) + - MT_RXQ_WED_DATA_RING_BASE; + wed->wlan.wpdma_rx[0] = pci_resource_start(pci_dev, 0) + + MT_RXQ_WED_DATA_RING_BASE; } else { struct platform_device *plat_dev = pdev_ptr; struct resource *res; @@ -687,7 +687,7 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr, wed->wlan.wpdma_tx = res->start + MT_TXQ_WED_RING_BASE; wed->wlan.wpdma_txfree = res->start + MT_RXQ_WED_RING_BASE; wed->wlan.wpdma_rx_glo = res->start + MT_WPDMA_GLO_CFG; - wed->wlan.wpdma_rx = res->start + MT_RXQ_WED_DATA_RING_BASE; + wed->wlan.wpdma_rx[0] = res->start + MT_RXQ_WED_DATA_RING_BASE; } wed->wlan.nbuf = MT7915_HW_TOKEN_SIZE; wed->wlan.tx_tbit[0] = is_mt7915(&dev->mt76) ? 4 : 30; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c index 30b40f4a91be..fb2428a9b877 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c @@ -503,9 +503,9 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, } wed->wlan.wpdma_rx_glo = wed->wlan.phy_base + hif1_ofs + MT_WFDMA0_GLO_CFG; - wed->wlan.wpdma_rx = wed->wlan.phy_base + hif1_ofs + - MT_RXQ_RING_BASE(MT7996_RXQ_BAND0) + - MT7996_RXQ_BAND0 * MT_RING_SIZE; + wed->wlan.wpdma_rx[0] = wed->wlan.phy_base + hif1_ofs + + MT_RXQ_RING_BASE(MT7996_RXQ_BAND0) + + MT7996_RXQ_BAND0 * MT_RING_SIZE; wed->wlan.id = MT7996_DEVICE_ID_2; wed->wlan.tx_tbit[0] = ffs(MT_INT_TX_DONE_BAND2) - 1; @@ -518,9 +518,9 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, wed->wlan.wpdma_rx_glo = wed->wlan.phy_base + MT_WFDMA0_GLO_CFG; - wed->wlan.wpdma_rx = wed->wlan.phy_base + - MT_RXQ_RING_BASE(MT7996_RXQ_BAND0) + - MT7996_RXQ_BAND0 * MT_RING_SIZE; + wed->wlan.wpdma_rx[0] = wed->wlan.phy_base + + MT_RXQ_RING_BASE(MT7996_RXQ_BAND0) + + MT7996_RXQ_BAND0 * MT_RING_SIZE; wed->wlan.wpdma_rx_rro[0] = wed->wlan.phy_base + MT_RXQ_RING_BASE(MT7996_RXQ_RRO_BAND0) + diff --git a/include/linux/soc/mediatek/mtk_wed.h b/include/linux/soc/mediatek/mtk_wed.h index d8949a4ed0dc..c4ff6bab176d 100644 --- a/include/linux/soc/mediatek/mtk_wed.h +++ b/include/linux/soc/mediatek/mtk_wed.h @@ -147,7 +147,7 @@ struct mtk_wed_device { u32 wpdma_tx; u32 wpdma_txfree; u32 wpdma_rx_glo; - u32 wpdma_rx; + u32 wpdma_rx[MTK_WED_RX_QUEUES]; u32 wpdma_rx_rro[MTK_WED_RX_QUEUES]; u32 wpdma_rx_pg; From 5e88777a382480d0b1f7eafb6d0fb680ec7a40bb Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 12 Aug 2025 10:18:10 +0300 Subject: [PATCH 00789/11391] selftests: forwarding: Add a test for FDB activity notification control Test various aspects of FDB activity notification control: * Transitioning of an FDB entry from inactive to active state. * Transitioning of an FDB entry from active to inactive state. * Avoiding the resetting of an FDB entry's last activity time (i.e., "updated" time) using the "norefresh" keyword. Reviewed-by: Petr Machata Signed-off-by: Ido Schimmel Acked-by: Nikolay Aleksandrov Link: https://patch.msgid.link/20250812071810.312346-1-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- .../testing/selftests/net/forwarding/Makefile | 4 +- .../net/forwarding/bridge_activity_notify.sh | 173 ++++++++++++++++++ 2 files changed, 176 insertions(+), 1 deletion(-) create mode 100755 tools/testing/selftests/net/forwarding/bridge_activity_notify.sh diff --git a/tools/testing/selftests/net/forwarding/Makefile b/tools/testing/selftests/net/forwarding/Makefile index d7bb2e80e88c..0a0d4c2a85f7 100644 --- a/tools/testing/selftests/net/forwarding/Makefile +++ b/tools/testing/selftests/net/forwarding/Makefile @@ -1,6 +1,8 @@ # SPDX-License-Identifier: GPL-2.0+ OR MIT -TEST_PROGS = bridge_fdb_learning_limit.sh \ +TEST_PROGS = \ + bridge_activity_notify.sh \ + bridge_fdb_learning_limit.sh \ bridge_igmp.sh \ bridge_locked_port.sh \ bridge_mdb.sh \ diff --git a/tools/testing/selftests/net/forwarding/bridge_activity_notify.sh b/tools/testing/selftests/net/forwarding/bridge_activity_notify.sh new file mode 100755 index 000000000000..a20ef4bd310b --- /dev/null +++ b/tools/testing/selftests/net/forwarding/bridge_activity_notify.sh @@ -0,0 +1,173 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +# +-----------------------+ +------------------------+ +# | H1 (vrf) | | H2 (vrf) | +# | 192.0.2.1/28 | | 192.0.2.2/28 | +# | + $h1 | | + $h2 | +# +----|------------------+ +----|-------------------+ +# | | +# +----|--------------------------------------------------|-------------------+ +# | SW | | | +# | +--|--------------------------------------------------|-----------------+ | +# | | + $swp1 BR1 (802.1d) + $swp2 | | +# | | | | +# | +-----------------------------------------------------------------------+ | +# +---------------------------------------------------------------------------+ + +ALL_TESTS=" + new_inactive_test + existing_active_test + norefresh_test +" + +NUM_NETIFS=4 +source lib.sh + +h1_create() +{ + simple_if_init "$h1" 192.0.2.1/28 + defer simple_if_fini "$h1" 192.0.2.1/28 +} + +h2_create() +{ + simple_if_init "$h2" 192.0.2.2/28 + defer simple_if_fini "$h2" 192.0.2.2/28 +} + +switch_create() +{ + ip_link_add br1 type bridge vlan_filtering 0 mcast_snooping 0 \ + ageing_time "$LOW_AGEING_TIME" + ip_link_set_up br1 + + ip_link_set_master "$swp1" br1 + ip_link_set_up "$swp1" + + ip_link_set_master "$swp2" br1 + ip_link_set_up "$swp2" +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + swp1=${NETIFS[p2]} + + swp2=${NETIFS[p3]} + h2=${NETIFS[p4]} + + vrf_prepare + defer vrf_cleanup + + h1_create + h2_create + switch_create +} + +fdb_active_wait() +{ + local mac=$1; shift + + bridge -d fdb get "$mac" br br1 | grep -q -v "inactive" +} + +fdb_inactive_wait() +{ + local mac=$1; shift + + bridge -d fdb get "$mac" br br1 | grep -q "inactive" +} + +new_inactive_test() +{ + local mac="00:11:22:33:44:55" + + # Add a new FDB entry as static and inactive and check that it + # becomes active upon traffic. + RET=0 + + bridge fdb add "$mac" dev "$swp1" master static activity_notify inactive + bridge -d fdb get "$mac" br br1 | grep -q "inactive" + check_err $? "FDB entry not present as \"inactive\" when should" + + $MZ "$h1" -c 1 -p 64 -a "$mac" -b bcast -t ip -q + + busywait "$BUSYWAIT_TIMEOUT" fdb_active_wait "$mac" + check_err $? "FDB entry present as \"inactive\" when should not" + + log_test "Transition from inactive to active" + + bridge fdb del "$mac" dev "$swp1" master +} + +existing_active_test() +{ + local mac="00:11:22:33:44:55" + local ageing_time + + # Enable activity notifications on an existing dynamic FDB entry and + # check that it becomes inactive after the ageing time passed. + RET=0 + + bridge fdb add "$mac" dev "$swp1" master dynamic + bridge fdb replace "$mac" dev "$swp1" master static activity_notify norefresh + + bridge -d fdb get "$mac" br br1 | grep -q "activity_notify" + check_err $? "FDB entry not present as \"activity_notify\" when should" + + bridge -d fdb get "$mac" br br1 | grep -q "inactive" + check_fail $? "FDB entry present as \"inactive\" when should not" + + ageing_time=$(bridge_ageing_time_get br1) + slowwait $((ageing_time * 2)) fdb_inactive_wait "$mac" + check_err $? "FDB entry not present as \"inactive\" when should" + + log_test "Transition from active to inactive" + + bridge fdb del "$mac" dev "$swp1" master +} + +norefresh_test() +{ + local mac="00:11:22:33:44:55" + local updated_time + + # Check that the "updated" time is reset when replacing an FDB entry + # without the "norefresh" keyword and that it is not reset when + # replacing with the "norefresh" keyword. + RET=0 + + bridge fdb add "$mac" dev "$swp1" master static + sleep 1 + + bridge fdb replace "$mac" dev "$swp1" master static activity_notify + updated_time=$(bridge -d -s -j fdb get "$mac" br br1 | jq '.[]["updated"]') + if [[ $updated_time -ne 0 ]]; then + check_err 1 "\"updated\" time was not reset when should" + fi + + sleep 1 + bridge fdb replace "$mac" dev "$swp1" master static norefresh + updated_time=$(bridge -d -s -j fdb get "$mac" br br1 | jq '.[]["updated"]') + if [[ $updated_time -eq 0 ]]; then + check_err 1 "\"updated\" time was reset when should not" + fi + + log_test "Resetting of \"updated\" time" + + bridge fdb del "$mac" dev "$swp1" master +} + +if ! bridge fdb help 2>&1 | grep -q "activity_notify"; then + echo "SKIP: iproute2 too old, missing bridge FDB activity notification control" + exit "$ksft_skip" +fi + +trap cleanup EXIT + +setup_prepare +setup_wait +tests_run + +exit "$EXIT_STATUS" From a57384110dc633856216fc254680923905391d67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Garc=C3=ADa?= Date: Tue, 12 Aug 2025 10:22:44 +0200 Subject: [PATCH 00790/11391] tun: replace strcpy with strscpy for ifr_name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the strcpy() calls that copy the device name into ifr->ifr_name with strscpy() to avoid potential overflows and guarantee NULL termination. Destination is ifr->ifr_name (size IFNAMSIZ). Tested in QEMU (BusyBox rootfs): - Created TUN devices via TUNSETIFF helper - Set addresses and brought links up - Verified long interface names are safely truncated (IFNAMSIZ-1) Signed-off-by: Miguel García Reviewed-by: Willem de Bruijn Link: https://patch.msgid.link/20250812082244.60240-1-miguelgarciaroman8@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/tun.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index cc6c50180663..86a9e927d0ff 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -2823,13 +2823,13 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) if (netif_running(tun->dev)) netif_tx_wake_all_queues(tun->dev); - strcpy(ifr->ifr_name, tun->dev->name); + strscpy(ifr->ifr_name, tun->dev->name); return 0; } static void tun_get_iff(struct tun_struct *tun, struct ifreq *ifr) { - strcpy(ifr->ifr_name, tun->dev->name); + strscpy(ifr->ifr_name, tun->dev->name); ifr->ifr_flags = tun_flags(tun); From 30f7d4099fb6736712338bd3e41433db796ec869 Mon Sep 17 00:00:00 2001 From: Jiawen Wu Date: Tue, 12 Aug 2025 17:37:25 +0800 Subject: [PATCH 00791/11391] net: libwx: cleanup VF register macros Adjust the order of VF regitser macros, make it elegant. Signed-off-by: Jiawen Wu Link: https://patch.msgid.link/778899EE1D862EC2+20250812093725.58821-1-jiawenwu@trustnetic.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/wangxun/libwx/wx_vf.h | 72 +++++++++++----------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf.h b/drivers/net/ethernet/wangxun/libwx/wx_vf.h index fec1126703e3..3f16de0fa427 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_vf.h +++ b/drivers/net/ethernet/wangxun/libwx/wx_vf.h @@ -4,6 +4,7 @@ #ifndef _WX_VF_H_ #define _WX_VF_H_ +/* Control registers */ #define WX_VF_MAX_RING_NUMS 8 #define WX_VX_PF_BME 0x4B8 #define WX_VF_BME_ENABLE BIT(0) @@ -12,16 +13,32 @@ #define WX_VXCTRL_RST BIT(0) #define WX_VXMRQC 0x78 +#define WX_VXMRQC_PSR_L4HDR BIT(0) +#define WX_VXMRQC_PSR_L3HDR BIT(1) +#define WX_VXMRQC_PSR_L2HDR BIT(2) +#define WX_VXMRQC_PSR_TUNHDR BIT(3) +#define WX_VXMRQC_PSR_TUNMAC BIT(4) +#define WX_VXMRQC_PSR_MASK GENMASK(5, 1) +#define WX_VXMRQC_PSR(f) FIELD_PREP(GENMASK(5, 1), f) +#define WX_VXMRQC_RSS_HASH(f) FIELD_PREP(GENMASK(15, 13), f) +#define WX_VXMRQC_RSS_MASK GENMASK(31, 16) +#define WX_VXMRQC_RSS(f) FIELD_PREP(GENMASK(31, 16), f) +#define WX_VXMRQC_RSS_ALG_IPV4_TCP BIT(0) +#define WX_VXMRQC_RSS_ALG_IPV4 BIT(1) +#define WX_VXMRQC_RSS_ALG_IPV6 BIT(4) +#define WX_VXMRQC_RSS_ALG_IPV6_TCP BIT(5) +#define WX_VXMRQC_RSS_EN BIT(8) + +#define WX_VXRSSRK(i) (0x80 + ((i) * 4)) /* i=[0,9] */ +#define WX_VXRETA(i) (0xC0 + ((i) * 4)) /* i=[0,15] */ + +/* Interrupt registers */ #define WX_VXICR 0x100 #define WX_VXIMS 0x108 #define WX_VXIMC 0x10C #define WX_VF_IRQ_CLEAR_MASK 7 #define WX_VF_MAX_TX_QUEUES 4 #define WX_VF_MAX_RX_QUEUES 4 -#define WX_VXTXDCTL(r) (0x3010 + (0x40 * (r))) -#define WX_VXRXDCTL(r) (0x1010 + (0x40 * (r))) -#define WX_VXRXDCTL_ENABLE BIT(0) -#define WX_VXTXDCTL_FLUSH BIT(26) #define WX_VXITR(i) (0x200 + (4 * (i))) /* i=[0,1] */ #define WX_VXITR_MASK GENMASK(8, 0) @@ -29,16 +46,6 @@ #define WX_VXIVAR_MISC 0x260 #define WX_VXIVAR(i) (0x240 + (4 * (i))) /* i=[0,3] */ -#define WX_VXRXDCTL_RSCMAX(f) FIELD_PREP(GENMASK(24, 23), f) -#define WX_VXRXDCTL_BUFLEN(f) FIELD_PREP(GENMASK(6, 1), f) -#define WX_VXRXDCTL_BUFSZ(f) FIELD_PREP(GENMASK(11, 8), f) -#define WX_VXRXDCTL_HDRSZ(f) FIELD_PREP(GENMASK(15, 12), f) - -#define WX_VXRXDCTL_RSCMAX_MASK GENMASK(24, 23) -#define WX_VXRXDCTL_BUFLEN_MASK GENMASK(6, 1) -#define WX_VXRXDCTL_BUFSZ_MASK GENMASK(11, 8) -#define WX_VXRXDCTL_HDRSZ_MASK GENMASK(15, 12) - #define wx_conf_size(v, mwidth, uwidth) ({ \ typeof(v) _v = (v); \ (_v == 2 << (mwidth) ? 0 : _v >> (uwidth)); \ @@ -59,44 +66,35 @@ #define WX_VXRDBAH(r) (0x1004 + (0x40 * (r))) #define WX_VXRDT(r) (0x1008 + (0x40 * (r))) #define WX_VXRDH(r) (0x100C + (0x40 * (r))) - +#define WX_VXRXDCTL(r) (0x1010 + (0x40 * (r))) +#define WX_VXRXDCTL_ENABLE BIT(0) +#define WX_VXRXDCTL_BUFLEN_MASK GENMASK(6, 1) +#define WX_VXRXDCTL_BUFLEN(f) FIELD_PREP(GENMASK(6, 1), f) +#define WX_VXRXDCTL_BUFSZ_MASK GENMASK(11, 8) +#define WX_VXRXDCTL_BUFSZ(f) FIELD_PREP(GENMASK(11, 8), f) +#define WX_VXRXDCTL_HDRSZ_MASK GENMASK(15, 12) +#define WX_VXRXDCTL_HDRSZ(f) FIELD_PREP(GENMASK(15, 12), f) +#define WX_VXRXDCTL_RSCMAX_MASK GENMASK(24, 23) +#define WX_VXRXDCTL_RSCMAX(f) FIELD_PREP(GENMASK(24, 23), f) #define WX_VXRXDCTL_RSCEN BIT(29) #define WX_VXRXDCTL_DROP BIT(30) #define WX_VXRXDCTL_VLAN BIT(31) +/* Transimit Path */ #define WX_VXTDBAL(r) (0x3000 + (0x40 * (r))) #define WX_VXTDBAH(r) (0x3004 + (0x40 * (r))) #define WX_VXTDT(r) (0x3008 + (0x40 * (r))) #define WX_VXTDH(r) (0x300C + (0x40 * (r))) - +#define WX_VXTXDCTL(r) (0x3010 + (0x40 * (r))) #define WX_VXTXDCTL_ENABLE BIT(0) #define WX_VXTXDCTL_BUFLEN(f) FIELD_PREP(GENMASK(6, 1), f) #define WX_VXTXDCTL_PTHRESH(f) FIELD_PREP(GENMASK(11, 8), f) #define WX_VXTXDCTL_WTHRESH(f) FIELD_PREP(GENMASK(22, 16), f) - -#define WX_VXMRQC_PSR(f) FIELD_PREP(GENMASK(5, 1), f) -#define WX_VXMRQC_PSR_MASK GENMASK(5, 1) -#define WX_VXMRQC_PSR_L4HDR BIT(0) -#define WX_VXMRQC_PSR_L3HDR BIT(1) -#define WX_VXMRQC_PSR_L2HDR BIT(2) -#define WX_VXMRQC_PSR_TUNHDR BIT(3) -#define WX_VXMRQC_PSR_TUNMAC BIT(4) - -#define WX_VXRSSRK(i) (0x80 + ((i) * 4)) /* i=[0,9] */ -#define WX_VXRETA(i) (0xC0 + ((i) * 4)) /* i=[0,15] */ - -#define WX_VXMRQC_RSS(f) FIELD_PREP(GENMASK(31, 16), f) -#define WX_VXMRQC_RSS_MASK GENMASK(31, 16) -#define WX_VXMRQC_RSS_ALG_IPV4_TCP BIT(0) -#define WX_VXMRQC_RSS_ALG_IPV4 BIT(1) -#define WX_VXMRQC_RSS_ALG_IPV6 BIT(4) -#define WX_VXMRQC_RSS_ALG_IPV6_TCP BIT(5) -#define WX_VXMRQC_RSS_EN BIT(8) -#define WX_VXMRQC_RSS_HASH(f) FIELD_PREP(GENMASK(15, 13), f) +#define WX_VXTXDCTL_FLUSH BIT(26) #define WX_PFLINK_STATUS(g) FIELD_GET(BIT(0), g) #define WX_PFLINK_SPEED(g) FIELD_GET(GENMASK(31, 1), g) -#define WX_VXSTATUS_SPEED(g) FIELD_GET(GENMASK(4, 1), g) +#define WX_VXSTATUS_SPEED(g) FIELD_GET(GENMASK(4, 1), g) struct wx_link_reg_fields { u32 mac_type; From 3051f49b0e03b1a5a2f8a70dbc4ae5bf3759bcb7 Mon Sep 17 00:00:00 2001 From: Waqar Hameed Date: Tue, 12 Aug 2025 14:13:58 +0200 Subject: [PATCH 00792/11391] net: enetc: 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: Joe Damato Link: https://patch.msgid.link/pnd1ppghh4p.a.out@axis.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/freescale/enetc/enetc4_pf.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c index b3dc1afeefd1..38fb81db48c2 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c +++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c @@ -1016,8 +1016,7 @@ static int enetc4_pf_probe(struct pci_dev *pdev, err = devm_add_action_or_reset(dev, enetc4_pci_remove, pdev); if (err) - return dev_err_probe(dev, err, - "Add enetc4_pci_remove() action failed\n"); + return err; /* si is the private data. */ si = pci_get_drvdata(pdev); From acfea9361073134e828fddbd5f8201d428d7a7b1 Mon Sep 17 00:00:00 2001 From: Andre Carvalho Date: Tue, 12 Aug 2025 20:38:23 +0100 Subject: [PATCH 00793/11391] selftests: netconsole: Validate interface selection by MAC address Extend the existing netconsole cmdline selftest to also validate that interface selection can be performed via MAC address. The test now validates that netconsole works with both interface name and MAC address, improving test coverage. Suggested-by: Breno Leitao Reviewed-by: Breno Leitao Signed-off-by: Andre Carvalho Link: https://patch.msgid.link/20250812-netcons-cmdline-selftest-v2-1-8099fb7afa9e@gmail.com Signed-off-by: Jakub Kicinski --- .../drivers/net/lib/sh/lib_netcons.sh | 10 +++- .../selftests/drivers/net/netcons_cmdline.sh | 51 ++++++++++++------- 2 files changed, 41 insertions(+), 20 deletions(-) diff --git a/tools/testing/selftests/drivers/net/lib/sh/lib_netcons.sh b/tools/testing/selftests/drivers/net/lib/sh/lib_netcons.sh index b6071e80ebbb..8e1085e89647 100644 --- a/tools/testing/selftests/drivers/net/lib/sh/lib_netcons.sh +++ b/tools/testing/selftests/drivers/net/lib/sh/lib_netcons.sh @@ -148,12 +148,20 @@ function create_dynamic_target() { # Generate the command line argument for netconsole following: # netconsole=[+][src-port]@[src-ip]/[],[tgt-port]@/[tgt-macaddr] function create_cmdline_str() { + local BINDMODE=${1:-"ifname"} + if [ "${BINDMODE}" == "ifname" ] + then + SRCDEV=${SRCIF} + else + SRCDEV=$(mac_get "${SRCIF}") + fi + DSTMAC=$(ip netns exec "${NAMESPACE}" \ ip link show "${DSTIF}" | awk '/ether/ {print $2}') SRCPORT="1514" TGTPORT="6666" - echo "netconsole=\"+${SRCPORT}@${SRCIP}/${SRCIF},${TGTPORT}@${DSTIP}/${DSTMAC}\"" + echo "netconsole=\"+${SRCPORT}@${SRCIP}/${SRCDEV},${TGTPORT}@${DSTIP}/${DSTMAC}\"" } # Do not append the release to the header of the message diff --git a/tools/testing/selftests/drivers/net/netcons_cmdline.sh b/tools/testing/selftests/drivers/net/netcons_cmdline.sh index ad2fb8b1c463..d1d23dc67f99 100755 --- a/tools/testing/selftests/drivers/net/netcons_cmdline.sh +++ b/tools/testing/selftests/drivers/net/netcons_cmdline.sh @@ -19,9 +19,6 @@ check_netconsole_module modprobe netdevsim 2> /dev/null || true rmmod netconsole 2> /dev/null || true -# The content of kmsg will be save to the following file -OUTPUT_FILE="/tmp/${TARGET}" - # Check for basic system dependency and exit if not found # check_for_dependencies # Set current loglevel to KERN_INFO(6), and default to KERN_NOTICE(5) @@ -30,23 +27,39 @@ echo "6 5" > /proc/sys/kernel/printk trap do_cleanup EXIT # Create one namespace and two interfaces set_network -# Create the command line for netconsole, with the configuration from the -# function above -CMDLINE="$(create_cmdline_str)" -# Load the module, with the cmdline set -modprobe netconsole "${CMDLINE}" +# Run the test twice, with different cmdline parameters +for BINDMODE in "ifname" "mac" +do + echo "Running with bind mode: ${BINDMODE}" >&2 + # Create the command line for netconsole, with the configuration from + # the function above + CMDLINE=$(create_cmdline_str "${BINDMODE}") -# Listed for netconsole port inside the namespace and destination interface -listen_port_and_save_to "${OUTPUT_FILE}" & -# Wait for socat to start and listen to the port. -wait_local_port_listen "${NAMESPACE}" "${PORT}" udp -# Send the message -echo "${MSG}: ${TARGET}" > /dev/kmsg -# Wait until socat saves the file to disk -busywait "${BUSYWAIT_TIMEOUT}" test -s "${OUTPUT_FILE}" -# Make sure the message was received in the dst part -# and exit -validate_msg "${OUTPUT_FILE}" + # The content of kmsg will be save to the following file + OUTPUT_FILE="/tmp/${TARGET}-${BINDMODE}" + + # Load the module, with the cmdline set + modprobe netconsole "${CMDLINE}" + + # Listed for netconsole port inside the namespace and destination + # interface + listen_port_and_save_to "${OUTPUT_FILE}" & + # Wait for socat to start and listen to the port. + wait_local_port_listen "${NAMESPACE}" "${PORT}" udp + # Send the message + echo "${MSG}: ${TARGET}" > /dev/kmsg + # Wait until socat saves the file to disk + busywait "${BUSYWAIT_TIMEOUT}" test -s "${OUTPUT_FILE}" + # Make sure the message was received in the dst part + # and exit + validate_msg "${OUTPUT_FILE}" + + # kill socat in case it is still running + pkill_socat + # Unload the module + rmmod netconsole + echo "${BINDMODE} : Test passed" >&2 +done exit "${ksft_pass}" From 66ceb45b7d7e9673254116eefe5b6d3a44eba267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Mon, 11 Aug 2025 11:43:18 +0200 Subject: [PATCH 00794/11391] ice: Don't use %pK through printk or tracepoints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the past %pK was preferable to %p as it would not leak raw pointer values into the kernel log. Since commit ad67b74d2469 ("printk: hash addresses printed with %p") the regular %p has been improved to avoid this issue. Furthermore, restricted pointers ("%pK") were never meant to be used through printk(). They can still unintentionally leak raw pointers or acquire sleeping locks in atomic contexts. Switch to the regular pointer formatting which is safer and easier to reason about. There are still a few users of %pK left, but these use it through seq_file, for which its usage is safe. Signed-off-by: Thomas Weißschuh Acked-by: Przemek Kitszel Reviewed-by: Aleksandr Loktionov Reviewed-by: Simon Horman Reviewed-by: Paul Menzel Reviewed-by: Jacob Keller Link: https://patch.msgid.link/20250811-restricted-pointers-net-v5-1-2e2fdc7d3f2c@linutronix.de Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/ice/ice_main.c | 2 +- drivers/net/ethernet/intel/ice/ice_trace.h | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 8e0b06c1e02b..93c6e64ed940 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -9117,7 +9117,7 @@ static int ice_create_q_channels(struct ice_vsi *vsi) list_add_tail(&ch->list, &vsi->ch_list); vsi->tc_map_vsi[i] = ch->ch_vsi; dev_dbg(ice_pf_to_dev(pf), - "successfully created channel: VSI %pK\n", ch->ch_vsi); + "successfully created channel: VSI %p\n", ch->ch_vsi); } return 0; diff --git a/drivers/net/ethernet/intel/ice/ice_trace.h b/drivers/net/ethernet/intel/ice/ice_trace.h index 07aab6e130cd..4f35ef8d6b29 100644 --- a/drivers/net/ethernet/intel/ice/ice_trace.h +++ b/drivers/net/ethernet/intel/ice/ice_trace.h @@ -130,7 +130,7 @@ DECLARE_EVENT_CLASS(ice_tx_template, __entry->buf = buf; __assign_str(devname);), - TP_printk("netdev: %s ring: %pK desc: %pK buf %pK", __get_str(devname), + TP_printk("netdev: %s ring: %p desc: %p buf %p", __get_str(devname), __entry->ring, __entry->desc, __entry->buf) ); @@ -158,7 +158,7 @@ DECLARE_EVENT_CLASS(ice_rx_template, __entry->desc = desc; __assign_str(devname);), - TP_printk("netdev: %s ring: %pK desc: %pK", __get_str(devname), + TP_printk("netdev: %s ring: %p desc: %p", __get_str(devname), __entry->ring, __entry->desc) ); DEFINE_EVENT(ice_rx_template, ice_clean_rx_irq, @@ -182,7 +182,7 @@ DECLARE_EVENT_CLASS(ice_rx_indicate_template, __entry->skb = skb; __assign_str(devname);), - TP_printk("netdev: %s ring: %pK desc: %pK skb %pK", __get_str(devname), + TP_printk("netdev: %s ring: %p desc: %p skb %p", __get_str(devname), __entry->ring, __entry->desc, __entry->skb) ); @@ -205,7 +205,7 @@ DECLARE_EVENT_CLASS(ice_xmit_template, __entry->skb = skb; __assign_str(devname);), - TP_printk("netdev: %s skb: %pK ring: %pK", __get_str(devname), + TP_printk("netdev: %s skb: %p ring: %p", __get_str(devname), __entry->skb, __entry->ring) ); @@ -228,7 +228,7 @@ DECLARE_EVENT_CLASS(ice_tx_tstamp_template, TP_fast_assign(__entry->skb = skb; __entry->idx = idx;), - TP_printk("skb %pK idx %d", + TP_printk("skb %p idx %d", __entry->skb, __entry->idx) ); #define DEFINE_TX_TSTAMP_OP_EVENT(name) \ From e2068f74b97653356ad7d6ce456db1f5b7fb575e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Mon, 11 Aug 2025 11:43:19 +0200 Subject: [PATCH 00795/11391] net/mlx5: Don't use %pK through tracepoints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the past %pK was preferable to %p as it would not leak raw pointer values into the kernel log. Since commit ad67b74d2469 ("printk: hash addresses printed with %p") the regular %p has been improved to avoid this issue. Furthermore, restricted pointers ("%pK") were never meant to be used through tracepoints. They can still unintentionally leak raw pointers or acquire sleeping locks in atomic contexts. Switch to the regular pointer formatting which is safer and easier to reason about. There are still a few users of %pK left, but these use it through seq_file, for which its usage is safe. Signed-off-by: Thomas Weißschuh Reviewed-by: Aleksandr Loktionov Reviewed-by: Tariq Toukan Reviewed-by: Simon Horman Reviewed-by: Paul Menzel Reviewed-by: Jacob Keller Link: https://patch.msgid.link/20250811-restricted-pointers-net-v5-2-2e2fdc7d3f2c@linutronix.de Signed-off-by: Jakub Kicinski --- .../ethernet/mellanox/mlx5/core/sf/dev/diag/dev_tracepoint.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/diag/dev_tracepoint.h b/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/diag/dev_tracepoint.h index 0537de86f981..9b0f44253f33 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/diag/dev_tracepoint.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/diag/dev_tracepoint.h @@ -28,7 +28,7 @@ DECLARE_EVENT_CLASS(mlx5_sf_dev_template, __entry->hw_fn_id = sfdev->fn_id; __entry->sfnum = sfdev->sfnum; ), - TP_printk("(%s) sfdev=%pK aux_id=%d hw_id=0x%x sfnum=%u\n", + TP_printk("(%s) sfdev=%p aux_id=%d hw_id=0x%x sfnum=%u\n", __get_str(devname), __entry->sfdev, __entry->aux_id, __entry->hw_fn_id, __entry->sfnum) From 5d8a9c8401648d338d072a488d455ed4611c5d4b Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 13 Aug 2025 18:15:04 +0200 Subject: [PATCH 00796/11391] soc: 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-19-wsa+renesas@sang-engineering.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/llcc-qcom.c | 1 - drivers/soc/qcom/ramp_controller.c | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c index 192edc3f64dc..857ead56b37d 100644 --- a/drivers/soc/qcom/llcc-qcom.c +++ b/drivers/soc/qcom/llcc-qcom.c @@ -4409,7 +4409,6 @@ static struct regmap *qcom_llcc_init_mmio(struct platform_device *pdev, u8 index .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .fast_io = true, }; base = devm_platform_ioremap_resource(pdev, index); diff --git a/drivers/soc/qcom/ramp_controller.c b/drivers/soc/qcom/ramp_controller.c index 349bdfbc61ef..15782bed2925 100644 --- a/drivers/soc/qcom/ramp_controller.c +++ b/drivers/soc/qcom/ramp_controller.c @@ -229,7 +229,6 @@ static const struct regmap_config qrc_regmap_config = { .reg_stride = 4, .val_bits = 32, .max_register = 0x68, - .fast_io = true, }; static const struct reg_sequence msm8976_cfg_dfs_sid[] = { From daad2ef99145215fac1cab196811e3e03ef8bc9f Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Wed, 13 Aug 2025 07:54:31 +0000 Subject: [PATCH 00797/11391] rust: cpumask: rename CpumaskVar::as[_mut]_ref to from_raw[_mut] The prefix as_* shouldn't be used for constructors. For further motivation, see commit 2f5606afa4c2 ("device: rust: rename Device::as_ref() to Device::from_raw()"). Signed-off-by: Alice Ryhl Reviewed-by: Benno Lossin Reviewed-by: Yury Norov (NVIDIA) Signed-off-by: Viresh Kumar --- rust/kernel/cpufreq.rs | 2 +- rust/kernel/cpumask.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs index afc15e72a7c3..eea57ba95f24 100644 --- a/rust/kernel/cpufreq.rs +++ b/rust/kernel/cpufreq.rs @@ -543,7 +543,7 @@ pub fn register_em_opp(&mut self) { pub fn cpus(&mut self) -> &mut cpumask::Cpumask { // SAFETY: The pointer to `cpus` is valid for writing and remains valid for the lifetime of // the returned reference. - unsafe { cpumask::CpumaskVar::as_mut_ref(&mut self.as_mut_ref().cpus) } + unsafe { cpumask::CpumaskVar::from_raw_mut(&mut self.as_mut_ref().cpus) } } /// Sets clock for the [`Policy`]. diff --git a/rust/kernel/cpumask.rs b/rust/kernel/cpumask.rs index 3fcbff438670..e311ab9038df 100644 --- a/rust/kernel/cpumask.rs +++ b/rust/kernel/cpumask.rs @@ -270,7 +270,7 @@ pub unsafe fn new(_flags: Flags) -> Result { /// /// The caller must ensure that `ptr` is valid for writing and remains valid for the lifetime /// of the returned reference. - pub unsafe fn as_mut_ref<'a>(ptr: *mut bindings::cpumask_var_t) -> &'a mut Self { + pub unsafe fn from_raw_mut<'a>(ptr: *mut bindings::cpumask_var_t) -> &'a mut Self { // SAFETY: Guaranteed by the safety requirements of the function. // // INVARIANT: The caller ensures that `ptr` is valid for writing and remains valid for the @@ -284,7 +284,7 @@ pub unsafe fn as_mut_ref<'a>(ptr: *mut bindings::cpumask_var_t) -> &'a mut Self /// /// The caller must ensure that `ptr` is valid for reading and remains valid for the lifetime /// of the returned reference. - pub unsafe fn as_ref<'a>(ptr: *const bindings::cpumask_var_t) -> &'a Self { + pub unsafe fn from_raw<'a>(ptr: *const bindings::cpumask_var_t) -> &'a Self { // SAFETY: Guaranteed by the safety requirements of the function. // // INVARIANT: The caller ensures that `ptr` is valid for reading and remains valid for the From 23fca458f6ab18927e50c2134fb7b60297f18b4e Mon Sep 17 00:00:00 2001 From: Baptiste Lepers Date: Tue, 12 Aug 2025 16:42:11 +0200 Subject: [PATCH 00798/11391] rust: cpumask: Mark CpumaskVar as transparent Unsafe code in CpumaskVar's methods assumes that the type has the same layout as `bindings::cpumask_var_t`. This is not guaranteed by the default struct representation in Rust, but requires specifying the `transparent` representation. Fixes: 8961b8cb3099a ("rust: cpumask: Add initial abstractions") Signed-off-by: Baptiste Lepers Reviewed-by: Alice Ryhl Signed-off-by: Viresh Kumar --- rust/kernel/cpumask.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/rust/kernel/cpumask.rs b/rust/kernel/cpumask.rs index e311ab9038df..c1d17826ae7b 100644 --- a/rust/kernel/cpumask.rs +++ b/rust/kernel/cpumask.rs @@ -212,6 +212,7 @@ pub fn copy(&self, dstp: &mut Self) { /// } /// assert_eq!(mask2.weight(), count); /// ``` +#[repr(transparent)] pub struct CpumaskVar { #[cfg(CONFIG_CPUMASK_OFFSTACK)] ptr: NonNull, From 5d03847175e81e86d4865456c15638faaf7c0634 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Tue, 12 Aug 2025 15:42:29 +0200 Subject: [PATCH 00799/11391] 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 c308bb4190a8f6f09270b541457d6ae905d2f7bc Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Wed, 13 Aug 2025 22:55:02 +0200 Subject: [PATCH 00800/11391] ALSA: hda: Use min() to simplify snd_hda_get_devices() Use min() to simplify snd_hda_get_devices() and improve its readability. Change the function parameter 'max_devices' from 'int' to 'unsigned int' to avoid a min() signedness error. Update all related local variables and the function's return type to 'unsigned int' accordingly. No functional changes intended. Signed-off-by: Thorsten Blum Link: https://patch.msgid.link/20250813205507.215658-2-thorsten.blum@linux.dev Signed-off-by: Takashi Iwai --- include/sound/hda_codec.h | 4 ++-- sound/hda/common/codec.c | 11 +++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h index ddc9c392f93f..006d4e4a8195 100644 --- a/include/sound/hda_codec.h +++ b/include/sound/hda_codec.h @@ -360,8 +360,8 @@ int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int nums, int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux, hda_nid_t nid, int recursive); unsigned int snd_hda_get_num_devices(struct hda_codec *codec, hda_nid_t nid); -int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid, - u8 *dev_list, int max_devices); +unsigned int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid, + u8 *dev_list, unsigned int max_devices); int snd_hda_get_dev_select(struct hda_codec *codec, hda_nid_t nid); int snd_hda_set_dev_select(struct hda_codec *codec, hda_nid_t nid, int dev_id); diff --git a/sound/hda/common/codec.c b/sound/hda/common/codec.c index cab479111603..7a72d4c7ae91 100644 --- a/sound/hda/common/codec.c +++ b/sound/hda/common/codec.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -323,18 +324,16 @@ EXPORT_SYMBOL_GPL(snd_hda_get_num_devices); * Copy the device list. This info is dynamic and so not cached. * Currently called only from hda_proc.c, so not exported. */ -int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid, - u8 *dev_list, int max_devices) +unsigned int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid, + u8 *dev_list, unsigned int max_devices) { - unsigned int parm; - int i, dev_len, devices; + unsigned int parm, i, dev_len, devices; parm = snd_hda_get_num_devices(codec, nid); if (!parm) /* not multi-stream capable */ return 0; - dev_len = parm + 1; - dev_len = dev_len < max_devices ? dev_len : max_devices; + dev_len = min(parm + 1, max_devices); devices = 0; while (devices < dev_len) { From 4a31a043fc16d72b662251b75b183e25e2fa9e47 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Wed, 13 Aug 2025 23:00:57 +0200 Subject: [PATCH 00801/11391] ALSA: hda: Improve local variable data type in print_device_list() Use 'unsigned int' instead of 'int' for the local variable 'devlist_len' because snd_hda_get_devices() returns an 'unsigned int' and the length cannot be negative. Update the print format specifier and the if condition accordingly. Reformat calling snd_hda_codec_read() to fit in a single line while we're at it. Signed-off-by: Thorsten Blum Link: https://patch.msgid.link/20250813210059.215912-2-thorsten.blum@linux.dev Signed-off-by: Takashi Iwai --- sound/hda/common/proc.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/hda/common/proc.c b/sound/hda/common/proc.c index 00c2eeb2c472..d36195f73d45 100644 --- a/sound/hda/common/proc.c +++ b/sound/hda/common/proc.c @@ -716,16 +716,15 @@ static void print_device_list(struct snd_info_buffer *buffer, { int i, curr = -1; u8 dev_list[AC_MAX_DEV_LIST_LEN]; - int devlist_len; + unsigned int devlist_len; devlist_len = snd_hda_get_devices(codec, nid, dev_list, AC_MAX_DEV_LIST_LEN); - snd_iprintf(buffer, " Devices: %d\n", devlist_len); - if (devlist_len <= 0) + snd_iprintf(buffer, " Devices: %u\n", devlist_len); + if (devlist_len == 0) return; - curr = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_DEVICE_SEL, 0); + curr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DEVICE_SEL, 0); for (i = 0; i < devlist_len; i++) { if (i == curr) From 5893165a27e7d1f318aa91f0cd84e795dab7460d Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 13 Aug 2025 18:14:49 +0200 Subject: [PATCH 00802/11391] gpio: 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-4-wsa+renesas@sang-engineering.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-mvebu.c | 1 - drivers/gpio/gpio-sifive.c | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 5e3f54cb8bc4..261ffd0c614b 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -602,7 +602,6 @@ static const struct regmap_config mvebu_gpio_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .fast_io = true, }; /* diff --git a/drivers/gpio/gpio-sifive.c b/drivers/gpio/gpio-sifive.c index 067c8edb62e2..98ef975c44d9 100644 --- a/drivers/gpio/gpio-sifive.c +++ b/drivers/gpio/gpio-sifive.c @@ -174,7 +174,6 @@ static const struct regmap_config sifive_gpio_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .fast_io = true, .disable_locking = true, }; From 40e819747b45fd254ab99cfe39ba8787d6bbd33d Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Sun, 10 Aug 2025 18:24:14 -0400 Subject: [PATCH 00803/11391] net: cadence: macb: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate(). Signed-off-by: Brian Masney Reviewed-by: Jacob Keller Link: https://patch.msgid.link/20250810-net-round-rate-v1-1-dbb237c9fe5c@redhat.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/cadence/macb_main.c | 57 ++++++++++++++---------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index ce95fad8cedd..ce55a1f59b50 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -4822,36 +4822,45 @@ static unsigned long fu540_macb_tx_recalc_rate(struct clk_hw *hw, return mgmt->rate; } -static long fu540_macb_tx_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int fu540_macb_tx_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - if (WARN_ON(rate < 2500000)) - return 2500000; - else if (rate == 2500000) - return 2500000; - else if (WARN_ON(rate < 13750000)) - return 2500000; - else if (WARN_ON(rate < 25000000)) - return 25000000; - else if (rate == 25000000) - return 25000000; - else if (WARN_ON(rate < 75000000)) - return 25000000; - else if (WARN_ON(rate < 125000000)) - return 125000000; - else if (rate == 125000000) - return 125000000; + if (WARN_ON(req->rate < 2500000)) + req->rate = 2500000; + else if (req->rate == 2500000) + req->rate = 2500000; + else if (WARN_ON(req->rate < 13750000)) + req->rate = 2500000; + else if (WARN_ON(req->rate < 25000000)) + req->rate = 25000000; + else if (req->rate == 25000000) + req->rate = 25000000; + else if (WARN_ON(req->rate < 75000000)) + req->rate = 25000000; + else if (WARN_ON(req->rate < 125000000)) + req->rate = 125000000; + else if (req->rate == 125000000) + req->rate = 125000000; + else if (WARN_ON(req->rate > 125000000)) + req->rate = 125000000; + else + req->rate = 125000000; - WARN_ON(rate > 125000000); - - return 125000000; + return 0; } static int fu540_macb_tx_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { - rate = fu540_macb_tx_round_rate(hw, rate, &parent_rate); - if (rate != 125000000) + struct clk_rate_request req; + int ret; + + clk_hw_init_rate_request(hw, &req, rate); + ret = fu540_macb_tx_determine_rate(hw, &req); + if (ret != 0) + return ret; + + if (req.rate != 125000000) iowrite32(1, mgmt->reg); else iowrite32(0, mgmt->reg); @@ -4862,7 +4871,7 @@ static int fu540_macb_tx_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops fu540_c000_ops = { .recalc_rate = fu540_macb_tx_recalc_rate, - .round_rate = fu540_macb_tx_round_rate, + .determine_rate = fu540_macb_tx_determine_rate, .set_rate = fu540_macb_tx_set_rate, }; From f22cc6f766f84496b260347d4f0d92cf95f30699 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 11 Aug 2025 16:42:09 -0700 Subject: [PATCH 00804/11391] net: ethtool: support including Flow Label in the flow hash for RSS Some modern NICs support including the IPv6 Flow Label in the flow hash for RSS queue selection. This is outside the old "Microsoft spec", but was included in the OCP NIC spec: [ ] RSS include flow label in the hash (configurable) https://www.opencompute.org/w/index.php?title=Core_Offloads#Receive_Side_Scaling RSS Flow Label hashing allows TCP Protective Load Balancing (PLB) to recover from receiver congestion / overload. Rx CPU/queue hotspots are relatively common for data ingest workloads, and so far we had to try to detect the condition at the RPC layer and reopen the connection. PLB lets us change the Flow Label and therefore Rx CPU on RTO, with minimal packet reordering. PLB reaction times are much faster, and can happen at any point in the connection, not just at RPC boundaries. Due to the nature of host processing (relatively long queues, other kernel subsystems masking IRQs for 100s of msecs) the risk of reordering within the host is higher than in the network. But for applications which need it - it is far preferable to potentially persistent overload of subset of queues. It is expected that the hash communicated to the host may change if the Flow Label changes. This may be surprising to some host software, but I don't expect the devices can compute two Toeplitz hashes, one with the Flow Label for queue selection and one without for the rx hash communicated to the host. Besides, changing the hash may potentially help to change the path thru host queues. User can disable NETIF_F_RXHASH if they require a stable flow hash. The name RXH_IP6_FL was chosen based on what we call Flow Label variables in IPv6 processing (fl). I prefer fl_lbl but that appears to be an fbnic-only spelling. We could spell out RXH_IP6_FLOW_LABEL but existing RXH_ defines are a lot more terse. Willem notes [1] that Flow Label is defined as identifying the flow and therefore including both the flow label _and_ the L4 header fields is not generally necessary. But it should not hurt so it's not explicitly prevented if the driver supports hashing on both at the same time. Link: https://lore.kernel.org/68483433b45e2_3cd66f29440@willemb.c.googlers.com.notmuch [1] Signed-off-by: Jakub Kicinski Reviewed-by: Joe Damato Link: https://patch.msgid.link/20250811234212.580748-2-kuba@kernel.org Signed-off-by: Paolo Abeni --- Documentation/netlink/specs/ethtool.yaml | 3 +++ include/uapi/linux/ethtool.h | 1 + net/ethtool/ioctl.c | 25 ++++++++++++++++++++++ net/ethtool/rss.c | 27 ++++++++++++------------ 4 files changed, 43 insertions(+), 13 deletions(-) diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netlink/specs/ethtool.yaml index 1bc1bd7d33c2..7a7594713f1f 100644 --- a/Documentation/netlink/specs/ethtool.yaml +++ b/Documentation/netlink/specs/ethtool.yaml @@ -204,6 +204,9 @@ definitions: doc: dst port in case of TCP/UDP/SCTP - name: gtp-teid + - + name: ip6-fl + doc: IPv6 Flow Label - name: discard value: 31 diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h index 9e9afdd1238a..8bd5ea5469d9 100644 --- a/include/uapi/linux/ethtool.h +++ b/include/uapi/linux/ethtool.h @@ -2380,6 +2380,7 @@ enum { #define RXH_L4_B_0_1 (1 << 6) /* src port in case of TCP/UDP/SCTP */ #define RXH_L4_B_2_3 (1 << 7) /* dst port in case of TCP/UDP/SCTP */ #define RXH_GTP_TEID (1 << 8) /* teid in case of GTP */ +#define RXH_IP6_FL (1 << 9) /* IPv6 flow label */ #define RXH_DISCARD (1 << 31) #define RX_CLS_FLOW_DISC 0xffffffffffffffffULL diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c index 43a7854e784e..0b2a4d0573b3 100644 --- a/net/ethtool/ioctl.c +++ b/net/ethtool/ioctl.c @@ -1014,6 +1014,28 @@ static bool flow_type_hashable(u32 flow_type) return false; } +static bool flow_type_v6(u32 flow_type) +{ + switch (flow_type) { + case TCP_V6_FLOW: + case UDP_V6_FLOW: + case SCTP_V6_FLOW: + case AH_ESP_V6_FLOW: + case AH_V6_FLOW: + case ESP_V6_FLOW: + case IPV6_FLOW: + case GTPU_V6_FLOW: + case GTPC_V6_FLOW: + case GTPC_TEID_V6_FLOW: + case GTPU_EH_V6_FLOW: + case GTPU_UL_V6_FLOW: + case GTPU_DL_V6_FLOW: + return true; + } + + return false; +} + /* When adding a new type, update the assert and, if it's hashable, add it to * the flow_type_hashable switch case. */ @@ -1077,6 +1099,9 @@ ethtool_set_rxfh_fields(struct net_device *dev, u32 cmd, void __user *useraddr) if (rc) return rc; + if (info.data & RXH_IP6_FL && !flow_type_v6(info.flow_type)) + return -EINVAL; + if (info.flow_type & FLOW_RSS && info.rss_context && !ops->rxfh_per_ctx_fields) return -EINVAL; diff --git a/net/ethtool/rss.c b/net/ethtool/rss.c index 992e98abe9dd..202d95e8bf3e 100644 --- a/net/ethtool/rss.c +++ b/net/ethtool/rss.c @@ -536,35 +536,36 @@ void ethtool_rss_notify(struct net_device *dev, u32 type, u32 rss_context) #define RFH_MASK (RXH_L2DA | RXH_VLAN | RXH_IP_SRC | RXH_IP_DST | \ RXH_L3_PROTO | RXH_L4_B_0_1 | RXH_L4_B_2_3 | \ RXH_GTP_TEID | RXH_DISCARD) +#define RFH_MASKv6 (RFH_MASK | RXH_IP6_FL) static const struct nla_policy ethnl_rss_flows_policy[] = { [ETHTOOL_A_FLOW_ETHER] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), [ETHTOOL_A_FLOW_IP4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), - [ETHTOOL_A_FLOW_IP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), + [ETHTOOL_A_FLOW_IP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6), [ETHTOOL_A_FLOW_TCP4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), [ETHTOOL_A_FLOW_UDP4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), [ETHTOOL_A_FLOW_SCTP4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), [ETHTOOL_A_FLOW_AH_ESP4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), - [ETHTOOL_A_FLOW_TCP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), - [ETHTOOL_A_FLOW_UDP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), - [ETHTOOL_A_FLOW_SCTP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), - [ETHTOOL_A_FLOW_AH_ESP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), + [ETHTOOL_A_FLOW_TCP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6), + [ETHTOOL_A_FLOW_UDP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6), + [ETHTOOL_A_FLOW_SCTP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6), + [ETHTOOL_A_FLOW_AH_ESP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6), [ETHTOOL_A_FLOW_AH4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), [ETHTOOL_A_FLOW_ESP4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), - [ETHTOOL_A_FLOW_AH6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), - [ETHTOOL_A_FLOW_ESP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), + [ETHTOOL_A_FLOW_AH6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6), + [ETHTOOL_A_FLOW_ESP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6), [ETHTOOL_A_FLOW_GTPU4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), - [ETHTOOL_A_FLOW_GTPU6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), + [ETHTOOL_A_FLOW_GTPU6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6), [ETHTOOL_A_FLOW_GTPC4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), - [ETHTOOL_A_FLOW_GTPC6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), + [ETHTOOL_A_FLOW_GTPC6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6), [ETHTOOL_A_FLOW_GTPC_TEID4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), - [ETHTOOL_A_FLOW_GTPC_TEID6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), + [ETHTOOL_A_FLOW_GTPC_TEID6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6), [ETHTOOL_A_FLOW_GTPU_EH4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), - [ETHTOOL_A_FLOW_GTPU_EH6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), + [ETHTOOL_A_FLOW_GTPU_EH6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6), [ETHTOOL_A_FLOW_GTPU_UL4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), - [ETHTOOL_A_FLOW_GTPU_UL6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), + [ETHTOOL_A_FLOW_GTPU_UL6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6), [ETHTOOL_A_FLOW_GTPU_DL4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), - [ETHTOOL_A_FLOW_GTPU_DL6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK), + [ETHTOOL_A_FLOW_GTPU_DL6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6), }; const struct nla_policy ethnl_rss_set_policy[ETHTOOL_A_RSS_FLOW_HASH + 1] = { From 0afbfdc0f64a8525624b317a99050082be08ceb2 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 11 Aug 2025 16:42:10 -0700 Subject: [PATCH 00805/11391] eth: fbnic: support RSS on IPv6 Flow Label Support IPv6 Flow Label hashing. Use both inner and outer IPv6 header's Flow Label if both headers are detected. Flow Label is unlike normal header fields, by enabling it user accepts the unstable hash and possible reordering. Because of that I think it's reasonable to hash over all Flow Labels we can find, even tho we don't hash over all L3 addresses. Signed-off-by: Jakub Kicinski Link: https://patch.msgid.link/20250811234212.580748-3-kuba@kernel.org Signed-off-by: Paolo Abeni --- drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c | 2 +- drivers/net/ethernet/meta/fbnic/fbnic_rpc.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c index dc7ba8d5fc43..461c8661eb93 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c @@ -1310,7 +1310,7 @@ fbnic_get_rss_hash_opts(struct net_device *netdev, #define FBNIC_L2_HASH_OPTIONS \ (RXH_L2DA | RXH_DISCARD) #define FBNIC_L3_HASH_OPTIONS \ - (FBNIC_L2_HASH_OPTIONS | RXH_IP_SRC | RXH_IP_DST) + (FBNIC_L2_HASH_OPTIONS | RXH_IP_SRC | RXH_IP_DST | RXH_IP6_FL) #define FBNIC_L4_HASH_OPTIONS \ (FBNIC_L3_HASH_OPTIONS | RXH_L4_B_0_1 | RXH_L4_B_2_3) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_rpc.c b/drivers/net/ethernet/meta/fbnic/fbnic_rpc.c index 8ff07b5562e3..a4dc1024c0c2 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_rpc.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_rpc.c @@ -71,6 +71,8 @@ u16 fbnic_flow_hash_2_rss_en_mask(struct fbnic_net *fbn, int flow_type) rss_en_mask |= FBNIC_FH_2_RSSEM_BIT(IP_DST, IP_DST, flow_hash); rss_en_mask |= FBNIC_FH_2_RSSEM_BIT(L4_B_0_1, L4_SRC, flow_hash); rss_en_mask |= FBNIC_FH_2_RSSEM_BIT(L4_B_2_3, L4_DST, flow_hash); + rss_en_mask |= FBNIC_FH_2_RSSEM_BIT(IP6_FL, OV6_FL_LBL, flow_hash); + rss_en_mask |= FBNIC_FH_2_RSSEM_BIT(IP6_FL, IV6_FL_LBL, flow_hash); return rss_en_mask; } From 46c0faa46378ee54404383629641857476dc77f7 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 11 Aug 2025 16:42:11 -0700 Subject: [PATCH 00806/11391] eth: bnxt: support RSS on IPv6 Flow Label It appears that the bnxt FW API has the relevant bit for Flow Label hashing. Plumb in the support. Obey the capability bit. Signed-off-by: Jakub Kicinski Reviewed-by: Michael Chan Link: https://patch.msgid.link/20250811234212.580748-4-kuba@kernel.org Signed-off-by: Paolo Abeni --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 2 ++ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 + .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 20 +++++++++++++++---- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 5578ddcb465d..ab74c71c4557 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -6957,6 +6957,8 @@ static int bnxt_hwrm_vnic_qcaps(struct bnxt *bp) bp->rss_cap |= BNXT_RSS_CAP_ESP_V4_RSS_CAP; if (flags & VNIC_QCAPS_RESP_FLAGS_RSS_IPSEC_ESP_SPI_IPV6_CAP) bp->rss_cap |= BNXT_RSS_CAP_ESP_V6_RSS_CAP; + if (flags & VNIC_QCAPS_RESP_FLAGS_RSS_IPV6_FLOW_LABEL_CAP) + bp->rss_cap |= BNXT_RSS_CAP_IPV6_FLOW_LABEL_RSS_CAP; if (flags & VNIC_QCAPS_RESP_FLAGS_RE_FLUSH_CAP) bp->fw_cap |= BNXT_FW_CAP_VNIC_RE_FLUSH; } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index fda0d3cc6227..40ae34923511 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -2407,6 +2407,7 @@ struct bnxt { #define BNXT_RSS_CAP_ESP_V4_RSS_CAP BIT(6) #define BNXT_RSS_CAP_ESP_V6_RSS_CAP BIT(7) #define BNXT_RSS_CAP_MULTI_RSS_CTX BIT(8) +#define BNXT_RSS_CAP_IPV6_FLOW_LABEL_RSS_CAP BIT(9) u8 rss_hash_key[HW_HASH_KEY_SIZE]; u8 rss_hash_key_valid:1; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 1b37612b1c01..68a4ee9f69b1 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -1584,6 +1584,8 @@ static u64 get_ethtool_ipv6_rss(struct bnxt *bp) { if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6) return RXH_IP_SRC | RXH_IP_DST; + if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6_FLOW_LABEL) + return RXH_IP_SRC | RXH_IP_DST | RXH_IP6_FL; return 0; } @@ -1662,13 +1664,18 @@ static int bnxt_set_rxfh_fields(struct net_device *dev, if (cmd->data == RXH_4TUPLE) tuple = 4; - else if (cmd->data == RXH_2TUPLE) + else if (cmd->data == RXH_2TUPLE || + cmd->data == (RXH_2TUPLE | RXH_IP6_FL)) tuple = 2; else if (!cmd->data) tuple = 0; else return -EINVAL; + if (cmd->data & RXH_IP6_FL && + !(bp->rss_cap & BNXT_RSS_CAP_IPV6_FLOW_LABEL_RSS_CAP)) + return -EINVAL; + if (cmd->flow_type == TCP_V4_FLOW) { rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4; if (tuple == 4) @@ -1732,10 +1739,15 @@ static int bnxt_set_rxfh_fields(struct net_device *dev, case AH_V6_FLOW: case ESP_V6_FLOW: case IPV6_FLOW: - if (tuple == 2) + rss_hash_cfg &= ~(VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6 | + VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6_FLOW_LABEL); + if (!tuple) + break; + if (cmd->data & RXH_IP6_FL) + rss_hash_cfg |= + VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6_FLOW_LABEL; + else if (tuple == 2) rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6; - else if (!tuple) - rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6; break; } From 26dbe030ff08930bb243af3c66dd3b7e7bb8406d Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 11 Aug 2025 16:42:12 -0700 Subject: [PATCH 00807/11391] selftests: drv-net: add test for RSS on flow label Add a simple test for checking that RSS on flow label works, and that its rejected for IPv4 flows. # ./tools/testing/selftests/drivers/net/hw/rss_flow_label.py TAP version 13 1..2 ok 1 rss_flow_label.test_rss_flow_label ok 2 rss_flow_label.test_rss_flow_label_6only # Totals: pass:2 fail:0 xfail:0 xpass:0 skip:0 error:0 Reviewed-by: Willem de Bruijn Signed-off-by: Jakub Kicinski Reviewed-by: Joe Damato Link: https://patch.msgid.link/20250811234212.580748-5-kuba@kernel.org Signed-off-by: Paolo Abeni --- .../testing/selftests/drivers/net/hw/Makefile | 1 + .../drivers/net/hw/rss_flow_label.py | 167 ++++++++++++++++++ 2 files changed, 168 insertions(+) create mode 100755 tools/testing/selftests/drivers/net/hw/rss_flow_label.py diff --git a/tools/testing/selftests/drivers/net/hw/Makefile b/tools/testing/selftests/drivers/net/hw/Makefile index fdc97355588c..5159fd34cb33 100644 --- a/tools/testing/selftests/drivers/net/hw/Makefile +++ b/tools/testing/selftests/drivers/net/hw/Makefile @@ -18,6 +18,7 @@ TEST_PROGS = \ pp_alloc_fail.py \ rss_api.py \ rss_ctx.py \ + rss_flow_label.py \ rss_input_xfrm.py \ tso.py \ xsk_reconfig.py \ diff --git a/tools/testing/selftests/drivers/net/hw/rss_flow_label.py b/tools/testing/selftests/drivers/net/hw/rss_flow_label.py new file mode 100755 index 000000000000..6fa95fe27c47 --- /dev/null +++ b/tools/testing/selftests/drivers/net/hw/rss_flow_label.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 + +""" +Tests for RSS hashing on IPv6 Flow Label. +""" + +import glob +import os +import socket +from lib.py import CmdExitFailure +from lib.py import ksft_run, ksft_exit, ksft_eq, ksft_ge, ksft_in, \ + ksft_not_in, ksft_raises, KsftSkipEx +from lib.py import bkg, cmd, defer, fd_read_timeout, rand_port +from lib.py import NetDrvEpEnv + + +def _check_system(cfg): + if not hasattr(socket, "SO_INCOMING_CPU"): + raise KsftSkipEx("socket.SO_INCOMING_CPU was added in Python 3.11") + + qcnt = len(glob.glob(f"/sys/class/net/{cfg.ifname}/queues/rx-*")) + if qcnt < 2: + raise KsftSkipEx(f"Local has only {qcnt} queues") + + for f in [f"/sys/class/net/{cfg.ifname}/queues/rx-0/rps_flow_cnt", + f"/sys/class/net/{cfg.ifname}/queues/rx-0/rps_cpus"]: + try: + with open(f, 'r') as fp: + setting = fp.read().strip() + # CPU mask will be zeros and commas + if setting.replace("0", "").replace(",", ""): + raise KsftSkipEx(f"RPS/RFS is configured: {f}: {setting}") + except FileNotFoundError: + pass + + # 1 is the default, if someone changed it we probably shouldn"t mess with it + af = cmd("cat /proc/sys/net/ipv6/auto_flowlabels", host=cfg.remote).stdout + if af.strip() != "1": + raise KsftSkipEx("Remote does not have auto_flowlabels enabled") + + +def _ethtool_get_cfg(cfg, fl_type): + descr = cmd(f"ethtool -n {cfg.ifname} rx-flow-hash {fl_type}").stdout + + converter = { + "IP SA": "s", + "IP DA": "d", + "L3 proto": "t", + "L4 bytes 0 & 1 [TCP/UDP src port]": "f", + "L4 bytes 2 & 3 [TCP/UDP dst port]": "n", + "IPv6 Flow Label": "l", + } + + ret = "" + for line in descr.split("\n")[1:-2]: + # if this raises we probably need to add more keys to converter above + ret += converter[line] + return ret + + +def _traffic(cfg, one_sock, one_cpu): + local_port = rand_port(socket.SOCK_DGRAM) + remote_port = rand_port(socket.SOCK_DGRAM) + + sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) + sock.bind(("", local_port)) + sock.connect((cfg.remote_addr_v["6"], 0)) + if one_sock: + send = f"exec 5<>/dev/udp/{cfg.addr_v['6']}/{local_port}; " \ + "for i in `seq 20`; do echo a >&5; sleep 0.02; done; exec 5>&-" + else: + send = "for i in `seq 20`; do echo a | socat -t0.02 - UDP6:" \ + f"[{cfg.addr_v['6']}]:{local_port},sourceport={remote_port}; done" + + cpus = set() + with bkg(send, shell=True, host=cfg.remote, exit_wait=True): + for _ in range(20): + fd_read_timeout(sock.fileno(), 1) + cpu = sock.getsockopt(socket.SOL_SOCKET, socket.SO_INCOMING_CPU) + cpus.add(cpu) + + if one_cpu: + ksft_eq(len(cpus), 1, + f"{one_sock=} - expected one CPU, got traffic on: {cpus=}") + else: + ksft_ge(len(cpus), 2, + f"{one_sock=} - expected many CPUs, got traffic on: {cpus=}") + + +def test_rss_flow_label(cfg): + """ + Test hashing on IPv6 flow label. Send traffic over a single socket + and over multiple sockets. Depend on the remote having auto-label + enabled so that it randomizes the label per socket. + """ + + cfg.require_ipver("6") + cfg.require_cmd("socat", remote=True) + _check_system(cfg) + + # Enable flow label hashing for UDP6 + initial = _ethtool_get_cfg(cfg, "udp6") + no_lbl = initial.replace("l", "") + if "l" not in initial: + try: + cmd(f"ethtool -N {cfg.ifname} rx-flow-hash udp6 l{no_lbl}") + except CmdExitFailure as exc: + raise KsftSkipEx("Device doesn't support Flow Label for UDP6") from exc + + defer(cmd, f"ethtool -N {cfg.ifname} rx-flow-hash udp6 {initial}") + + _traffic(cfg, one_sock=True, one_cpu=True) + _traffic(cfg, one_sock=False, one_cpu=False) + + # Disable it, we should see no hashing (reset was already defer()ed) + cmd(f"ethtool -N {cfg.ifname} rx-flow-hash udp6 {no_lbl}") + + _traffic(cfg, one_sock=False, one_cpu=True) + + +def _check_v4_flow_types(cfg): + for fl_type in ["tcp4", "udp4", "ah4", "esp4", "sctp4"]: + try: + cur = cmd(f"ethtool -n {cfg.ifname} rx-flow-hash {fl_type}").stdout + ksft_not_in("Flow Label", cur, + comment=f"{fl_type=} has Flow Label:" + cur) + except CmdExitFailure: + # Probably does not support this flow type + pass + + +def test_rss_flow_label_6only(cfg): + """ + Test interactions with IPv4 flow types. It should not be possible to set + IPv6 Flow Label hashing for an IPv4 flow type. The Flow Label should also + not appear in the IPv4 "current config". + """ + + with ksft_raises(CmdExitFailure) as cm: + cmd(f"ethtool -N {cfg.ifname} rx-flow-hash tcp4 sdfnl") + ksft_in("Invalid argument", cm.exception.cmd.stderr) + + _check_v4_flow_types(cfg) + + # Try to enable Flow Labels and check again, in case it leaks thru + initial = _ethtool_get_cfg(cfg, "udp6") + changed = initial.replace("l", "") if "l" in initial else initial + "l" + + cmd(f"ethtool -N {cfg.ifname} rx-flow-hash udp6 {changed}") + restore = defer(cmd, f"ethtool -N {cfg.ifname} rx-flow-hash udp6 {initial}") + + _check_v4_flow_types(cfg) + restore.exec() + _check_v4_flow_types(cfg) + + +def main() -> None: + with NetDrvEpEnv(__file__, nsim_test=False) as cfg: + ksft_run([test_rss_flow_label, + test_rss_flow_label_6only], + args=(cfg, )) + ksft_exit() + + +if __name__ == "__main__": + main() From 3fc36ae6abd263a5cbf93b2f5539eccc1fc753f7 Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer Date: Fri, 25 Jul 2025 15:40:17 +0200 Subject: [PATCH 00808/11391] 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 @@ static void ip22zilog_transmit_chars(struct uart_ip22zilog_port *up, 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 00809/11391] 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 00810/11391] 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 00811/11391] 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 00812/11391] 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 00813/11391] 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 00814/11391] 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 a341bcfbfa74a00ddb741bbfe9a7c08c63382235 Mon Sep 17 00:00:00 2001 From: Kyle Hendry Date: Tue, 15 Jul 2025 16:46:03 -0700 Subject: [PATCH 00815/11391] dt-bindings: reset: add compatible for bcm63xx ephy control Add compatible string for bcm63xx ephy control. Signed-off-by: Kyle Hendry Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250715234605.36216-3-kylehendrydev@gmail.com Signed-off-by: Philipp Zabel --- .../devicetree/bindings/reset/brcm,bcm6345-reset.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/reset/brcm,bcm6345-reset.yaml b/Documentation/devicetree/bindings/reset/brcm,bcm6345-reset.yaml index 00150b93fca0..b8a320bb1776 100644 --- a/Documentation/devicetree/bindings/reset/brcm,bcm6345-reset.yaml +++ b/Documentation/devicetree/bindings/reset/brcm,bcm6345-reset.yaml @@ -13,7 +13,9 @@ maintainers: properties: compatible: - const: brcm,bcm6345-reset + enum: + - brcm,bcm6345-reset + - brcm,bcm63xx-ephy-ctrl reg: maxItems: 1 From 6e273caeacf0ec4a438f9cd22ecf9b77414e429d Mon Sep 17 00:00:00 2001 From: Kyle Hendry Date: Tue, 15 Jul 2025 16:46:02 -0700 Subject: [PATCH 00816/11391] reset: bcm6345: add support for bcm63xx ephy control register The ephy control register on bcm63xx SoCs contain bits for resetting individual internal phys. Use the existing bcm6345-reset driver to set bits. Signed-off-by: Kyle Hendry Link: https://lore.kernel.org/r/20250715234605.36216-2-kylehendrydev@gmail.com Signed-off-by: Philipp Zabel --- drivers/reset/reset-bcm6345.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/reset/reset-bcm6345.c b/drivers/reset/reset-bcm6345.c index aa9353439e70..56518f7bfbb3 100644 --- a/drivers/reset/reset-bcm6345.c +++ b/drivers/reset/reset-bcm6345.c @@ -119,6 +119,7 @@ static int bcm6345_reset_probe(struct platform_device *pdev) static const struct of_device_id bcm6345_reset_of_match[] = { { .compatible = "brcm,bcm6345-reset" }, + { .compatible = "brcm,bcm63xx-ephy-ctrl" }, { /* sentinel */ }, }; From 9c50f99c135384a4c1918e267c706f196820b214 Mon Sep 17 00:00:00 2001 From: Ryan Chen Date: Tue, 8 Jul 2025 13:29:08 +0800 Subject: [PATCH 00817/11391] 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 Link: https://lore.kernel.org/r/20250708052909.4145983-3-ryan_chen@aspeedtech.com Signed-off-by: Philipp Zabel --- 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 f443d7c9ed4642489d2f73a35e86df6228f65dfc Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Wed, 13 Aug 2025 16:17:15 +0800 Subject: [PATCH 00818/11391] dt-bindings: reset: thead,th1520-reset: add more VOSYS resets VOSYS contains more resets for a display pipeline, includes ones for the display controller (called DPU in the manual), the HDMI controller and 2 MIPI DSI controllers. Allocate IDs for these resets in the dt binding header file. Now all peripheral related VOSYS reset controls are here, only the bus matrix / IOPMP ones are missing, which shouldn't be messed with. Signed-off-by: Icenowy Zheng Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20250813081716.2181843-2-uwu@icenowy.me Signed-off-by: Philipp Zabel --- include/dt-bindings/reset/thead,th1520-reset.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/dt-bindings/reset/thead,th1520-reset.h b/include/dt-bindings/reset/thead,th1520-reset.h index 00459f160489..ee799286c175 100644 --- a/include/dt-bindings/reset/thead,th1520-reset.h +++ b/include/dt-bindings/reset/thead,th1520-reset.h @@ -12,5 +12,12 @@ #define TH1520_RESET_ID_NPU 2 #define TH1520_RESET_ID_WDT0 3 #define TH1520_RESET_ID_WDT1 4 +#define TH1520_RESET_ID_DPU_AHB 5 +#define TH1520_RESET_ID_DPU_AXI 6 +#define TH1520_RESET_ID_DPU_CORE 7 +#define TH1520_RESET_ID_DSI0_APB 8 +#define TH1520_RESET_ID_DSI1_APB 9 +#define TH1520_RESET_ID_HDMI 10 +#define TH1520_RESET_ID_HDMI_APB 11 #endif /* _DT_BINDINGS_TH1520_RESET_H */ From d342031a523835d5cbf959f74663ee405acefb2c Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Wed, 13 Aug 2025 16:17:16 +0800 Subject: [PATCH 00819/11391] reset: th1520: add resets for display pipeline The VO subsystem of TH1520 contains a few resets for the display pipeline -- display, MIPI DSI and HDMI controllers. Add support for them to the reset-th1520 driver. Signed-off-by: Icenowy Zheng Reviewed-by: Philipp Zabel Link: https://lore.kernel.org/r/20250813081716.2181843-3-uwu@icenowy.me Signed-off-by: Philipp Zabel --- drivers/reset/reset-th1520.c | 40 +++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/drivers/reset/reset-th1520.c b/drivers/reset/reset-th1520.c index 7874f0693e1b..06e5dff7c524 100644 --- a/drivers/reset/reset-th1520.c +++ b/drivers/reset/reset-th1520.c @@ -14,10 +14,20 @@ /* register offset in VOSYS_REGMAP */ #define TH1520_GPU_RST_CFG 0x0 #define TH1520_GPU_RST_CFG_MASK GENMASK(1, 0) +#define TH1520_DPU_RST_CFG 0x4 +#define TH1520_DSI0_RST_CFG 0x8 +#define TH1520_DSI1_RST_CFG 0xc +#define TH1520_HDMI_RST_CFG 0x14 /* register values */ #define TH1520_GPU_SW_GPU_RST BIT(0) #define TH1520_GPU_SW_CLKGEN_RST BIT(1) +#define TH1520_DPU_SW_DPU_HRST BIT(0) +#define TH1520_DPU_SW_DPU_ARST BIT(1) +#define TH1520_DPU_SW_DPU_CRST BIT(2) +#define TH1520_DSI_SW_DSI_PRST BIT(0) +#define TH1520_HDMI_SW_MAIN_RST BIT(0) +#define TH1520_HDMI_SW_PRST BIT(1) struct th1520_reset_priv { struct reset_controller_dev rcdev; @@ -37,7 +47,35 @@ static const struct th1520_reset_map th1520_resets[] = { [TH1520_RESET_ID_GPU_CLKGEN] = { .bit = TH1520_GPU_SW_CLKGEN_RST, .reg = TH1520_GPU_RST_CFG, - } + }, + [TH1520_RESET_ID_DPU_AHB] = { + .bit = TH1520_DPU_SW_DPU_HRST, + .reg = TH1520_DPU_RST_CFG, + }, + [TH1520_RESET_ID_DPU_AXI] = { + .bit = TH1520_DPU_SW_DPU_ARST, + .reg = TH1520_DPU_RST_CFG, + }, + [TH1520_RESET_ID_DPU_CORE] = { + .bit = TH1520_DPU_SW_DPU_CRST, + .reg = TH1520_DPU_RST_CFG, + }, + [TH1520_RESET_ID_DSI0_APB] = { + .bit = TH1520_DSI_SW_DSI_PRST, + .reg = TH1520_DSI0_RST_CFG, + }, + [TH1520_RESET_ID_DSI1_APB] = { + .bit = TH1520_DSI_SW_DSI_PRST, + .reg = TH1520_DSI1_RST_CFG, + }, + [TH1520_RESET_ID_HDMI] = { + .bit = TH1520_HDMI_SW_MAIN_RST, + .reg = TH1520_HDMI_RST_CFG, + }, + [TH1520_RESET_ID_HDMI_APB] = { + .bit = TH1520_HDMI_SW_PRST, + .reg = TH1520_HDMI_RST_CFG, + }, }; static inline struct th1520_reset_priv * From 1527cd3b89f0db8d71828f86a64dc901415f9be1 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 13 Aug 2025 18:15:02 +0200 Subject: [PATCH 00820/11391] reset: 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 Acked-by: Drew Fustini # for reset-th1520.c Link: https://lore.kernel.org/r/20250813161517.4746-17-wsa+renesas@sang-engineering.com Signed-off-by: Philipp Zabel --- drivers/reset/reset-intel-gw.c | 1 - drivers/reset/reset-qcom-pdc.c | 1 - drivers/reset/reset-th1520.c | 1 - 3 files changed, 3 deletions(-) diff --git a/drivers/reset/reset-intel-gw.c b/drivers/reset/reset-intel-gw.c index a5a01388ae7f..a5ce3350cb5e 100644 --- a/drivers/reset/reset-intel-gw.c +++ b/drivers/reset/reset-intel-gw.c @@ -40,7 +40,6 @@ static const struct regmap_config intel_rcu_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .fast_io = true, }; /* diff --git a/drivers/reset/reset-qcom-pdc.c b/drivers/reset/reset-qcom-pdc.c index dce1fc1a68ad..ae2b5aba7a59 100644 --- a/drivers/reset/reset-qcom-pdc.c +++ b/drivers/reset/reset-qcom-pdc.c @@ -36,7 +36,6 @@ static const struct regmap_config pdc_regmap_config = { .reg_stride = 4, .val_bits = 32, .max_register = 0x20000, - .fast_io = true, }; static const struct qcom_pdc_reset_map sdm845_pdc_resets[] = { diff --git a/drivers/reset/reset-th1520.c b/drivers/reset/reset-th1520.c index 06e5dff7c524..14d964a9c6b6 100644 --- a/drivers/reset/reset-th1520.c +++ b/drivers/reset/reset-th1520.c @@ -116,7 +116,6 @@ static const struct regmap_config th1520_reset_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, - .fast_io = true, }; static int th1520_reset_probe(struct platform_device *pdev) From 6d068f1ae2a2f713d7f21a9a602e65b3d6b6fc6d Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 14 Aug 2025 08:33:26 +0100 Subject: [PATCH 00821/11391] regulator: rt5133: Fix spelling mistake "regualtor" -> "regulator" There is a spelling mistake in a dev_err message. Fix it. Signed-off-by: Colin Ian King Link: https://patch.msgid.link/20250814073326.17644-1-colin.i.king@gmail.com Signed-off-by: Mark Brown --- drivers/regulator/rt5133-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/rt5133-regulator.c b/drivers/regulator/rt5133-regulator.c index d0f367381fbb..39532618e73d 100644 --- a/drivers/regulator/rt5133-regulator.c +++ b/drivers/regulator/rt5133-regulator.c @@ -511,7 +511,7 @@ static int rt5133_validate_vendor_info(struct rt5133_priv *priv) } } if (IS_ERR(priv->cdata)) { - dev_err(priv->dev, "Failed to find regualtor match version\n"); + dev_err(priv->dev, "Failed to find regulator match version\n"); return -ENODEV; } From 7bf9e646af9a0ceac57b27e62b71f750af096c2c Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Thu, 14 Aug 2025 17:21:53 +0800 Subject: [PATCH 00822/11391] ASoC: rt1321: Add RT1321 amplifier support This patch supported RT1321 amplifier. Signed-off-by: Shuming Fan Link: https://patch.msgid.link/20250814092153.2733592-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1320-sdw.c | 380 +++++++++++++++++++++++++++++----- sound/soc/codecs/rt1320-sdw.h | 10 + 2 files changed, 343 insertions(+), 47 deletions(-) diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c index b13d7a99bf63..94034182eb40 100644 --- a/sound/soc/codecs/rt1320-sdw.c +++ b/sound/soc/codecs/rt1320-sdw.c @@ -255,6 +255,161 @@ static const struct reg_sequence rt1320_vc_blind_write[] = { { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, }; +static const struct reg_sequence rt1321_blind_write[] = { + { 0x0000c003, 0xf0 }, + { 0x0000c01b, 0xfc }, + { 0x0000c5c3, 0xf2 }, + { 0x0000c5c2, 0x00 }, + { 0x0000c5c1, 0x10 }, + { 0x0000c5c0, 0x04 }, + { 0x0000c5c7, 0x03 }, + { 0x0000c5c6, 0x10 }, + { 0x0000c526, 0x47 }, + { 0x0000c5c4, 0x12 }, + { 0x0000c5c5, 0x60 }, + { 0x0000c520, 0x10 }, + { 0x0000c521, 0x32 }, + { 0x0000c5c7, 0x00 }, + { 0x0000c5c8, 0x03 }, + { 0x0000c5d3, 0x08 }, + { 0x0000c5d2, 0x0a }, + { 0x0000c5d1, 0x49 }, + { 0x0000c5d0, 0x0f }, + { 0x0000c580, 0x10 }, + { 0x0000c581, 0x32 }, + { 0x0000c582, 0x01 }, + { 0x0000cb00, 0x03 }, + { 0x0000cb02, 0x52 }, + { 0x0000cb04, 0x80 }, + { 0x0000cb0b, 0x01 }, + { 0x0000c682, 0x60 }, + { 0x0000c019, 0x10 }, + { 0x0000c5f0, 0x01 }, + { 0x0000c5f7, 0x22 }, + { 0x0000c5f6, 0x22 }, + { 0x0000c057, 0x51 }, + { 0x0000c054, 0x55 }, + { 0x0000c053, 0x55 }, + { 0x0000c052, 0x55 }, + { 0x0000c051, 0x01 }, + { 0x0000c050, 0x15 }, + { 0x0000c060, 0x99 }, + { 0x0000c030, 0x55 }, + { 0x0000c061, 0x55 }, + { 0x0000c063, 0x55 }, + { 0x0000c065, 0xa5 }, + { 0x0000c06b, 0x0a }, + { 0x0000ca05, 0xd6 }, + { 0x0000ca07, 0x07 }, + { 0x0000ca25, 0xd6 }, + { 0x0000ca27, 0x07 }, + { 0x0000cd00, 0x05 }, + { 0x0000c604, 0x40 }, + { 0x0000c609, 0x40 }, + { 0x0000c046, 0xf7 }, + { 0x0000c045, 0xff }, + { 0x0000c044, 0xff }, + { 0x0000c043, 0xff }, + { 0x0000c042, 0xff }, + { 0x0000c041, 0xff }, + { 0x0000c040, 0xff }, + { 0x0000c049, 0xff }, + { 0x0000c028, 0x3f }, + { 0x0000c020, 0x3f }, + { 0x0000c032, 0x13 }, + { 0x0000c033, 0x01 }, + { 0x0000cc10, 0x01 }, + { 0x0000dc20, 0x03 }, + { 0x0000de03, 0x05 }, + { 0x0000dc00, 0x00 }, + { 0x0000c700, 0xf0 }, + { 0x0000c701, 0x13 }, + { 0x0000c900, 0xc3 }, + { 0x0000c570, 0x08 }, + { 0x0000c086, 0x02 }, + { 0x0000c085, 0x7f }, + { 0x0000c084, 0x00 }, + { 0x0000c081, 0xff }, + { 0x0000f084, 0x0f }, + { 0x0000f083, 0xff }, + { 0x0000f082, 0xff }, + { 0x0000f081, 0xff }, + { 0x0000f080, 0xff }, + { 0x20003003, 0x3f }, + { 0x20005818, 0x81 }, + { 0x20009018, 0x81 }, + { 0x2000301c, 0x81 }, + { 0x0000c003, 0xc0 }, + { 0x0000c047, 0x80 }, + { 0x0000d541, 0x80 }, + { 0x0000d487, 0x0b }, + { 0x0000d487, 0x3b }, + { 0x0000d486, 0xc3 }, + { 0x0000d470, 0x89 }, + { 0x0000d471, 0x3a }, + { 0x0000d472, 0x1d }, + { 0x0000d478, 0xff }, + { 0x0000d479, 0x20 }, + { 0x0000d47a, 0x10 }, + { 0x0000d73c, 0xb7 }, + { 0x0000d73d, 0xd7 }, + { 0x0000d73e, 0x00 }, + { 0x0000d73f, 0x10 }, + { 0x3fc2dfc3, 0x00 }, + { 0x3fc2dfc2, 0x00 }, + { 0x3fc2dfc1, 0x00 }, + { 0x3fc2dfc0, 0x07 }, + { 0x3fc2dfc7, 0x00 }, + { 0x3fc2dfc6, 0x00 }, + { 0x3fc2dfc5, 0x00 }, + { 0x3fc2dfc4, 0x01 }, + { 0x3fc2df83, 0x00 }, + { 0x3fc2df82, 0x00 }, + { 0x3fc2df81, 0x00 }, + { 0x3fc2df80, 0x00 }, + { 0x0000d541, 0x40 }, + { 0x0000d486, 0x43 }, + { 0x1000db00, 0x03 }, + { 0x1000db01, 0x00 }, + { 0x1000db02, 0x10 }, + { 0x1000db03, 0x00 }, + { 0x1000db04, 0x00 }, + { 0x1000db05, 0x45 }, + { 0x1000db06, 0x12 }, + { 0x1000db07, 0x09 }, + { 0x1000db08, 0x00 }, + { 0x1000db09, 0x00 }, + { 0x1000db0a, 0x00 }, + { 0x1000db0b, 0x13 }, + { 0x1000db0c, 0x09 }, + { 0x1000db0d, 0x00 }, + { 0x1000db0e, 0x00 }, + { 0x1000db0f, 0x00 }, + { 0x0000d540, 0x21 }, + { 0x41000189, 0x00 }, + { 0x4100018a, 0x00 }, + { 0x41001988, 0x00 }, + { 0x41081400, 0x09 }, + { 0x40801508, 0x03 }, + { 0x40801588, 0x03 }, + { 0x40801809, 0x00 }, + { 0x4080180a, 0x00 }, + { 0x4080180b, 0x00 }, + { 0x4080180c, 0x00 }, + { 0x40801b09, 0x00 }, + { 0x40801b0a, 0x00 }, + { 0x40801b0b, 0x00 }, + { 0x40801b0c, 0x00 }, + { 0x0000d714, 0x17 }, + { 0x20009012, 0x00 }, + { 0x0000dd0b, 0x0d }, + { 0x0000dd0a, 0xff }, + { 0x0000dd09, 0x0d }, + { 0x0000dd08, 0xff }, + { 0x0000d172, 0x2a }, + { 0x41001988, 0x03 }, +}; + static const struct reg_default rt1320_reg_defaults[] = { { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, @@ -339,10 +494,19 @@ static bool rt1320_readable_register(struct device *dev, unsigned int reg) case 0xf717 ... 0xf719: case 0xf720 ... 0xf723: case 0x1000cd91 ... 0x1000cd96: + case RT1321_PATCH_MAIN_VER ... RT1321_PATCH_BETA_VER: case 0x1000f008: case 0x1000f021: + case 0x2000300f: + case 0x2000301c: + case 0x2000900f: + case 0x20009018: + case 0x3fc29d80 ... 0x3fc29d83: case 0x3fe2e000 ... 0x3fe2e003: case 0x3fc2ab80 ... 0x3fc2abd4: + case 0x3fc2bfc0 ... 0x3fc2bfc8: + case 0x3fc2d300 ... 0x3fc2d354: + case 0x3fc2dfc0 ... 0x3fc2dfc8: /* 0x40801508/0x40801809/0x4080180a/0x40801909/0x4080190a */ case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_REQ_POWER_STATE, 0): case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_01): @@ -393,6 +557,7 @@ static bool rt1320_volatile_register(struct device *dev, unsigned int reg) case 0xc560: case 0xc5b5 ... 0xc5b7: case 0xc5fc ... 0xc5ff: + case 0xc680 ... 0xc683: case 0xc820: case 0xc900: case 0xc920: @@ -411,7 +576,7 @@ static bool rt1320_volatile_register(struct device *dev, unsigned int reg) case 0xd4e5 ... 0xd4e6: case 0xd4e8 ... 0xd4ff: case 0xd530: - case 0xd540: + case 0xd540 ... 0xd541: case 0xd543: case 0xdb58 ... 0xdb5f: case 0xdb60 ... 0xdb63: @@ -428,13 +593,20 @@ static bool rt1320_volatile_register(struct device *dev, unsigned int reg) case 0xf01e: case 0xf717 ... 0xf719: case 0xf720 ... 0xf723: - case 0x10000000 ... 0x10007fff: + case 0x10000000 ... 0x10008fff: case 0x1000c000 ... 0x1000dfff: case 0x1000f008: case 0x1000f021: + case 0x2000300f: + case 0x2000301c: + case 0x2000900f: + case 0x20009018: case 0x3fc2ab80 ... 0x3fc2abd4: + case 0x3fc2b780: case 0x3fc2bf80 ... 0x3fc2bf83: - case 0x3fc2bfc0 ... 0x3fc2bfc7: + case 0x3fc2bfc0 ... 0x3fc2bfc8: + case 0x3fc2d300 ... 0x3fc2d354: + case 0x3fc2dfc0 ... 0x3fc2dfc8: case 0x3fe2e000 ... 0x3fe2e003: case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0): case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT0, RT1320_SDCA_CTL_FUNC_STATUS, 0): @@ -559,7 +731,7 @@ static int rt1320_read_prop(struct sdw_slave *slave) static int rt1320_pde_transition_delay(struct rt1320_sdw_priv *rt1320, unsigned char func, unsigned char entity, unsigned char ps) { - unsigned int delay = 1000, val; + unsigned int delay = 2000, val; pm_runtime_mark_last_busy(&rt1320->sdw_slave->dev); @@ -590,24 +762,44 @@ static void rt1320_load_mcu_patch(struct rt1320_sdw_priv *rt1320) struct sdw_slave *slave = rt1320->sdw_slave; const struct firmware *patch; const char *filename; - unsigned int addr, val; + unsigned int addr, val, min_addr, max_addr; const unsigned char *ptr; int ret, i; - if (rt1320->version_id <= RT1320_VB) - filename = RT1320_VAB_MCU_PATCH; - else - filename = RT1320_VC_MCU_PATCH; + switch (rt1320->dev_id) { + case RT1320_DEV_ID: + if (rt1320->version_id <= RT1320_VB) + filename = RT1320_VAB_MCU_PATCH; + else + filename = RT1320_VC_MCU_PATCH; + min_addr = 0x10007000; + max_addr = 0x10007fff; + break; + case RT1321_DEV_ID: + filename = RT1321_VA_MCU_PATCH; + min_addr = 0x10008000; + max_addr = 0x10008fff; + break; + default: + dev_err(&slave->dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); + return; + } /* load the patch code here */ ret = request_firmware(&patch, filename, &slave->dev); if (ret) { dev_err(&slave->dev, "%s: Failed to load %s firmware", __func__, filename); regmap_write(rt1320->regmap, 0xc598, 0x00); - regmap_write(rt1320->regmap, 0x10007000, 0x67); - regmap_write(rt1320->regmap, 0x10007001, 0x80); - regmap_write(rt1320->regmap, 0x10007002, 0x00); - regmap_write(rt1320->regmap, 0x10007003, 0x00); + regmap_write(rt1320->regmap, min_addr, 0x67); + regmap_write(rt1320->regmap, min_addr + 0x1, 0x80); + regmap_write(rt1320->regmap, min_addr + 0x2, 0x00); + regmap_write(rt1320->regmap, min_addr + 0x3, 0x00); + if (rt1320->dev_id == RT1321_DEV_ID) { + regmap_write(rt1320->regmap, 0xd73c, 0x67); + regmap_write(rt1320->regmap, 0xd73d, 0x80); + regmap_write(rt1320->regmap, 0xd73e, 0x00); + regmap_write(rt1320->regmap, 0xd73f, 0x00); + } } else { ptr = (const unsigned char *)patch->data; if ((patch->size % 8) == 0) { @@ -617,7 +809,7 @@ static void rt1320_load_mcu_patch(struct rt1320_sdw_priv *rt1320) val = (ptr[i + 4] & 0xff) | (ptr[i + 5] & 0xff) << 8 | (ptr[i + 6] & 0xff) << 16 | (ptr[i + 7] & 0xff) << 24; - if (addr > 0x10007fff || addr < 0x10007000) { + if (addr > max_addr || addr < min_addr) { dev_err(&slave->dev, "%s: the address 0x%x is wrong", __func__, addr); goto _exit_; } @@ -687,6 +879,28 @@ static void rt1320_vc_preset(struct rt1320_sdw_priv *rt1320) } } +static void rt1321_preset(struct rt1320_sdw_priv *rt1320) +{ + unsigned int i, reg, val, delay; + + for (i = 0; i < ARRAY_SIZE(rt1321_blind_write); i++) { + reg = rt1321_blind_write[i].reg; + val = rt1321_blind_write[i].def; + delay = rt1321_blind_write[i].delay_us; + + if (reg == 0x3fc2dfc3) + rt1320_load_mcu_patch(rt1320); + + regmap_write(rt1320->regmap, reg, val); + + if (delay) + usleep_range(delay, delay + 1000); + + if (reg == SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0)) + rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, val); + } +} + static int rt1320_io_init(struct device *dev, struct sdw_slave *slave) { struct rt1320_sdw_priv *rt1320 = dev_get_drvdata(dev); @@ -713,6 +927,9 @@ static int rt1320_io_init(struct device *dev, struct sdw_slave *slave) if (rt1320->version_id < 0) { regmap_read(rt1320->regmap, RT1320_DEV_VERSION_ID_1, &val); rt1320->version_id = val; + regmap_read(rt1320->regmap, RT1320_DEV_ID_0, &val); + regmap_read(rt1320->regmap, RT1320_DEV_ID_1, &tmp); + rt1320->dev_id = (val << 8) | tmp; } regmap_read(rt1320->regmap, @@ -721,16 +938,25 @@ static int rt1320_io_init(struct device *dev, struct sdw_slave *slave) /* initialization write */ if ((amp_func_status & FUNCTION_NEEDS_INITIALIZATION)) { - if (rt1320->version_id < RT1320_VC) - rt1320_vab_preset(rt1320); - else - rt1320_vc_preset(rt1320); + switch (rt1320->dev_id) { + case RT1320_DEV_ID: + if (rt1320->version_id < RT1320_VC) + rt1320_vab_preset(rt1320); + else + rt1320_vc_preset(rt1320); + break; + case RT1321_DEV_ID: + rt1321_preset(rt1320); + break; + default: + dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); + } regmap_write(rt1320->regmap, SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT0, RT1320_SDCA_CTL_FUNC_STATUS, 0), FUNCTION_NEEDS_INITIALIZATION); } - if (!rt1320->first_hw_init && rt1320->version_id == RT1320_VA) { + if (!rt1320->first_hw_init && rt1320->version_id == RT1320_VA && rt1320->dev_id == RT1320_DEV_ID) { regmap_write(rt1320->regmap, SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0); regmap_read(rt1320->regmap, RT1320_HIFI_VER_0, &val); @@ -750,7 +976,7 @@ static int rt1320_io_init(struct device *dev, struct sdw_slave *slave) regmap_write(rt1320->regmap, SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 3); } - dev_dbg(dev, "%s version_id=%d\n", __func__, rt1320->version_id); + dev_dbg(dev, "%s version_id=%d, dev_id=0x%x\n", __func__, rt1320->version_id, rt1320->dev_id); if (rt1320->first_hw_init) { regcache_cache_bypass(rt1320->regmap, false); @@ -893,12 +1119,20 @@ static int rt1320_set_gain_put(struct snd_kcontrol *kcontrol, /* check all channels */ for (i = 0; i < p->count; i++) { - if (i < 2) { + switch (rt1320->dev_id) { + case RT1320_DEV_ID: + if (i < 2) { + reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01); + regmap_read(rt1320->mbq_regmap, reg_base + i, ®value[i]); + } else { + reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01); + regmap_read(rt1320->mbq_regmap, reg_base + i - 2, ®value[i]); + } + break; + case RT1321_DEV_ID: reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01); regmap_read(rt1320->mbq_regmap, reg_base + i, ®value[i]); - } else { - reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01); - regmap_read(rt1320->mbq_regmap, reg_base + i - 2, ®value[i]); + break; } gain_val[i] = ucontrol->value.integer.value[i]; @@ -915,12 +1149,20 @@ static int rt1320_set_gain_put(struct snd_kcontrol *kcontrol, return 0; for (i = 0; i < p->count; i++) { - if (i < 2) { + switch (rt1320->dev_id) { + case RT1320_DEV_ID: + if (i < 2) { + reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01); + err = regmap_write(rt1320->mbq_regmap, reg_base + i, gain_val[i]); + } else { + reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01); + err = regmap_write(rt1320->mbq_regmap, reg_base + i - 2, gain_val[i]); + } + break; + case RT1321_DEV_ID: reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01); err = regmap_write(rt1320->mbq_regmap, reg_base + i, gain_val[i]); - } else { - reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01); - err = regmap_write(rt1320->mbq_regmap, reg_base + i - 2, gain_val[i]); + break; } if (err < 0) @@ -965,12 +1207,20 @@ static int rt1320_set_gain_get(struct snd_kcontrol *kcontrol, /* check all channels */ for (i = 0; i < p->count; i++) { - if (i < 2) { + switch (rt1320->dev_id) { + case RT1320_DEV_ID: + if (i < 2) { + reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01); + regmap_read(rt1320->mbq_regmap, reg_base + i, ®value); + } else { + reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01); + regmap_read(rt1320->mbq_regmap, reg_base + i - 2, ®value); + } + break; + case RT1321_DEV_ID: reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01); regmap_read(rt1320->mbq_regmap, reg_base + i, ®value); - } else { - reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01); - regmap_read(rt1320->mbq_regmap, reg_base + i - 2, ®value); + break; } ctl = p->max - (((0x1e00 - regvalue) & 0xffff) / interval_offset); @@ -988,14 +1238,26 @@ static int rt1320_set_fu_capture_ctl(struct rt1320_sdw_priv *rt1320) for (i = 0; i < ARRAY_SIZE(rt1320->fu_mixer_mute); i++) { ch_mute = (rt1320->fu_dapm_mute || rt1320->fu_mixer_mute[i]) ? 0x01 : 0x00; - if (i < 2) + switch (rt1320->dev_id) { + case RT1320_DEV_ID: + if (i < 2) + err = regmap_write(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, + RT1320_SDCA_CTL_FU_MUTE, CH_01) + i, ch_mute); + else + err = regmap_write(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, + RT1320_SDCA_CTL_FU_MUTE, CH_01) + i - 2, ch_mute); + break; + case RT1321_DEV_ID: err = regmap_write(rt1320->regmap, SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_01) + i, ch_mute); - else - err = regmap_write(rt1320->regmap, - SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, - RT1320_SDCA_CTL_FU_MUTE, CH_01) + i - 2, ch_mute); + break; + default: + dev_err(&rt1320->sdw_slave->dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); + return -EINVAL; + } if (err < 0) return err; } @@ -1216,10 +1478,20 @@ static int rt1320_sdw_hw_params(struct snd_pcm_substream *substream, if (dai->id == RT1320_AIF1) port_config.num = 4; else if (dai->id == RT1320_AIF2) { - dmic_port_config[0].ch_mask = BIT(0) | BIT(1); - dmic_port_config[0].num = 8; - dmic_port_config[1].ch_mask = BIT(0) | BIT(1); - dmic_port_config[1].num = 10; + switch (rt1320->dev_id) { + case RT1320_DEV_ID: + dmic_port_config[0].ch_mask = BIT(0) | BIT(1); + dmic_port_config[0].num = 8; + dmic_port_config[1].ch_mask = BIT(0) | BIT(1); + dmic_port_config[1].num = 10; + break; + case RT1321_DEV_ID: + dmic_port_config[0].ch_mask = BIT(0) | BIT(1); + dmic_port_config[0].num = 8; + break; + default: + return -EINVAL; + } } else return -EINVAL; } @@ -1227,10 +1499,21 @@ static int rt1320_sdw_hw_params(struct snd_pcm_substream *substream, if (dai->id == RT1320_AIF1) retval = sdw_stream_add_slave(rt1320->sdw_slave, &stream_config, &port_config, 1, sdw_stream); - else if (dai->id == RT1320_AIF2) - retval = sdw_stream_add_slave(rt1320->sdw_slave, &stream_config, + else if (dai->id == RT1320_AIF2) { + switch (rt1320->dev_id) { + case RT1320_DEV_ID: + retval = sdw_stream_add_slave(rt1320->sdw_slave, &stream_config, dmic_port_config, 2, sdw_stream); - else + break; + case RT1321_DEV_ID: + retval = sdw_stream_add_slave(rt1320->sdw_slave, &stream_config, + dmic_port_config, 1, sdw_stream); + break; + default: + dev_err(dai->dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); + return -EINVAL; + } + } else return -EINVAL; if (retval) { dev_err(dai->dev, "%s: Unable to configure port\n", __func__); @@ -1272,9 +1555,11 @@ static int rt1320_sdw_hw_params(struct snd_pcm_substream *substream, regmap_write(rt1320->regmap, SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS113, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate); - regmap_write(rt1320->regmap, - SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS14, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), - sampling_rate); + + if (rt1320->dev_id == RT1320_DEV_ID) + regmap_write(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS14, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), + sampling_rate); } return 0; @@ -1468,6 +1753,7 @@ static int rt1320_sdw_remove(struct sdw_slave *slave) static const struct sdw_device_id rt1320_id[] = { SDW_SLAVE_ENTRY_EXT(0x025d, 0x1320, 0x3, 0x0, 0), SDW_SLAVE_ENTRY_EXT(0x025d, 0x1320, 0x3, 0x1, 0), + SDW_SLAVE_ENTRY_EXT(0x025d, 0x1321, 0x3, 0x1, 0), {}, }; MODULE_DEVICE_TABLE(sdw, rt1320_id); diff --git a/sound/soc/codecs/rt1320-sdw.h b/sound/soc/codecs/rt1320-sdw.h index 23b321aee6a9..a6d90e259dc9 100644 --- a/sound/soc/codecs/rt1320-sdw.h +++ b/sound/soc/codecs/rt1320-sdw.h @@ -14,8 +14,16 @@ #include #include +#define RT1320_DEV_ID 0x6981 +#define RT1321_DEV_ID 0x7045 + /* imp-defined registers */ #define RT1320_DEV_VERSION_ID_1 0xc404 +#define RT1320_DEV_ID_1 0xc405 +#define RT1320_DEV_ID_0 0xc406 + +#define RT1321_PATCH_MAIN_VER 0x1000cffe +#define RT1321_PATCH_BETA_VER 0x1000cfff #define RT1320_KR0_STATUS_CNT 0x1000f008 #define RT1320_KR0_INT_READY 0x1000f021 @@ -86,6 +94,7 @@ enum rt1320_version_id { #define RT1320_VER_B_ID 0x07392238 #define RT1320_VAB_MCU_PATCH "realtek/rt1320/rt1320-patch-code-vab.bin" #define RT1320_VC_MCU_PATCH "realtek/rt1320/rt1320-patch-code-vc.bin" +#define RT1321_VA_MCU_PATCH "realtek/rt1320/rt1321-patch-code-va.bin" struct rt1320_sdw_priv { struct snd_soc_component *component; @@ -96,6 +105,7 @@ struct rt1320_sdw_priv { bool hw_init; bool first_hw_init; int version_id; + unsigned int dev_id; bool fu_dapm_mute; bool fu_mixer_mute[4]; }; From d578faf7096affc036fd16333f1bfbe4991a22f7 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 13 Aug 2025 18:15:07 +0200 Subject: [PATCH 00823/11391] ASoC: 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-22-wsa+renesas@sang-engineering.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index c313b654236c..cf1915b93d78 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -1244,7 +1244,6 @@ static struct regmap_config fsl_sai_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .fast_io = true, .max_register = FSL_SAI_RMR, .reg_defaults = fsl_sai_reg_defaults_ofs0, From 258384d8ce365dddd6c5c15204de8ccd53a7ab0a Mon Sep 17 00:00:00 2001 From: Shimrra Shai Date: Wed, 13 Aug 2025 20:49:19 -0500 Subject: [PATCH 00824/11391] ASoC: es8323: enable DAPM power widgets for playback DAC and output Enable DAPM widgets for power and volume control of playback. Signed-off-by: Shimrra Shai Link: https://patch.msgid.link/20250814014919.87170-1-shimrrashai@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8323.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/es8323.c b/sound/soc/codecs/es8323.c index a9822998199f..70d348ff3b43 100644 --- a/sound/soc/codecs/es8323.c +++ b/sound/soc/codecs/es8323.c @@ -211,8 +211,8 @@ static const struct snd_soc_dapm_widget es8323_dapm_widgets[] = { SND_SOC_DAPM_ADC("Right ADC", "Right Capture", SND_SOC_NOPM, 4, 1), SND_SOC_DAPM_ADC("Left ADC", "Left Capture", SND_SOC_NOPM, 5, 1), - SND_SOC_DAPM_DAC("Right DAC", "Right Playback", SND_SOC_NOPM, 6, 1), - SND_SOC_DAPM_DAC("Left DAC", "Left Playback", SND_SOC_NOPM, 7, 1), + SND_SOC_DAPM_DAC("Right DAC", "Right Playback", ES8323_DACPOWER, 6, 1), + SND_SOC_DAPM_DAC("Left DAC", "Left Playback", ES8323_DACPOWER, 7, 1), SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0, &es8323_left_mixer_controls[0], @@ -223,10 +223,10 @@ static const struct snd_soc_dapm_widget es8323_dapm_widgets[] = { SND_SOC_DAPM_PGA("Right ADC Power", SND_SOC_NOPM, 6, 1, NULL, 0), SND_SOC_DAPM_PGA("Left ADC Power", SND_SOC_NOPM, 7, 1, NULL, 0), - SND_SOC_DAPM_PGA("Right Out 2", SND_SOC_NOPM, 2, 0, NULL, 0), - SND_SOC_DAPM_PGA("Left Out 2", SND_SOC_NOPM, 3, 0, NULL, 0), - SND_SOC_DAPM_PGA("Right Out 1", SND_SOC_NOPM, 4, 0, NULL, 0), - SND_SOC_DAPM_PGA("Left Out 1", SND_SOC_NOPM, 5, 0, NULL, 0), + SND_SOC_DAPM_PGA("Right Out 2", ES8323_DACPOWER, 2, 0, NULL, 0), + SND_SOC_DAPM_PGA("Left Out 2", ES8323_DACPOWER, 3, 0, NULL, 0), + SND_SOC_DAPM_PGA("Right Out 1", ES8323_DACPOWER, 4, 0, NULL, 0), + SND_SOC_DAPM_PGA("Left Out 1", ES8323_DACPOWER, 5, 0, NULL, 0), SND_SOC_DAPM_PGA("LAMP", ES8323_ADCCONTROL1, 4, 0, NULL, 0), SND_SOC_DAPM_PGA("RAMP", ES8323_ADCCONTROL1, 0, 0, NULL, 0), From f93dd842719b123cfad6385a32acf6386a3c7659 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Thu, 7 Aug 2025 16:45:07 -0500 Subject: [PATCH 00825/11391] dt-bindings: display: Drop duplicate ti,opa362 binding The "ti,opa362" binding is already supported in simple-bridge.yaml, so remove the old binding doc. Acked-by: Conor Dooley Reviewed-by: Tomi Valkeinen Link: https://lore.kernel.org/r/20250807214508.4174167-1-robh@kernel.org Signed-off-by: Rob Herring (Arm) --- .../bindings/display/ti/ti,opa362.txt | 38 ------------------- 1 file changed, 38 deletions(-) delete mode 100644 Documentation/devicetree/bindings/display/ti/ti,opa362.txt diff --git a/Documentation/devicetree/bindings/display/ti/ti,opa362.txt b/Documentation/devicetree/bindings/display/ti/ti,opa362.txt deleted file mode 100644 index f96083c0bd17..000000000000 --- a/Documentation/devicetree/bindings/display/ti/ti,opa362.txt +++ /dev/null @@ -1,38 +0,0 @@ -OPA362 analog video amplifier - -Required properties: -- compatible: "ti,opa362" -- enable-gpios: enable/disable output gpio - -Required node: -- Video port 0 for opa362 input -- Video port 1 for opa362 output - -Example: - -tv_amp: opa362 { - compatible = "ti,opa362"; - enable-gpios = <&gpio1 23 0>; /* GPIO to enable video out amplifier */ - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - opa_in: endpoint@0 { - remote-endpoint = <&venc_out>; - }; - }; - - port@1 { - reg = <1>; - opa_out: endpoint@0 { - remote-endpoint = <&tv_connector_in>; - }; - }; - }; -}; - - - From 6b8c52b41be4b3940f38b037cc953505aeb5768c Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Wed, 6 Aug 2025 16:27:40 -0500 Subject: [PATCH 00826/11391] dt-bindings: arm: Convert cavium,thunder-88xx to DT schema Convert Cavium Thunder-88xx boards to DT schema format. There's not any defined board compatibles in this case. Link: https://lore.kernel.org/r/20250806212741.1633917-1-robh@kernel.org Signed-off-by: Rob Herring (Arm) --- .../bindings/arm/cavium,thunder-88xx.yaml | 19 +++++++++++++++++++ .../bindings/arm/cavium-thunder.txt | 10 ---------- 2 files changed, 19 insertions(+), 10 deletions(-) create mode 100644 Documentation/devicetree/bindings/arm/cavium,thunder-88xx.yaml delete mode 100644 Documentation/devicetree/bindings/arm/cavium-thunder.txt diff --git a/Documentation/devicetree/bindings/arm/cavium,thunder-88xx.yaml b/Documentation/devicetree/bindings/arm/cavium,thunder-88xx.yaml new file mode 100644 index 000000000000..d7c813118c1c --- /dev/null +++ b/Documentation/devicetree/bindings/arm/cavium,thunder-88xx.yaml @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/cavium,thunder-88xx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Cavium Thunder 88xx SoC + +maintainers: + - Robert Richter + +properties: + $nodename: + const: '/' + compatible: + items: + - const: cavium,thunder-88xx + +additionalProperties: true diff --git a/Documentation/devicetree/bindings/arm/cavium-thunder.txt b/Documentation/devicetree/bindings/arm/cavium-thunder.txt deleted file mode 100644 index 6f63a5866902..000000000000 --- a/Documentation/devicetree/bindings/arm/cavium-thunder.txt +++ /dev/null @@ -1,10 +0,0 @@ -Cavium Thunder platform device tree bindings --------------------------------------------- - -Boards with Cavium's Thunder SoC shall have following properties. - -Root Node ---------- -Required root node properties: - - - compatible = "cavium,thunder-88xx"; From f56fbb6a1b36da1d481d7ce8245f7bedad3aa863 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Wed, 6 Aug 2025 16:28:11 -0500 Subject: [PATCH 00827/11391] dt-bindings: arm: Drop obsolete cavium-thunder2.txt The binding is already converted to schema and is located in Documentation/devicetree/bindings/arm/bcm/brcm,vulcan-soc.yaml. Link: https://lore.kernel.org/r/20250806212812.1634740-1-robh@kernel.org Signed-off-by: Rob Herring (Arm) --- Documentation/devicetree/bindings/arm/cavium-thunder2.txt | 8 -------- MAINTAINERS | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) delete mode 100644 Documentation/devicetree/bindings/arm/cavium-thunder2.txt diff --git a/Documentation/devicetree/bindings/arm/cavium-thunder2.txt b/Documentation/devicetree/bindings/arm/cavium-thunder2.txt deleted file mode 100644 index dc5dd65cbce7..000000000000 --- a/Documentation/devicetree/bindings/arm/cavium-thunder2.txt +++ /dev/null @@ -1,8 +0,0 @@ -Cavium ThunderX2 CN99XX platform tree bindings ----------------------------------------------- - -Boards with Cavium ThunderX2 CN99XX SoC shall have the root property: - compatible = "cavium,thunderx2-cn9900", "brcm,vulcan-soc"; - -These SoC uses the "cavium,thunder2" core which will be compatible -with "brcm,vulcan". diff --git a/MAINTAINERS b/MAINTAINERS index c2cf508e6379..7969d09dff17 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5545,7 +5545,7 @@ CAVIUM THUNDERX2 ARM64 SOC M: Robert Richter L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Odd Fixes -F: Documentation/devicetree/bindings/arm/cavium-thunder2.txt +F: Documentation/devicetree/bindings/arm/bcm/brcm,vulcan-soc.yaml F: arch/arm64/boot/dts/cavium/thunder2-99xx* CBS/ETF/TAPRIO QDISCS From 2412f16c9afa7710778fc032139a6df38b68fd7c Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 14 Aug 2025 16:50:07 +0300 Subject: [PATCH 00828/11391] media: v4l2-common: Improve devm_v4l2_sensor_clk_get() documentation Remove the extra leading period and provide more elaborate explanation for why devm_v4l2_sensor_clk_get() is only allowed to be used on camera sensor devices. Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- include/media/v4l2-common.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index 9d6c236e8f14..39dd0c78d70f 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h @@ -623,7 +623,7 @@ int v4l2_link_freq_to_bitmap(struct device *dev, const u64 *fw_link_freqs, /** * devm_v4l2_sensor_clk_get - lookup and obtain a reference to a clock producer - * for a camera sensor. + * for a camera sensor * * @dev: device for v4l2 sensor clock "consumer" * @id: clock consumer ID @@ -643,6 +643,14 @@ int v4l2_link_freq_to_bitmap(struct device *dev, const u64 *fw_link_freqs, * * In this case try to set the clock-frequency value to the provided clock. * + * As the name indicates, this function may only be used on camera sensor + * devices. This is because generally only camera sensors do need a clock to + * query the frequency from, due to the requirement to configure the PLL for a + * given CSI-2 interface frequency where the sensor's external clock frequency + * is a factor. Additionally, the clock frequency tends to be available on ACPI + * firmware based systems for camera sensors specifically (if e.g. DisCo for + * Imaging compliant). + * * Returns a pointer to a struct clk on success or an error pointer on failure. */ struct clk *devm_v4l2_sensor_clk_get(struct device *dev, const char *id); From a46e95c81e3a28926ab1904d9f754fef8318074d Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Wed, 25 Jun 2025 14:32:56 +0100 Subject: [PATCH 00829/11391] ASoC: wl1273: Remove The wl1273 FM radio is on Arnd's unused driver list: https://lore.kernel.org/lkml/a15bb180-401d-49ad-a212-0c81d613fbc8@app.fastmail.com/ Remove the codec component. Signed-off-by: Dr. David Alan Gilbert Acked-by: Arnd Bergmann Link: https://patch.msgid.link/20250625133258.78133-3-linux@treblig.org Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 4 - sound/soc/codecs/Makefile | 2 - sound/soc/codecs/wl1273.c | 500 -------------------------------------- sound/soc/codecs/wl1273.h | 16 -- 4 files changed, 522 deletions(-) delete mode 100644 sound/soc/codecs/wl1273.c delete mode 100644 sound/soc/codecs/wl1273.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 099b4ce4f910..b8d58d2fe326 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -301,7 +301,6 @@ config SND_SOC_ALL_CODECS imply SND_SOC_LPASS_MACRO_COMMON imply SND_SOC_LPASS_RX_MACRO imply SND_SOC_LPASS_TX_MACRO - imply SND_SOC_WL1273 imply SND_SOC_WM0010 imply SND_SOC_WM1250_EV1 imply SND_SOC_WM2000 @@ -2335,9 +2334,6 @@ config SND_SOC_WCD939X_SDW The WCD9390/9395 is a audio codec IC Integrated in Qualcomm SoCs like SM8650. -config SND_SOC_WL1273 - tristate - config SND_SOC_WM0010 tristate depends on SPI_MASTER diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 3f97afaaaed8..a476d6c45451 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -350,7 +350,6 @@ snd-soc-wcd938x-y := wcd938x.o snd-soc-wcd938x-sdw-y := wcd938x-sdw.o snd-soc-wcd939x-y := wcd939x.o snd-soc-wcd939x-sdw-y := wcd939x-sdw.o -snd-soc-wl1273-y := wl1273.o snd-soc-wm-adsp-y := wm_adsp.o snd-soc-wm0010-y := wm0010.o snd-soc-wm1250-ev1-y := wm1250-ev1.o @@ -783,7 +782,6 @@ ifdef CONFIG_SND_SOC_WCD939X_SDW # avoid link failure by forcing sdw code built-in when needed obj-$(CONFIG_SND_SOC_WCD939X) += snd-soc-wcd939x-sdw.o endif -obj-$(CONFIG_SND_SOC_WL1273) += snd-soc-wl1273.o obj-$(CONFIG_SND_SOC_WM0010) += snd-soc-wm0010.o obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o obj-$(CONFIG_SND_SOC_WM2000) += snd-soc-wm2000.o diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c deleted file mode 100644 index 737ca82cf976..000000000000 --- a/sound/soc/codecs/wl1273.c +++ /dev/null @@ -1,500 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * ALSA SoC WL1273 codec driver - * - * Author: Matti Aaltonen, - * - * Copyright: (C) 2010, 2011 Nokia Corporation - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "wl1273.h" - -enum wl1273_mode { WL1273_MODE_BT, WL1273_MODE_FM_RX, WL1273_MODE_FM_TX }; - -/* codec private data */ -struct wl1273_priv { - enum wl1273_mode mode; - struct wl1273_core *core; - unsigned int channels; -}; - -static int snd_wl1273_fm_set_i2s_mode(struct wl1273_core *core, - int rate, int width) -{ - struct device *dev = &core->client->dev; - int r = 0; - u16 mode; - - dev_dbg(dev, "rate: %d\n", rate); - dev_dbg(dev, "width: %d\n", width); - - mutex_lock(&core->lock); - - mode = core->i2s_mode & ~WL1273_IS2_WIDTH & ~WL1273_IS2_RATE; - - switch (rate) { - case 48000: - mode |= WL1273_IS2_RATE_48K; - break; - case 44100: - mode |= WL1273_IS2_RATE_44_1K; - break; - case 32000: - mode |= WL1273_IS2_RATE_32K; - break; - case 22050: - mode |= WL1273_IS2_RATE_22_05K; - break; - case 16000: - mode |= WL1273_IS2_RATE_16K; - break; - case 12000: - mode |= WL1273_IS2_RATE_12K; - break; - case 11025: - mode |= WL1273_IS2_RATE_11_025; - break; - case 8000: - mode |= WL1273_IS2_RATE_8K; - break; - default: - dev_err(dev, "Sampling rate: %d not supported\n", rate); - r = -EINVAL; - goto out; - } - - switch (width) { - case 16: - mode |= WL1273_IS2_WIDTH_32; - break; - case 20: - mode |= WL1273_IS2_WIDTH_40; - break; - case 24: - mode |= WL1273_IS2_WIDTH_48; - break; - case 25: - mode |= WL1273_IS2_WIDTH_50; - break; - case 30: - mode |= WL1273_IS2_WIDTH_60; - break; - case 32: - mode |= WL1273_IS2_WIDTH_64; - break; - case 40: - mode |= WL1273_IS2_WIDTH_80; - break; - case 48: - mode |= WL1273_IS2_WIDTH_96; - break; - case 64: - mode |= WL1273_IS2_WIDTH_128; - break; - default: - dev_err(dev, "Data width: %d not supported\n", width); - r = -EINVAL; - goto out; - } - - dev_dbg(dev, "WL1273_I2S_DEF_MODE: 0x%04x\n", WL1273_I2S_DEF_MODE); - dev_dbg(dev, "core->i2s_mode: 0x%04x\n", core->i2s_mode); - dev_dbg(dev, "mode: 0x%04x\n", mode); - - if (core->i2s_mode != mode) { - r = core->write(core, WL1273_I2S_MODE_CONFIG_SET, mode); - if (r) - goto out; - - core->i2s_mode = mode; - r = core->write(core, WL1273_AUDIO_ENABLE, - WL1273_AUDIO_ENABLE_I2S); - if (r) - goto out; - } -out: - mutex_unlock(&core->lock); - - return r; -} - -static int snd_wl1273_fm_set_channel_number(struct wl1273_core *core, - int channel_number) -{ - struct device *dev = &core->client->dev; - int r = 0; - - dev_dbg(dev, "%s\n", __func__); - - mutex_lock(&core->lock); - - if (core->channel_number == channel_number) - goto out; - - if (channel_number == 1 && core->mode == WL1273_MODE_RX) - r = core->write(core, WL1273_MOST_MODE_SET, WL1273_RX_MONO); - else if (channel_number == 1 && core->mode == WL1273_MODE_TX) - r = core->write(core, WL1273_MONO_SET, WL1273_TX_MONO); - else if (channel_number == 2 && core->mode == WL1273_MODE_RX) - r = core->write(core, WL1273_MOST_MODE_SET, WL1273_RX_STEREO); - else if (channel_number == 2 && core->mode == WL1273_MODE_TX) - r = core->write(core, WL1273_MONO_SET, WL1273_TX_STEREO); - else - r = -EINVAL; -out: - mutex_unlock(&core->lock); - - return r; -} - -static int snd_wl1273_get_audio_route(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); - struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component); - - ucontrol->value.enumerated.item[0] = wl1273->mode; - - return 0; -} - -/* - * TODO: Implement the audio routing in the driver. Now this control - * only indicates the setting that has been done elsewhere (in the user - * space). - */ -static const char * const wl1273_audio_route[] = { "Bt", "FmRx", "FmTx" }; - -static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); - struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component); - - if (wl1273->mode == ucontrol->value.enumerated.item[0]) - return 0; - - /* Do not allow changes while stream is running */ - if (snd_soc_component_active(component)) - return -EPERM; - - if (ucontrol->value.enumerated.item[0] >= ARRAY_SIZE(wl1273_audio_route)) - return -EINVAL; - - wl1273->mode = ucontrol->value.enumerated.item[0]; - - return 1; -} - -static SOC_ENUM_SINGLE_EXT_DECL(wl1273_enum, wl1273_audio_route); - -static int snd_wl1273_fm_audio_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); - struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component); - - dev_dbg(component->dev, "%s: enter.\n", __func__); - - ucontrol->value.enumerated.item[0] = wl1273->core->audio_mode; - - return 0; -} - -static int snd_wl1273_fm_audio_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); - struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component); - int val, r = 0; - - dev_dbg(component->dev, "%s: enter.\n", __func__); - - val = ucontrol->value.enumerated.item[0]; - if (wl1273->core->audio_mode == val) - return 0; - - r = wl1273->core->set_audio(wl1273->core, val); - if (r < 0) - return r; - - return 1; -} - -static const char * const wl1273_audio_strings[] = { "Digital", "Analog" }; - -static SOC_ENUM_SINGLE_EXT_DECL(wl1273_audio_enum, wl1273_audio_strings); - -static int snd_wl1273_fm_volume_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); - struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component); - - dev_dbg(component->dev, "%s: enter.\n", __func__); - - ucontrol->value.integer.value[0] = wl1273->core->volume; - - return 0; -} - -static int snd_wl1273_fm_volume_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); - struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component); - int r; - - dev_dbg(component->dev, "%s: enter.\n", __func__); - - r = wl1273->core->set_volume(wl1273->core, - ucontrol->value.integer.value[0]); - if (r) - return r; - - return 1; -} - -static const struct snd_kcontrol_new wl1273_controls[] = { - SOC_ENUM_EXT("Codec Mode", wl1273_enum, - snd_wl1273_get_audio_route, snd_wl1273_set_audio_route), - SOC_ENUM_EXT("Audio Switch", wl1273_audio_enum, - snd_wl1273_fm_audio_get, snd_wl1273_fm_audio_put), - SOC_SINGLE_EXT("Volume", 0, 0, WL1273_MAX_VOLUME, 0, - snd_wl1273_fm_volume_get, snd_wl1273_fm_volume_put), -}; - -static const struct snd_soc_dapm_widget wl1273_dapm_widgets[] = { - SND_SOC_DAPM_INPUT("RX"), - - SND_SOC_DAPM_OUTPUT("TX"), -}; - -static const struct snd_soc_dapm_route wl1273_dapm_routes[] = { - { "Capture", NULL, "RX" }, - - { "TX", NULL, "Playback" }, -}; - -static int wl1273_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_component *component = dai->component; - struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component); - - switch (wl1273->mode) { - case WL1273_MODE_BT: - snd_pcm_hw_constraint_single(substream->runtime, - SNDRV_PCM_HW_PARAM_RATE, 8000); - snd_pcm_hw_constraint_single(substream->runtime, - SNDRV_PCM_HW_PARAM_CHANNELS, 1); - break; - case WL1273_MODE_FM_RX: - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - pr_err("Cannot play in RX mode.\n"); - return -EINVAL; - } - break; - case WL1273_MODE_FM_TX: - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - pr_err("Cannot capture in TX mode.\n"); - return -EINVAL; - } - break; - default: - return -EINVAL; - } - - return 0; -} - -static int wl1273_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(dai->component); - struct wl1273_core *core = wl1273->core; - unsigned int rate, width, r; - - if (params_width(params) != 16) { - dev_err(dai->dev, "%d bits/sample not supported\n", - params_width(params)); - return -EINVAL; - } - - rate = params_rate(params); - width = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min; - - if (wl1273->mode == WL1273_MODE_BT) { - if (rate != 8000) { - pr_err("Rate %d not supported.\n", params_rate(params)); - return -EINVAL; - } - - if (params_channels(params) != 1) { - pr_err("Only mono supported.\n"); - return -EINVAL; - } - - return 0; - } - - if (wl1273->mode == WL1273_MODE_FM_TX && - substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - pr_err("Only playback supported with TX.\n"); - return -EINVAL; - } - - if (wl1273->mode == WL1273_MODE_FM_RX && - substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - pr_err("Only capture supported with RX.\n"); - return -EINVAL; - } - - if (wl1273->mode != WL1273_MODE_FM_RX && - wl1273->mode != WL1273_MODE_FM_TX) { - pr_err("Unexpected mode: %d.\n", wl1273->mode); - return -EINVAL; - } - - r = snd_wl1273_fm_set_i2s_mode(core, rate, width); - if (r) - return r; - - wl1273->channels = params_channels(params); - r = snd_wl1273_fm_set_channel_number(core, wl1273->channels); - if (r) - return r; - - return 0; -} - -static const struct snd_soc_dai_ops wl1273_dai_ops = { - .startup = wl1273_startup, - .hw_params = wl1273_hw_params, -}; - -static struct snd_soc_dai_driver wl1273_dai = { - .name = "wl1273-fm", - .playback = { - .stream_name = "Playback", - .channels_min = 1, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE}, - .capture = { - .stream_name = "Capture", - .channels_min = 1, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE}, - .ops = &wl1273_dai_ops, -}; - -/* Audio interface format for the soc_card driver */ -int wl1273_get_format(struct snd_soc_component *component, unsigned int *fmt) -{ - struct wl1273_priv *wl1273; - - if (component == NULL || fmt == NULL) - return -EINVAL; - - wl1273 = snd_soc_component_get_drvdata(component); - - switch (wl1273->mode) { - case WL1273_MODE_FM_RX: - case WL1273_MODE_FM_TX: - *fmt = SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBP_CFP; - - break; - case WL1273_MODE_BT: - *fmt = SND_SOC_DAIFMT_DSP_A | - SND_SOC_DAIFMT_IB_NF | - SND_SOC_DAIFMT_CBP_CFP; - - break; - default: - return -EINVAL; - } - - return 0; -} -EXPORT_SYMBOL_GPL(wl1273_get_format); - -static int wl1273_probe(struct snd_soc_component *component) -{ - struct wl1273_core **core = component->dev->platform_data; - struct wl1273_priv *wl1273; - - dev_dbg(component->dev, "%s.\n", __func__); - - if (!core) { - dev_err(component->dev, "Platform data is missing.\n"); - return -EINVAL; - } - - wl1273 = kzalloc(sizeof(struct wl1273_priv), GFP_KERNEL); - if (!wl1273) - return -ENOMEM; - - wl1273->mode = WL1273_MODE_BT; - wl1273->core = *core; - - snd_soc_component_set_drvdata(component, wl1273); - - return 0; -} - -static void wl1273_remove(struct snd_soc_component *component) -{ - struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component); - - dev_dbg(component->dev, "%s\n", __func__); - kfree(wl1273); -} - -static const struct snd_soc_component_driver soc_component_dev_wl1273 = { - .probe = wl1273_probe, - .remove = wl1273_remove, - .controls = wl1273_controls, - .num_controls = ARRAY_SIZE(wl1273_controls), - .dapm_widgets = wl1273_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wl1273_dapm_widgets), - .dapm_routes = wl1273_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wl1273_dapm_routes), - .idle_bias_on = 1, - .use_pmdown_time = 1, - .endianness = 1, -}; - -static int wl1273_platform_probe(struct platform_device *pdev) -{ - return devm_snd_soc_register_component(&pdev->dev, - &soc_component_dev_wl1273, - &wl1273_dai, 1); -} - -MODULE_ALIAS("platform:wl1273-codec"); - -static struct platform_driver wl1273_platform_driver = { - .driver = { - .name = "wl1273-codec", - }, - .probe = wl1273_platform_probe, -}; - -module_platform_driver(wl1273_platform_driver); - -MODULE_AUTHOR("Matti Aaltonen "); -MODULE_DESCRIPTION("ASoC WL1273 codec driver"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wl1273.h b/sound/soc/codecs/wl1273.h deleted file mode 100644 index 66c312fa7eee..000000000000 --- a/sound/soc/codecs/wl1273.h +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * sound/soc/codec/wl1273.h - * - * ALSA SoC WL1273 codec driver - * - * Copyright (C) Nokia Corporation - * Author: Matti Aaltonen - */ - -#ifndef __WL1273_CODEC_H__ -#define __WL1273_CODEC_H__ - -int wl1273_get_format(struct snd_soc_component *component, unsigned int *fmt); - -#endif /* End of __WL1273_CODEC_H__ */ From 27fce9e8c6f031b526bf471e1076abca31473464 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Thu, 14 Aug 2025 17:21:20 +0200 Subject: [PATCH 00830/11391] 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 ba7fad179699dbbd3dfdc9ca5594d7f3c425a2a2 Mon Sep 17 00:00:00 2001 From: Dave Ertman Date: Mon, 16 Jun 2025 13:03:16 +0200 Subject: [PATCH 00831/11391] ice: Remove casts on void pointers in LAG code This series will be touching on the LAG code in the ice driver, to prevent moving or propagating casting on void pointers, clean them up first. This also allows for moving the variable initialization into the variable declaration. Reviewed-by: Aleksandr Loktionov Reviewed-by: Przemek Kitszel Signed-off-by: Dave Ertman Tested-by: Sujai Buvaneswaran Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_lag.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_lag.c b/drivers/net/ethernet/intel/ice/ice_lag.c index b1129da72139..96b11d8f1422 100644 --- a/drivers/net/ethernet/intel/ice/ice_lag.c +++ b/drivers/net/ethernet/intel/ice/ice_lag.c @@ -321,7 +321,7 @@ ice_lag_cfg_drop_fltr(struct ice_lag *lag, bool add) static void ice_lag_cfg_pf_fltrs(struct ice_lag *lag, void *ptr) { - struct netdev_notifier_bonding_info *info; + struct netdev_notifier_bonding_info *info = ptr; struct netdev_bonding_info *bonding_info; struct net_device *event_netdev; struct device *dev; @@ -331,7 +331,6 @@ ice_lag_cfg_pf_fltrs(struct ice_lag *lag, void *ptr) if (event_netdev != lag->netdev) return; - info = (struct netdev_notifier_bonding_info *)ptr; bonding_info = &info->bonding_info; dev = ice_pf_to_dev(lag->pf); @@ -873,13 +872,12 @@ void ice_lag_complete_vf_reset(struct ice_lag *lag, u8 act_prt) */ static void ice_lag_info_event(struct ice_lag *lag, void *ptr) { - struct netdev_notifier_bonding_info *info; + struct netdev_notifier_bonding_info *info = ptr; struct netdev_bonding_info *bonding_info; struct net_device *event_netdev; const char *lag_netdev_name; event_netdev = netdev_notifier_info_to_dev(ptr); - info = ptr; lag_netdev_name = netdev_name(lag->netdev); bonding_info = &info->bonding_info; @@ -1344,11 +1342,10 @@ static void ice_lag_init_feature_support_flag(struct ice_pf *pf) */ static void ice_lag_changeupper_event(struct ice_lag *lag, void *ptr) { - struct netdev_notifier_changeupper_info *info; + struct netdev_notifier_changeupper_info *info = ptr; struct ice_lag *primary_lag; struct net_device *netdev; - info = ptr; netdev = netdev_notifier_info_to_dev(ptr); /* not for this netdev */ @@ -1408,7 +1405,7 @@ static void ice_lag_changeupper_event(struct ice_lag *lag, void *ptr) */ static void ice_lag_monitor_link(struct ice_lag *lag, void *ptr) { - struct netdev_notifier_changeupper_info *info; + struct netdev_notifier_changeupper_info *info = ptr; struct ice_hw *prim_hw, *active_hw; struct net_device *event_netdev; struct ice_pf *pf; @@ -1425,7 +1422,6 @@ static void ice_lag_monitor_link(struct ice_lag *lag, void *ptr) prim_hw = &pf->hw; prim_port = prim_hw->port_info->lport; - info = (struct netdev_notifier_changeupper_info *)ptr; if (info->upper_dev != lag->upper_netdev) return; @@ -1454,8 +1450,8 @@ static void ice_lag_monitor_link(struct ice_lag *lag, void *ptr) */ static void ice_lag_monitor_active(struct ice_lag *lag, void *ptr) { + struct netdev_notifier_bonding_info *info = ptr; struct net_device *event_netdev, *event_upper; - struct netdev_notifier_bonding_info *info; struct netdev_bonding_info *bonding_info; struct ice_netdev_priv *event_np; struct ice_pf *pf, *event_pf; @@ -1480,7 +1476,6 @@ static void ice_lag_monitor_active(struct ice_lag *lag, void *ptr) event_port = event_pf->hw.port_info->lport; prim_port = pf->hw.port_info->lport; - info = (struct netdev_notifier_bonding_info *)ptr; bonding_info = &info->bonding_info; if (!bonding_info->slave.state) { @@ -1527,8 +1522,8 @@ static void ice_lag_monitor_active(struct ice_lag *lag, void *ptr) static bool ice_lag_chk_comp(struct ice_lag *lag, void *ptr) { + struct netdev_notifier_bonding_info *info = ptr; struct net_device *event_netdev, *event_upper; - struct netdev_notifier_bonding_info *info; struct netdev_bonding_info *bonding_info; struct list_head *tmp; struct device *dev; @@ -1554,7 +1549,6 @@ ice_lag_chk_comp(struct ice_lag *lag, void *ptr) return false; } - info = (struct netdev_notifier_bonding_info *)ptr; bonding_info = &info->bonding_info; lag->bond_mode = bonding_info->master.bond_mode; if (lag->bond_mode != BOND_MODE_ACTIVEBACKUP) { @@ -1664,10 +1658,9 @@ ice_lag_unregister(struct ice_lag *lag, struct net_device *event_netdev) static void ice_lag_monitor_rdma(struct ice_lag *lag, void *ptr) { - struct netdev_notifier_changeupper_info *info; + struct netdev_notifier_changeupper_info *info = ptr; struct net_device *netdev; - info = ptr; netdev = netdev_notifier_info_to_dev(ptr); if (netdev != lag->netdev) @@ -1837,9 +1830,8 @@ ice_lag_event_handler(struct notifier_block *notif_blk, unsigned long event, lag_work->lag = lag; lag_work->event = event; if (event == NETDEV_CHANGEUPPER) { - struct netdev_notifier_changeupper_info *info; + struct netdev_notifier_changeupper_info *info = ptr; - info = ptr; upper_netdev = info->upper_dev; } else { upper_netdev = netdev_master_upper_dev_get(netdev); From 5b35b83d0d759e8313e0dd921fb9b9ac947c2585 Mon Sep 17 00:00:00 2001 From: Dave Ertman Date: Mon, 16 Jun 2025 13:03:17 +0200 Subject: [PATCH 00832/11391] ice: replace u8 elements with bool where appropriate In preparation for the new LAG functionality implementation, there are a couple of existing LAG elements of the capabilities struct that should be bool instead of u8. Since we are adding a new element to this struct that should also be a bool, fix the existing LAG u8 in this patch and eliminate !! operators where possible. Reviewed-by: Przemek Kitszel Signed-off-by: Dave Ertman Tested-by: Sujai Buvaneswaran Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_common.c | 4 ++-- drivers/net/ethernet/intel/ice/ice_type.h | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 003d60a4db21..209f42045fea 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -2418,10 +2418,10 @@ ice_parse_common_caps(struct ice_hw *hw, struct ice_hw_common_caps *caps, caps->reset_restrict_support); break; case LIBIE_AQC_CAPS_FW_LAG_SUPPORT: - caps->roce_lag = !!(number & LIBIE_AQC_BIT_ROCEV2_LAG); + caps->roce_lag = number & LIBIE_AQC_BIT_ROCEV2_LAG; ice_debug(hw, ICE_DBG_INIT, "%s: roce_lag = %u\n", prefix, caps->roce_lag); - caps->sriov_lag = !!(number & LIBIE_AQC_BIT_SRIOV_LAG); + caps->sriov_lag = number & LIBIE_AQC_BIT_SRIOV_LAG; ice_debug(hw, ICE_DBG_INIT, "%s: sriov_lag = %u\n", prefix, caps->sriov_lag); break; diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index 03c6c271865d..2b07d5e48847 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -293,8 +293,9 @@ struct ice_hw_common_caps { u8 dcb; u8 ieee_1588; u8 rdma; - u8 roce_lag; - u8 sriov_lag; + + bool roce_lag; + bool sriov_lag; bool nvm_update_pending_nvm; bool nvm_update_pending_orom; From a66b3b537d2133e8980e49d68b3573b5aec23699 Mon Sep 17 00:00:00 2001 From: Dave Ertman Date: Mon, 16 Jun 2025 13:03:18 +0200 Subject: [PATCH 00833/11391] ice: Add driver specific prefix to LAG defines A define in the LAG code is missing a driver specific prefix. Add a prefix to the define. Also shorten a defines name and move to a more logical place. Reviewed-by: Przemek Kitszel Signed-off-by: Dave Ertman Tested-by: Sujai Buvaneswaran Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_lag.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_lag.c b/drivers/net/ethernet/intel/ice/ice_lag.c index 96b11d8f1422..48efd8d27296 100644 --- a/drivers/net/ethernet/intel/ice/ice_lag.c +++ b/drivers/net/ethernet/intel/ice/ice_lag.c @@ -10,12 +10,14 @@ #define ICE_LAG_RES_SHARED BIT(14) #define ICE_LAG_RES_VALID BIT(15) -#define LACP_TRAIN_PKT_LEN 16 -static const u8 lacp_train_pkt[LACP_TRAIN_PKT_LEN] = { 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0x88, 0x09, 0, 0 }; +#define ICE_TRAIN_PKT_LEN 16 +static const u8 lacp_train_pkt[ICE_TRAIN_PKT_LEN] = { 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0x88, 0x09, 0, 0 }; #define ICE_RECIPE_LEN 64 +#define ICE_LAG_SRIOV_CP_RECIPE 10 + static const u8 ice_dflt_vsi_rcp[ICE_RECIPE_LEN] = { 0x05, 0, 0, 0, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x85, 0, 0x01, 0, 0, 0, 0xff, 0xff, 0x08, 0, 0, 0, 0, 0, 0, 0, @@ -766,9 +768,6 @@ void ice_lag_move_vf_nodes_cfg(struct ice_lag *lag, u8 src_prt, u8 dst_prt) ice_lag_destroy_netdev_list(lag, &ndlist); } -#define ICE_LAG_SRIOV_CP_RECIPE 10 -#define ICE_LAG_SRIOV_TRAIN_PKT_LEN 16 - /** * ice_lag_cfg_cp_fltr - configure filter for control packets * @lag: local interface's lag struct @@ -783,8 +782,7 @@ ice_lag_cfg_cp_fltr(struct ice_lag *lag, bool add) vsi = lag->pf->vsi[0]; - buf_len = ICE_SW_RULE_RX_TX_HDR_SIZE(s_rule, - ICE_LAG_SRIOV_TRAIN_PKT_LEN); + buf_len = ICE_SW_RULE_RX_TX_HDR_SIZE(s_rule, ICE_TRAIN_PKT_LEN); s_rule = kzalloc(buf_len, GFP_KERNEL); if (!s_rule) { netdev_warn(lag->netdev, "-ENOMEM error configuring CP filter\n"); @@ -799,8 +797,8 @@ ice_lag_cfg_cp_fltr(struct ice_lag *lag, bool add) ICE_SINGLE_ACT_LAN_ENABLE | ICE_SINGLE_ACT_VALID_BIT | FIELD_PREP(ICE_SINGLE_ACT_VSI_ID_M, vsi->vsi_num)); - s_rule->hdr_len = cpu_to_le16(ICE_LAG_SRIOV_TRAIN_PKT_LEN); - memcpy(s_rule->hdr_data, lacp_train_pkt, LACP_TRAIN_PKT_LEN); + s_rule->hdr_len = cpu_to_le16(ICE_TRAIN_PKT_LEN); + memcpy(s_rule->hdr_data, lacp_train_pkt, ICE_TRAIN_PKT_LEN); opc = ice_aqc_opc_add_sw_rules; } else { opc = ice_aqc_opc_remove_sw_rules; From b2e97152df79ab4670ab47de34f2df5bd6b86005 Mon Sep 17 00:00:00 2001 From: Dave Ertman Date: Mon, 16 Jun 2025 13:03:19 +0200 Subject: [PATCH 00834/11391] ice: move LAG function in code to prepare for Active-Active In the SRIOV LAG Active-Active, the functions ice_lag_cfg_pf_fltr's and ice_lag_config_eswitch's content are moved to earlier locations in the source file. Also, ice_lag_cfg_pf_fltr is renamed, and its flow is changed. To reduce the delta in the larger patch, move the original functions to their new location so that only functional changes are needed in the larger patch. Reviewed-by: Przemek Kitszel Signed-off-by: Dave Ertman Tested-by: Sujai Buvaneswaran Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_lag.c | 147 ++++++++++++----------- 1 file changed, 74 insertions(+), 73 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_lag.c b/drivers/net/ethernet/intel/ice/ice_lag.c index 48efd8d27296..1f76536e6176 100644 --- a/drivers/net/ethernet/intel/ice/ice_lag.c +++ b/drivers/net/ethernet/intel/ice/ice_lag.c @@ -100,6 +100,28 @@ static bool netif_is_same_ice(struct ice_pf *pf, struct net_device *netdev) return true; } +/** + * ice_lag_config_eswitch - configure eswitch to work with LAG + * @lag: lag info struct + * @netdev: active network interface device struct + * + * Updates all port representors in eswitch to use @netdev for Tx. + * + * Configures the netdev to keep dst metadata (also used in representor Tx). + * This is required for an uplink without switchdev mode configured. + */ +static void ice_lag_config_eswitch(struct ice_lag *lag, + struct net_device *netdev) +{ + struct ice_repr *repr; + unsigned long id; + + xa_for_each(&lag->pf->eswitch.reprs, id, repr) + repr->dst->u.port_info.lower_dev = netdev; + + netif_keep_dst(netdev); +} + /** * ice_netdev_to_lag - return pointer to associated lag struct from netdev * @netdev: pointer to net_device struct to query @@ -354,6 +376,58 @@ ice_lag_cfg_pf_fltrs(struct ice_lag *lag, void *ptr) } } +/** + * ice_lag_cfg_cp_fltr - configure filter for control packets + * @lag: local interface's lag struct + * @add: add or remove rule + */ +static void +ice_lag_cfg_cp_fltr(struct ice_lag *lag, bool add) +{ + struct ice_sw_rule_lkup_rx_tx *s_rule = NULL; + struct ice_vsi *vsi; + u16 buf_len, opc; + + vsi = lag->pf->vsi[0]; + + buf_len = ICE_SW_RULE_RX_TX_HDR_SIZE(s_rule, ICE_TRAIN_PKT_LEN); + s_rule = kzalloc(buf_len, GFP_KERNEL); + if (!s_rule) { + netdev_warn(lag->netdev, "-ENOMEM error configuring CP filter\n"); + return; + } + + if (add) { + s_rule->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_RX); + s_rule->recipe_id = cpu_to_le16(ICE_LAG_SRIOV_CP_RECIPE); + s_rule->src = cpu_to_le16(vsi->port_info->lport); + s_rule->act = cpu_to_le32(ICE_FWD_TO_VSI | + ICE_SINGLE_ACT_LAN_ENABLE | + ICE_SINGLE_ACT_VALID_BIT | + FIELD_PREP(ICE_SINGLE_ACT_VSI_ID_M, + vsi->vsi_num)); + s_rule->hdr_len = cpu_to_le16(ICE_TRAIN_PKT_LEN); + memcpy(s_rule->hdr_data, lacp_train_pkt, ICE_TRAIN_PKT_LEN); + opc = ice_aqc_opc_add_sw_rules; + } else { + opc = ice_aqc_opc_remove_sw_rules; + s_rule->index = cpu_to_le16(lag->cp_rule_idx); + } + if (ice_aq_sw_rules(&lag->pf->hw, s_rule, buf_len, 1, opc, NULL)) { + netdev_warn(lag->netdev, "Error %s CP rule for fail-over\n", + add ? "ADDING" : "REMOVING"); + goto err_cp_free; + } + + if (add) + lag->cp_rule_idx = le16_to_cpu(s_rule->index); + else + lag->cp_rule_idx = 0; + +err_cp_free: + kfree(s_rule); +} + /** * ice_display_lag_info - print LAG info * @lag: LAG info struct @@ -768,57 +842,6 @@ void ice_lag_move_vf_nodes_cfg(struct ice_lag *lag, u8 src_prt, u8 dst_prt) ice_lag_destroy_netdev_list(lag, &ndlist); } -/** - * ice_lag_cfg_cp_fltr - configure filter for control packets - * @lag: local interface's lag struct - * @add: add or remove rule - */ -static void -ice_lag_cfg_cp_fltr(struct ice_lag *lag, bool add) -{ - struct ice_sw_rule_lkup_rx_tx *s_rule = NULL; - struct ice_vsi *vsi; - u16 buf_len, opc; - - vsi = lag->pf->vsi[0]; - - buf_len = ICE_SW_RULE_RX_TX_HDR_SIZE(s_rule, ICE_TRAIN_PKT_LEN); - s_rule = kzalloc(buf_len, GFP_KERNEL); - if (!s_rule) { - netdev_warn(lag->netdev, "-ENOMEM error configuring CP filter\n"); - return; - } - - if (add) { - s_rule->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_RX); - s_rule->recipe_id = cpu_to_le16(ICE_LAG_SRIOV_CP_RECIPE); - s_rule->src = cpu_to_le16(vsi->port_info->lport); - s_rule->act = cpu_to_le32(ICE_FWD_TO_VSI | - ICE_SINGLE_ACT_LAN_ENABLE | - ICE_SINGLE_ACT_VALID_BIT | - FIELD_PREP(ICE_SINGLE_ACT_VSI_ID_M, vsi->vsi_num)); - s_rule->hdr_len = cpu_to_le16(ICE_TRAIN_PKT_LEN); - memcpy(s_rule->hdr_data, lacp_train_pkt, ICE_TRAIN_PKT_LEN); - opc = ice_aqc_opc_add_sw_rules; - } else { - opc = ice_aqc_opc_remove_sw_rules; - s_rule->index = cpu_to_le16(lag->cp_rule_idx); - } - if (ice_aq_sw_rules(&lag->pf->hw, s_rule, buf_len, 1, opc, NULL)) { - netdev_warn(lag->netdev, "Error %s CP rule for fail-over\n", - add ? "ADDING" : "REMOVING"); - goto cp_free; - } - - if (add) - lag->cp_rule_idx = le16_to_cpu(s_rule->index); - else - lag->cp_rule_idx = 0; - -cp_free: - kfree(s_rule); -} - /** * ice_lag_prepare_vf_reset - helper to adjust vf lag for reset * @lag: lag struct for interface that owns VF @@ -1038,28 +1061,6 @@ static void ice_lag_link(struct ice_lag *lag) netdev_info(lag->netdev, "Shared SR-IOV resources in bond are active\n"); } -/** - * ice_lag_config_eswitch - configure eswitch to work with LAG - * @lag: lag info struct - * @netdev: active network interface device struct - * - * Updates all port representors in eswitch to use @netdev for Tx. - * - * Configures the netdev to keep dst metadata (also used in representor Tx). - * This is required for an uplink without switchdev mode configured. - */ -static void ice_lag_config_eswitch(struct ice_lag *lag, - struct net_device *netdev) -{ - struct ice_repr *repr; - unsigned long id; - - xa_for_each(&lag->pf->eswitch.reprs, id, repr) - repr->dst->u.port_info.lower_dev = netdev; - - netif_keep_dst(netdev); -} - /** * ice_lag_unlink - handle unlink event * @lag: LAG info struct From 148c8cb32b2f4a32c4b47998da20f2fd62cc38ca Mon Sep 17 00:00:00 2001 From: Dave Ertman Date: Mon, 16 Jun 2025 13:03:20 +0200 Subject: [PATCH 00835/11391] ice: Cleanup variable initialization in LAG code In preparation for implementing SRIOV Active-Active LAG support, cleanup several unneeded variable initializations in declaration blocks. Also move a couple of variable initializations into declaration block that should be there. Reviewed-by: Przemek Kitszel Signed-off-by: Dave Ertman Tested-by: Sujai Buvaneswaran Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_lag.c | 54 ++++++++---------------- 1 file changed, 17 insertions(+), 37 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_lag.c b/drivers/net/ethernet/intel/ice/ice_lag.c index 1f76536e6176..72284555b98a 100644 --- a/drivers/net/ethernet/intel/ice/ice_lag.c +++ b/drivers/net/ethernet/intel/ice/ice_lag.c @@ -234,13 +234,12 @@ ice_lag_cfg_fltr(struct ice_lag *lag, u32 act, u16 recipe_id, u16 *rule_idx, u8 direction, bool add) { struct ice_sw_rule_lkup_rx_tx *s_rule; + struct ice_hw *hw = &lag->pf->hw; u16 s_rule_sz, vsi_num; - struct ice_hw *hw; u8 *eth_hdr; u32 opc; int err; - hw = &lag->pf->hw; vsi_num = ice_get_hw_vsi_num(hw, 0); s_rule_sz = ICE_SW_RULE_RX_TX_ETH_HDR_SIZE(s_rule); @@ -384,12 +383,10 @@ ice_lag_cfg_pf_fltrs(struct ice_lag *lag, void *ptr) static void ice_lag_cfg_cp_fltr(struct ice_lag *lag, bool add) { - struct ice_sw_rule_lkup_rx_tx *s_rule = NULL; - struct ice_vsi *vsi; + struct ice_sw_rule_lkup_rx_tx *s_rule; + struct ice_vsi *vsi = lag->pf->vsi[0]; u16 buf_len, opc; - vsi = lag->pf->vsi[0]; - buf_len = ICE_SW_RULE_RX_TX_HDR_SIZE(s_rule, ICE_TRAIN_PKT_LEN); s_rule = kzalloc(buf_len, GFP_KERNEL); if (!s_rule) { @@ -477,12 +474,11 @@ static u16 ice_lag_qbuf_recfg(struct ice_hw *hw, struct ice_aqc_cfg_txqs_buf *qbuf, u16 vsi_num, u16 numq, u8 tc) { + struct ice_pf *pf = hw->back; struct ice_q_ctx *q_ctx; u16 qid, count = 0; - struct ice_pf *pf; int i; - pf = hw->back; for (i = 0; i < numq; i++) { q_ctx = ice_get_lan_q_ctx(hw, vsi_num, tc, i); if (!q_ctx) { @@ -940,13 +936,12 @@ ice_lag_reclaim_vf_tc(struct ice_lag *lag, struct ice_hw *src_hw, u16 vsi_num, u16 numq, valq, num_moved, qbuf_size; u16 buf_size = __struct_size(buf); struct ice_aqc_cfg_txqs_buf *qbuf; + struct ice_hw *hw = &lag->pf->hw; struct ice_sched_node *n_prt; __le32 teid, parent_teid; struct ice_vsi_ctx *ctx; - struct ice_hw *hw; u32 tmp_teid; - hw = &lag->pf->hw; ctx = ice_get_vsi_ctx(hw, vsi_num); if (!ctx) { dev_warn(dev, "Unable to locate VSI context for LAG reclaim\n"); @@ -1221,11 +1216,8 @@ ice_lag_set_swid(u16 primary_swid, struct ice_lag *local_lag, */ static void ice_lag_primary_swid(struct ice_lag *lag, bool link) { - struct ice_hw *hw; - u16 swid; - - hw = &lag->pf->hw; - swid = hw->port_info->sw_id; + struct ice_hw *hw = &lag->pf->hw; + u16 swid = hw->port_info->sw_id; if (ice_share_res(hw, ICE_AQC_RES_TYPE_SWID, link, swid)) dev_warn(ice_pf_to_dev(lag->pf), "Failure to set primary interface shared status\n"); @@ -1238,12 +1230,10 @@ static void ice_lag_primary_swid(struct ice_lag *lag, bool link) */ static void ice_lag_add_prune_list(struct ice_lag *lag, struct ice_pf *event_pf) { - u16 num_vsi, rule_buf_sz, vsi_list_id, event_vsi_num, prim_vsi_idx; - struct ice_sw_rule_vsi_list *s_rule = NULL; + u16 rule_buf_sz, vsi_list_id, event_vsi_num, prim_vsi_idx, num_vsi = 1; + struct ice_sw_rule_vsi_list *s_rule; struct device *dev; - num_vsi = 1; - dev = ice_pf_to_dev(lag->pf); event_vsi_num = event_pf->vsi[0]->vsi_num; prim_vsi_idx = lag->pf->vsi[0]->idx; @@ -1279,12 +1269,10 @@ static void ice_lag_add_prune_list(struct ice_lag *lag, struct ice_pf *event_pf) */ static void ice_lag_del_prune_list(struct ice_lag *lag, struct ice_pf *event_pf) { - u16 num_vsi, vsi_num, vsi_idx, rule_buf_sz, vsi_list_id; - struct ice_sw_rule_vsi_list *s_rule = NULL; + u16 vsi_num, vsi_idx, rule_buf_sz, vsi_list_id, num_vsi = 1; + struct ice_sw_rule_vsi_list *s_rule; struct device *dev; - num_vsi = 1; - dev = ice_pf_to_dev(lag->pf); vsi_num = event_pf->vsi[0]->vsi_num; vsi_idx = lag->pf->vsi[0]->idx; @@ -1707,11 +1695,9 @@ static void ice_lag_chk_disabled_bond(struct ice_lag *lag, void *ptr) */ static void ice_lag_disable_sriov_bond(struct ice_lag *lag) { - struct ice_netdev_priv *np; - struct ice_pf *pf; + struct ice_netdev_priv *np = netdev_priv(lag->netdev); + struct ice_pf *pf = np->vsi->back; - np = netdev_priv(lag->netdev); - pf = np->vsi->back; ice_clear_feature_support(pf, ICE_F_SRIOV_LAG); } @@ -1880,10 +1866,8 @@ ice_lag_event_handler(struct notifier_block *notif_blk, unsigned long event, */ static int ice_register_lag_handler(struct ice_lag *lag) { + struct notifier_block *notif_blk = &lag->notif_block; struct device *dev = ice_pf_to_dev(lag->pf); - struct notifier_block *notif_blk; - - notif_blk = &lag->notif_block; if (!notif_blk->notifier_call) { notif_blk->notifier_call = ice_lag_event_handler; @@ -1903,10 +1887,9 @@ static int ice_register_lag_handler(struct ice_lag *lag) */ static void ice_unregister_lag_handler(struct ice_lag *lag) { + struct notifier_block *notif_blk = &lag->notif_block; struct device *dev = ice_pf_to_dev(lag->pf); - struct notifier_block *notif_blk; - notif_blk = &lag->notif_block; if (notif_blk->notifier_call) { unregister_netdevice_notifier(notif_blk); dev_dbg(dev, "LAG event handler unregistered\n"); @@ -1968,13 +1951,12 @@ ice_lag_move_vf_nodes_tc_sync(struct ice_lag *lag, struct ice_hw *dest_hw, u16 numq, valq, num_moved, qbuf_size; u16 buf_size = __struct_size(buf); struct ice_aqc_cfg_txqs_buf *qbuf; + struct ice_hw *hw = &lag->pf->hw; struct ice_sched_node *n_prt; __le32 teid, parent_teid; struct ice_vsi_ctx *ctx; - struct ice_hw *hw; u32 tmp_teid; - hw = &lag->pf->hw; ctx = ice_get_vsi_ctx(hw, vsi_num); if (!ctx) { dev_warn(dev, "LAG rebuild failed after reset due to VSI Context failure\n"); @@ -2165,9 +2147,7 @@ int ice_init_lag(struct ice_pf *pf) */ void ice_deinit_lag(struct ice_pf *pf) { - struct ice_lag *lag; - - lag = pf->lag; + struct ice_lag *lag = pf->lag; if (!lag) return; From fb2f2a86f0cd9690357b9bb67af00d386a7e819f Mon Sep 17 00:00:00 2001 From: Dave Ertman Date: Mon, 16 Jun 2025 13:03:21 +0200 Subject: [PATCH 00836/11391] ice: cleanup capabilities evaluation When evaluating the capabilities field, the ICE_AQC_BIT_ROCEV2_LAG and ICE_AQC_BIT_SRIOV_LAG defines were both not using the BIT operator, instead simply setting a hex value that set the correct bits. While not inaccurate, this method is misleading, and when it is expanded in the following implementation it becomes even more confusing. Switch to using the BIT() operator to clarify what is being checked. Reviewed-by: Przemek Kitszel Reviewed-by: Aleksandr Loktionov Reviewed-by: Marcin Szycik Signed-off-by: Dave Ertman Tested-by: Sujai Buvaneswaran Signed-off-by: Tony Nguyen --- include/linux/net/intel/libie/adminq.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/net/intel/libie/adminq.h b/include/linux/net/intel/libie/adminq.h index 012b5d499c1a..dbe93f940ef0 100644 --- a/include/linux/net/intel/libie/adminq.h +++ b/include/linux/net/intel/libie/adminq.h @@ -192,8 +192,8 @@ LIBIE_CHECK_STRUCT_LEN(16, libie_aqc_list_caps); #define LIBIE_AQC_CAPS_TX_SCHED_TOPO_COMP_MODE 0x0085 #define LIBIE_AQC_CAPS_NAC_TOPOLOGY 0x0087 #define LIBIE_AQC_CAPS_FW_LAG_SUPPORT 0x0092 -#define LIBIE_AQC_BIT_ROCEV2_LAG 0x01 -#define LIBIE_AQC_BIT_SRIOV_LAG 0x02 +#define LIBIE_AQC_BIT_ROCEV2_LAG BIT(0) +#define LIBIE_AQC_BIT_SRIOV_LAG BIT(1) #define LIBIE_AQC_CAPS_FLEX10 0x00F1 #define LIBIE_AQC_CAPS_CEM 0x00F2 From f852ce052a8b78d6fade371bd1fad583541e78fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Thu, 14 Aug 2025 12:14:41 +0200 Subject: [PATCH 00837/11391] kbuild: align W=e with CONFIG_WERROR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CONFIG_WERROR sets KBUILD_CPPFLAGS while W=e would only set KBUILD_CFLAGS. As a preparation to unify the two mechanism, align their effects. While at it, add some alignment whitespace to prepare for later additions to the list of changed variables. Signed-off-by: Thomas Weißschuh Reviewed-by: Nicolas Schier Link: https://lore.kernel.org/r/20250814-kbuild-werror-v2-1-c01e596309d2@linutronix.de Signed-off-by: Nathan Chancellor --- scripts/Makefile.extrawarn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Makefile.extrawarn b/scripts/Makefile.extrawarn index dca175fffcab..4b4e8e136ce6 100644 --- a/scripts/Makefile.extrawarn +++ b/scripts/Makefile.extrawarn @@ -218,6 +218,6 @@ endif # ifneq ($(findstring e, $(KBUILD_EXTRA_WARN)),) -KBUILD_CFLAGS += -Werror +KBUILD_CPPFLAGS += -Werror endif From e7a10929c574cf30981a8e19ef39bc35e63e8b46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Thu, 14 Aug 2025 12:14:42 +0200 Subject: [PATCH 00838/11391] kbuild: unify W=e and CONFIG_WERROR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The two mechanisms have the same effect, unify their implementation. Also avoid spurious rebuilds when switching between the two. Signed-off-by: Thomas Weißschuh Reviewed-by: Nicolas Schier Link: https://lore.kernel.org/r/20250814-kbuild-werror-v2-2-c01e596309d2@linutronix.de Signed-off-by: Nathan Chancellor --- scripts/Makefile.extrawarn | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/scripts/Makefile.extrawarn b/scripts/Makefile.extrawarn index 4b4e8e136ce6..1ffc7beca43b 100644 --- a/scripts/Makefile.extrawarn +++ b/scripts/Makefile.extrawarn @@ -25,8 +25,6 @@ ifneq ($(CONFIG_FRAME_WARN),0) KBUILD_CFLAGS += -Wframe-larger-than=$(CONFIG_FRAME_WARN) endif -KBUILD_CPPFLAGS-$(CONFIG_WERROR) += -Werror -KBUILD_CPPFLAGS += $(KBUILD_CPPFLAGS-y) KBUILD_CFLAGS-$(CONFIG_CC_NO_ARRAY_BOUNDS) += -Wno-array-bounds ifdef CONFIG_CC_IS_CLANG @@ -214,9 +212,9 @@ KBUILD_CFLAGS += -Wno-unused-parameter endif # -# W=e - error out on warnings +# W=e and CONFIG_WERROR - error out on warnings # -ifneq ($(findstring e, $(KBUILD_EXTRA_WARN)),) +ifneq ($(findstring e, $(KBUILD_EXTRA_WARN))$(CONFIG_WERROR),) KBUILD_CPPFLAGS += -Werror From 592b571f20c5b905c47a1370210456f9f90ce04f Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Thu, 14 Aug 2025 12:14:43 +0200 Subject: [PATCH 00839/11391] kbuild: rust: move `-Dwarnings` handling to `Makefile.extrawarn` Following commit e88ca24319e4 ("kbuild: consolidate warning flags in scripts/Makefile.extrawarn"), move `-Dwarnings` handling into `Makefile.extrawarn` like C's `-Werror`. No functional change intended. Signed-off-by: Miguel Ojeda Reviewed-by: Nicolas Schier Link: https://lore.kernel.org/r/20250814-kbuild-werror-v2-3-c01e596309d2@linutronix.de Signed-off-by: Nathan Chancellor --- Makefile | 3 --- scripts/Makefile.extrawarn | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 6bfe776bf3c5..6630a66659c6 100644 --- a/Makefile +++ b/Makefile @@ -901,9 +901,6 @@ stackp-flags-$(CONFIG_STACKPROTECTOR_STRONG) := -fstack-protector-strong KBUILD_CFLAGS += $(stackp-flags-y) -KBUILD_RUSTFLAGS-$(CONFIG_WERROR) += -Dwarnings -KBUILD_RUSTFLAGS += $(KBUILD_RUSTFLAGS-y) - ifdef CONFIG_FRAME_POINTER KBUILD_CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls KBUILD_RUSTFLAGS += -Cforce-frame-pointers=y diff --git a/scripts/Makefile.extrawarn b/scripts/Makefile.extrawarn index 1ffc7beca43b..b04b3062e0e4 100644 --- a/scripts/Makefile.extrawarn +++ b/scripts/Makefile.extrawarn @@ -217,5 +217,6 @@ endif ifneq ($(findstring e, $(KBUILD_EXTRA_WARN))$(CONFIG_WERROR),) KBUILD_CPPFLAGS += -Werror +KBUILD_RUSTFLAGS += -Dwarnings endif From ec4a3992bc0b5b659eceb44a9f8582b26f2c8489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Thu, 14 Aug 2025 12:14:44 +0200 Subject: [PATCH 00840/11391] kbuild: respect CONFIG_WERROR for linker and assembler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The linker and assembler do not share the compiler flags. Make sure they also fail on warnings with CONFIG_WERROR and W=e. Signed-off-by: Thomas Weißschuh Reviewed-by: Nicolas Schier Link: https://lore.kernel.org/r/20250814-kbuild-werror-v2-4-c01e596309d2@linutronix.de Signed-off-by: Nathan Chancellor --- scripts/Makefile.extrawarn | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/Makefile.extrawarn b/scripts/Makefile.extrawarn index b04b3062e0e4..6efb9e5eeeed 100644 --- a/scripts/Makefile.extrawarn +++ b/scripts/Makefile.extrawarn @@ -217,6 +217,8 @@ endif ifneq ($(findstring e, $(KBUILD_EXTRA_WARN))$(CONFIG_WERROR),) KBUILD_CPPFLAGS += -Werror +KBUILD_AFLAGS += -Wa,--fatal-warnings +KBUILD_LDFLAGS += --fatal-warnings KBUILD_RUSTFLAGS += -Dwarnings endif From 3f0ff4cc6ffb43ea250fdf69d9f7ae8e5a05f1f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Thu, 14 Aug 2025 12:14:45 +0200 Subject: [PATCH 00841/11391] kbuild: respect CONFIG_WERROR for userprogs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The userprogs compiler and linker do not share the regular compiler flags. Make sure they also fail on warnings with CONFIG_WERROR and W=e. Signed-off-by: Thomas Weißschuh Reviewed-by: Nicolas Schier Link: https://lore.kernel.org/r/20250814-kbuild-werror-v2-5-c01e596309d2@linutronix.de Signed-off-by: Nathan Chancellor --- scripts/Makefile.extrawarn | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/Makefile.extrawarn b/scripts/Makefile.extrawarn index 6efb9e5eeeed..96ff3f5582d6 100644 --- a/scripts/Makefile.extrawarn +++ b/scripts/Makefile.extrawarn @@ -219,6 +219,8 @@ ifneq ($(findstring e, $(KBUILD_EXTRA_WARN))$(CONFIG_WERROR),) KBUILD_CPPFLAGS += -Werror KBUILD_AFLAGS += -Wa,--fatal-warnings KBUILD_LDFLAGS += --fatal-warnings +KBUILD_USERCFLAGS += -Werror +KBUILD_USERLDFLAGS += -Wl,--fatal-warnings KBUILD_RUSTFLAGS += -Dwarnings endif From 5de28cf4ae21aebb6a5af09c96d1fad9eb03f2f8 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Tue, 12 Aug 2025 13:14:27 -0500 Subject: [PATCH 00842/11391] dt-bindings: arm/cpus: Add missing Applied Micro CPU compatibles "apm,potenza" and "apm,strega" CPU compatibles have been in use for some time. Link: https://lore.kernel.org/r/20250812181428.69490-1-robh@kernel.org Signed-off-by: Rob Herring (Arm) --- Documentation/devicetree/bindings/arm/cpus.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/cpus.yaml b/Documentation/devicetree/bindings/arm/cpus.yaml index 5bd517befb68..bb1ab514924d 100644 --- a/Documentation/devicetree/bindings/arm/cpus.yaml +++ b/Documentation/devicetree/bindings/arm/cpus.yaml @@ -80,6 +80,8 @@ properties: compatible: enum: + - apm,potenza + - apm,strega - apple,avalanche - apple,blizzard - apple,cyclone From 01ce6aa56caa9dc7b240828ed40df8180df7afb7 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Tue, 12 Aug 2025 15:33:25 -0500 Subject: [PATCH 00843/11391] dt-bindings: interrupt-controller: Convert hisilicon,mbigen-v2 to DT schema Convert the HiSilicon MBIGEN binding to DT schema format. It's a straight-forward conversion. Link: https://lore.kernel.org/r/20250812203327.730393-1-robh@kernel.org Signed-off-by: Rob Herring (Arm) --- .../hisilicon,mbigen-v2.txt | 84 ------------------- .../hisilicon,mbigen-v2.yaml | 76 +++++++++++++++++ 2 files changed, 76 insertions(+), 84 deletions(-) delete mode 100644 Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt create mode 100644 Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.yaml diff --git a/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt b/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt deleted file mode 100644 index a6813a071f15..000000000000 --- a/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt +++ /dev/null @@ -1,84 +0,0 @@ -Hisilicon mbigen device tree bindings. -======================================= - -Mbigen means: message based interrupt generator. - -MBI is kind of msi interrupt only used on Non-PCI devices. - -To reduce the wired interrupt number connected to GIC, -Hisilicon designed mbigen to collect and generate interrupt. - - -Non-pci devices can connect to mbigen and generate the -interrupt by writing ITS register. - -The mbigen chip and devices connect to mbigen have the following properties: - -Mbigen main node required properties: -------------------------------------------- -- compatible: Should be "hisilicon,mbigen-v2" - -- reg: Specifies the base physical address and size of the Mbigen - registers. - -Mbigen sub node required properties: ------------------------------------------- -- interrupt controller: Identifies the node as an interrupt controller - -- msi-parent: Specifies the MSI controller this mbigen use. - For more detail information,please refer to the generic msi-parent binding in - Documentation/devicetree/bindings/interrupt-controller/msi.txt. - -- num-pins: the total number of pins implemented in this Mbigen - instance. - -- #interrupt-cells : Specifies the number of cells needed to encode an - interrupt source. The value must be 2. - - The 1st cell is hardware pin number of the interrupt.This number is local to - each mbigen chip and in the range from 0 to the maximum interrupts number - of the mbigen. - - The 2nd cell is the interrupt trigger type. - The value of this cell should be: - 1: rising edge triggered - or - 4: high level triggered - -Examples: - - mbigen_chip_dsa { - compatible = "hisilicon,mbigen-v2"; - reg = <0x0 0xc0080000 0x0 0x10000>; - - mbigen_gmac:intc_gmac { - interrupt-controller; - msi-parent = <&its_dsa 0x40b1c>; - num-pins = <9>; - #interrupt-cells = <2>; - }; - - mbigen_i2c:intc_i2c { - interrupt-controller; - msi-parent = <&its_dsa 0x40b0e>; - num-pins = <2>; - #interrupt-cells = <2>; - }; - }; - -Devices connect to mbigen required properties: ----------------------------------------------------- --interrupts:Specifies the interrupt source. - For the specific information of each cell in this property,please refer to - the "interrupt-cells" description mentioned above. - -Examples: - gmac0: ethernet@c2080000 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0 0xc2080000 0 0x20000>, - <0 0xc0000000 0 0x1000>; - interrupt-parent = <&mbigen_device_gmac>; - interrupts = <656 1>, - <657 1>; - }; diff --git a/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.yaml b/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.yaml new file mode 100644 index 000000000000..326424e6e02a --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.yaml @@ -0,0 +1,76 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interrupt-controller/hisilicon,mbigen-v2.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Hisilicon mbigen v2 + +maintainers: + - Wei Xu + +description: > + Mbigen means: message based interrupt generator. + + MBI is kind of msi interrupt only used on Non-PCI devices. + + To reduce the wired interrupt number connected to GIC, Hisilicon designed + mbigen to collect and generate interrupt. + + Non-pci devices can connect to mbigen and generate the interrupt by writing + ITS register. + +properties: + compatible: + const: hisilicon,mbigen-v2 + + reg: + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: + type: object + additionalProperties: false + + properties: + interrupt-controller: true + + '#interrupt-cells': + const: 2 + + msi-parent: + maxItems: 1 + + num-pins: + description: The total number of pins implemented in this Mbigen instance. + $ref: /schemas/types.yaml#/definitions/uint32 + + required: + - interrupt-controller + - "#interrupt-cells" + - msi-parent + - num-pins + +examples: + - | + mbigen@c0080000 { + compatible = "hisilicon,mbigen-v2"; + reg = <0xc0080000 0x10000>; + + mbigen_gmac: intc_gmac { + interrupt-controller; + #interrupt-cells = <2>; + msi-parent = <&its_dsa 0x40b1c>; + num-pins = <9>; + }; + + mbigen_i2c: intc_i2c { + interrupt-controller; + #interrupt-cells = <2>; + msi-parent = <&its_dsa 0x40b0e>; + num-pins = <2>; + }; + }; From 4239b174c2fc8307a1939ebaf51118109935a8fc Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 13 Aug 2025 18:14:48 +0200 Subject: [PATCH 00844/11391] 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 00845/11391] 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 00846/11391] 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 00847/11391] 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 @@ static int pci_dev_str_match(struct pci_dev *dev, const char *p, 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 00848/11391] 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 452d90def2dce8513d75981a4dc48e94e65ff54b Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Thu, 14 Aug 2025 11:22:11 -0400 Subject: [PATCH 00849/11391] dlm: handle invalid lockspace member remove Since commit de7b4869b4ecf ("dlm: add new configfs entry release_recover for lockspace members") we are moving lockspace members into a gone list before removing them to get additional removing attributes from configfs. There is still a very unlikely possibility when find_config_node() returns NULL, then for some reason the node wasn't marked as gone but it was removed. We will just handle this case and drop an error to observe if this case can ever happen. Reported-by: Dan Carpenter Closes: https://lore.kernel.org/gfs2/aJ2Ssuh8xlsTutrA@stanley.mountain/T/#u Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/member.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fs/dlm/member.c b/fs/dlm/member.c index 356337102015..c0f557a80a75 100644 --- a/fs/dlm/member.c +++ b/fs/dlm/member.c @@ -571,7 +571,13 @@ int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out) list_for_each_entry_safe(memb, safe, &ls->ls_nodes, list) { node = find_config_node(rv, memb->nodeid); - if (node && !node->new && !node->gone) + if (!node) { + log_error(ls, "remove member %d invalid", + memb->nodeid); + return -EFAULT; + } + + if (!node->new && !node->gone) continue; release_recover = 0; From a8abcff174f7f9ce4587c6451b1a2450d01f52c9 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Thu, 14 Aug 2025 11:22:12 -0400 Subject: [PATCH 00850/11391] dlm: move to rinfo for all middle conversion cases Since commit f74dacb4c8116 ("dlm: fix recovery of middle conversions") we introduced additional debugging information if we hit the middle conversion by using log_limit(). The DLM log_limit() functionality requires a DLM debug option being enabled. As this case is so rarely and excempt any potential introduced new issue with recovery we switching it to log_rinfo() ad this is ratelimited under normal DLM loglevel. Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/lock.c | 2 +- fs/dlm/recover.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 6dd3a524cd35..be938fdf17d9 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -5576,7 +5576,7 @@ static int receive_rcom_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb, if (rl->rl_status == DLM_LKSTS_CONVERT && middle_conversion(lkb)) { /* We may need to adjust grmode depending on other granted locks. */ - log_limit(ls, "%s %x middle convert gr %d rq %d remote %d %x", + log_rinfo(ls, "%s %x middle convert gr %d rq %d remote %d %x", __func__, lkb->lkb_id, lkb->lkb_grmode, lkb->lkb_rqmode, lkb->lkb_nodeid, lkb->lkb_remid); rsb_set_flag(r, RSB_RECOVER_CONVERT); diff --git a/fs/dlm/recover.c b/fs/dlm/recover.c index be4240f09abd..3ac020fb8139 100644 --- a/fs/dlm/recover.c +++ b/fs/dlm/recover.c @@ -842,7 +842,7 @@ static void recover_conversion(struct dlm_rsb *r) */ if (((lkb->lkb_grmode == DLM_LOCK_PR) && (other_grmode == DLM_LOCK_CW)) || ((lkb->lkb_grmode == DLM_LOCK_CW) && (other_grmode == DLM_LOCK_PR))) { - log_limit(ls, "%s %x gr %d rq %d, remote %d %x, other_lkid %u, other gr %d, set gr=NL", + log_rinfo(ls, "%s %x gr %d rq %d, remote %d %x, other_lkid %u, other gr %d, set gr=NL", __func__, lkb->lkb_id, lkb->lkb_grmode, lkb->lkb_rqmode, lkb->lkb_nodeid, lkb->lkb_remid, other_lkid, other_grmode); From 8d90041a0d285044b89629f539ca0685e156848b Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Thu, 14 Aug 2025 11:22:13 -0400 Subject: [PATCH 00851/11391] dlm: handle release_option as unsigned Future patches will introduce a invalid argument check for undefined values. All values for release_option are positive integer values to not check on negative values as well we just change the parameter to unsigned int. Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/lockspace.c | 8 ++++---- include/linux/dlm.h | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index d986b7ef153d..8eadbf0fdf17 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -676,7 +676,7 @@ int dlm_new_user_lockspace(const char *name, const char *cluster, This is because there may be LKBs queued as ASTs that have been unlinked from their RSBs and are pending deletion once the AST has been delivered */ -static int lockspace_busy(struct dlm_ls *ls, int release_option) +static int lockspace_busy(struct dlm_ls *ls, unsigned int release_option) { struct dlm_lkb *lkb; unsigned long id; @@ -704,7 +704,7 @@ static int lockspace_busy(struct dlm_ls *ls, int release_option) return rv; } -static int release_lockspace(struct dlm_ls *ls, int release_option) +static int release_lockspace(struct dlm_ls *ls, unsigned int release_option) { int busy, rv; @@ -792,7 +792,7 @@ static int release_lockspace(struct dlm_ls *ls, int release_option) * See DLM_RELEASE defines for release_option values and their meaning. */ -int dlm_release_lockspace(void *lockspace, int force) +int dlm_release_lockspace(void *lockspace, unsigned int release_option) { struct dlm_ls *ls; int error; @@ -803,7 +803,7 @@ int dlm_release_lockspace(void *lockspace, int force) dlm_put_lockspace(ls); mutex_lock(&ls_lock); - error = release_lockspace(ls, force); + error = release_lockspace(ls, release_option); if (!error) ls_count--; if (!ls_count) diff --git a/include/linux/dlm.h b/include/linux/dlm.h index 108eb953eb18..34015a008b80 100644 --- a/include/linux/dlm.h +++ b/include/linux/dlm.h @@ -122,7 +122,8 @@ int dlm_new_lockspace(const char *name, const char *cluster, * release_option: see DLM_RELEASE values above. */ -int dlm_release_lockspace(dlm_lockspace_t *lockspace, int release_option); +int dlm_release_lockspace(dlm_lockspace_t *lockspace, + unsigned int release_option); /* * dlm_lock From 8e40210788636619404871df07445fa4590138b4 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Thu, 14 Aug 2025 11:22:14 -0400 Subject: [PATCH 00852/11391] dlm: check for undefined release_option values Checking on all undefined release_option values to return -EINVAL in case a user is providing them to dlm_release_lockspace(). Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/lockspace.c | 3 +++ include/linux/dlm.h | 1 + 2 files changed, 4 insertions(+) diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index 8eadbf0fdf17..ddaa76558706 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -797,6 +797,9 @@ int dlm_release_lockspace(void *lockspace, unsigned int release_option) struct dlm_ls *ls; int error; + if (release_option > __DLM_RELEASE_MAX) + return -EINVAL; + ls = dlm_find_lockspace_local(lockspace); if (!ls) return -EINVAL; diff --git a/include/linux/dlm.h b/include/linux/dlm.h index 34015a008b80..7e7b45b0d097 100644 --- a/include/linux/dlm.h +++ b/include/linux/dlm.h @@ -113,6 +113,7 @@ int dlm_new_lockspace(const char *name, const char *cluster, #define DLM_RELEASE_NORMAL 2 #define DLM_RELEASE_NO_EVENT 3 #define DLM_RELEASE_RECOVER 4 +#define __DLM_RELEASE_MAX DLM_RELEASE_RECOVER /* * dlm_release_lockspace 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 00853/11391] 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 00854/11391] 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 00855/11391] 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 00856/11391] 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 00857/11391] 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 00858/11391] 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 00859/11391] 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 00860/11391] 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 00861/11391] 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 00862/11391] 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 00863/11391] 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 00864/11391] 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 00865/11391] 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 00866/11391] 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 00867/11391] 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 00868/11391] 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 00869/11391] 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 00870/11391] 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 28f073b38372b99d8d33ff5e63897d28419bda20 Mon Sep 17 00:00:00 2001 From: Dave Ertman Date: Mon, 16 Jun 2025 13:03:23 +0200 Subject: [PATCH 00871/11391] ice: Implement support for SRIOV VFs across Active/Active bonds This patch implements the software flows to handle SRIOV VF communication across an Active/Active link aggregate. The same restrictions apply as are in place for the support of Active/Backup bonds. - the two interfaces must be on the same NIC - the FW LLDP engine needs to be disabled - the DDP package that supports VF LAG must be loaded on device - the two interfaces must have the same QoS config - only the first interface added to the bond will have VF support - the interface with VFs must be in switchdev mode With the additional requirement of - the version of the FW on the NIC needs to have VF Active/Active support This requirement is indicated in the capabilities struct associated with the NVM loaded on the NIC. The balancing of traffic between the two interfaces is done on a queue basis. Taking the queues allocated to all of the VFs as a whole, one half of them will be distributed to each interface. When a link goes down, then the queues allocated to the down interface will migrate to the active port. When the down port comes back up, then the same queues as were originally assigned there will be moved back. Co-developed-by: Marcin Szycik Signed-off-by: Marcin Szycik Signed-off-by: Dave Ertman Tested-by: Sujai Buvaneswaran Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice.h | 1 + .../net/ethernet/intel/ice/ice_adminq_cmd.h | 4 + drivers/net/ethernet/intel/ice/ice_common.c | 15 +- drivers/net/ethernet/intel/ice/ice_common.h | 2 +- drivers/net/ethernet/intel/ice/ice_lag.c | 770 +++++++++++++++--- drivers/net/ethernet/intel/ice/ice_lag.h | 21 +- drivers/net/ethernet/intel/ice/ice_type.h | 1 + include/linux/net/intel/libie/adminq.h | 1 + 8 files changed, 712 insertions(+), 103 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 2098f00b3cd3..a83fdd22cbe4 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -203,6 +203,7 @@ enum ice_feature { ICE_F_GCS, ICE_F_ROCE_LAG, ICE_F_SRIOV_LAG, + ICE_F_SRIOV_AA_LAG, ICE_F_MBX_LIMIT, ICE_F_MAX }; diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index 3bd3ea3af888..caae1780fd37 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -2060,6 +2060,10 @@ struct ice_aqc_cfg_txqs { #define ICE_AQC_Q_CFG_SRC_PRT_M 0x7 #define ICE_AQC_Q_CFG_DST_PRT_S 3 #define ICE_AQC_Q_CFG_DST_PRT_M (0x7 << ICE_AQC_Q_CFG_DST_PRT_S) +#define ICE_AQC_Q_CFG_MODE_M GENMASK(7, 6) +#define ICE_AQC_Q_CFG_MODE_SAME_PF 0x0 +#define ICE_AQC_Q_CFG_MODE_GIVE_OWN 0x1 +#define ICE_AQC_Q_CFG_MODE_KEEP_OWN 0x2 u8 time_out; #define ICE_AQC_Q_CFG_TIMEOUT_S 2 #define ICE_AQC_Q_CFG_TIMEOUT_M (0x1F << ICE_AQC_Q_CFG_TIMEOUT_S) diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 209f42045fea..808870539667 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -2424,6 +2424,9 @@ ice_parse_common_caps(struct ice_hw *hw, struct ice_hw_common_caps *caps, caps->sriov_lag = number & LIBIE_AQC_BIT_SRIOV_LAG; ice_debug(hw, ICE_DBG_INIT, "%s: sriov_lag = %u\n", prefix, caps->sriov_lag); + caps->sriov_aa_lag = number & LIBIE_AQC_BIT_SRIOV_AA_LAG; + ice_debug(hw, ICE_DBG_INIT, "%s: sriov_aa_lag = %u\n", + prefix, caps->sriov_aa_lag); break; case LIBIE_AQC_CAPS_TX_SCHED_TOPO_COMP_MODE: caps->tx_sched_topo_comp_mode_en = (number == 1); @@ -4712,24 +4715,24 @@ ice_aq_dis_lan_txq(struct ice_hw *hw, u8 num_qgrps, } /** - * ice_aq_cfg_lan_txq + * ice_aq_cfg_lan_txq - send AQ command 0x0C32 to FW * @hw: pointer to the hardware structure * @buf: buffer for command * @buf_size: size of buffer in bytes * @num_qs: number of queues being configured * @oldport: origination lport * @newport: destination lport + * @mode: cmd_type for move to use * @cd: pointer to command details structure or NULL * * Move/Configure LAN Tx queue (0x0C32) * - * There is a better AQ command to use for moving nodes, so only coding - * this one for configuring the node. + * Return: Zero on success, associated error code on failure. */ int ice_aq_cfg_lan_txq(struct ice_hw *hw, struct ice_aqc_cfg_txqs_buf *buf, u16 buf_size, u16 num_qs, u8 oldport, u8 newport, - struct ice_sq_cd *cd) + u8 mode, struct ice_sq_cd *cd) { struct ice_aqc_cfg_txqs *cmd; struct libie_aq_desc desc; @@ -4742,10 +4745,12 @@ ice_aq_cfg_lan_txq(struct ice_hw *hw, struct ice_aqc_cfg_txqs_buf *buf, if (!buf) return -EINVAL; - cmd->cmd_type = ICE_AQC_Q_CFG_TC_CHNG; + cmd->cmd_type = mode; cmd->num_qs = num_qs; cmd->port_num_chng = (oldport & ICE_AQC_Q_CFG_SRC_PRT_M); cmd->port_num_chng |= FIELD_PREP(ICE_AQC_Q_CFG_DST_PRT_M, newport); + cmd->port_num_chng |= FIELD_PREP(ICE_AQC_Q_CFG_MODE_M, + ICE_AQC_Q_CFG_MODE_KEEP_OWN); cmd->time_out = FIELD_PREP(ICE_AQC_Q_CFG_TIMEOUT_M, 5); cmd->blocked_cgds = 0; diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h index 60320cdf7804..dba15ad315a6 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.h +++ b/drivers/net/ethernet/intel/ice/ice_common.h @@ -270,7 +270,7 @@ ice_ena_vsi_txq(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u16 q_handle, int ice_aq_cfg_lan_txq(struct ice_hw *hw, struct ice_aqc_cfg_txqs_buf *buf, u16 buf_size, u16 num_qs, u8 oldport, u8 newport, - struct ice_sq_cd *cd); + u8 mode, struct ice_sq_cd *cd); int ice_replay_vsi(struct ice_hw *hw, u16 vsi_handle); void ice_replay_post(struct ice_hw *hw); struct ice_q_ctx * diff --git a/drivers/net/ethernet/intel/ice/ice_lag.c b/drivers/net/ethernet/intel/ice/ice_lag.c index 72284555b98a..80312e1dcf7f 100644 --- a/drivers/net/ethernet/intel/ice/ice_lag.c +++ b/drivers/net/ethernet/intel/ice/ice_lag.c @@ -14,6 +14,9 @@ static const u8 lacp_train_pkt[ICE_TRAIN_PKT_LEN] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x88, 0x09, 0, 0 }; +static const u8 act_act_train_pkt[ICE_TRAIN_PKT_LEN] = { 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0 }; #define ICE_RECIPE_LEN 64 #define ICE_LAG_SRIOV_CP_RECIPE 10 @@ -48,10 +51,10 @@ static void ice_lag_set_primary(struct ice_lag *lag) } /** - * ice_lag_set_backup - set PF LAG state to Backup + * ice_lag_set_bkup - set PF LAG state to Backup * @lag: LAG info struct */ -static void ice_lag_set_backup(struct ice_lag *lag) +static void ice_lag_set_bkup(struct ice_lag *lag) { struct ice_pf *pf = lag->pf; @@ -337,25 +340,15 @@ ice_lag_cfg_drop_fltr(struct ice_lag *lag, bool add) } /** - * ice_lag_cfg_pf_fltrs - set filters up for new active port + * ice_lag_cfg_pf_fltrs_act_bkup - set filters up for new active port * @lag: local interfaces lag struct - * @ptr: opaque data containing notifier event + * @bonding_info: netdev event bonding info */ static void -ice_lag_cfg_pf_fltrs(struct ice_lag *lag, void *ptr) +ice_lag_cfg_pf_fltrs_act_bkup(struct ice_lag *lag, + struct netdev_bonding_info *bonding_info) { - struct netdev_notifier_bonding_info *info = ptr; - struct netdev_bonding_info *bonding_info; - struct net_device *event_netdev; - struct device *dev; - - event_netdev = netdev_notifier_info_to_dev(ptr); - /* not for this netdev */ - if (event_netdev != lag->netdev) - return; - - bonding_info = &info->bonding_info; - dev = ice_pf_to_dev(lag->pf); + struct device *dev = ice_pf_to_dev(lag->pf); /* interface not active - remove old default VSI rule */ if (bonding_info->slave.state && lag->pf_rx_rule_id) { @@ -376,12 +369,13 @@ ice_lag_cfg_pf_fltrs(struct ice_lag *lag, void *ptr) } /** - * ice_lag_cfg_cp_fltr - configure filter for control packets + * ice_lag_cfg_lp_fltr - configure lport filters * @lag: local interface's lag struct * @add: add or remove rule + * @cp: control packet only or general PF lport rule */ static void -ice_lag_cfg_cp_fltr(struct ice_lag *lag, bool add) +ice_lag_cfg_lp_fltr(struct ice_lag *lag, bool add, bool cp) { struct ice_sw_rule_lkup_rx_tx *s_rule; struct ice_vsi *vsi = lag->pf->vsi[0]; @@ -395,8 +389,17 @@ ice_lag_cfg_cp_fltr(struct ice_lag *lag, bool add) } if (add) { - s_rule->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_RX); - s_rule->recipe_id = cpu_to_le16(ICE_LAG_SRIOV_CP_RECIPE); + if (cp) { + s_rule->recipe_id = + cpu_to_le16(ICE_LAG_SRIOV_CP_RECIPE); + memcpy(s_rule->hdr_data, lacp_train_pkt, + ICE_TRAIN_PKT_LEN); + } else { + s_rule->recipe_id = cpu_to_le16(lag->act_act_recipe); + memcpy(s_rule->hdr_data, act_act_train_pkt, + ICE_TRAIN_PKT_LEN); + } + s_rule->src = cpu_to_le16(vsi->port_info->lport); s_rule->act = cpu_to_le32(ICE_FWD_TO_VSI | ICE_SINGLE_ACT_LAN_ENABLE | @@ -404,27 +407,66 @@ ice_lag_cfg_cp_fltr(struct ice_lag *lag, bool add) FIELD_PREP(ICE_SINGLE_ACT_VSI_ID_M, vsi->vsi_num)); s_rule->hdr_len = cpu_to_le16(ICE_TRAIN_PKT_LEN); - memcpy(s_rule->hdr_data, lacp_train_pkt, ICE_TRAIN_PKT_LEN); + s_rule->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_RX); opc = ice_aqc_opc_add_sw_rules; } else { opc = ice_aqc_opc_remove_sw_rules; - s_rule->index = cpu_to_le16(lag->cp_rule_idx); + if (cp) + s_rule->index = cpu_to_le16(lag->cp_rule_idx); + else + s_rule->index = cpu_to_le16(lag->act_act_rule_idx); } if (ice_aq_sw_rules(&lag->pf->hw, s_rule, buf_len, 1, opc, NULL)) { - netdev_warn(lag->netdev, "Error %s CP rule for fail-over\n", - add ? "ADDING" : "REMOVING"); + netdev_warn(lag->netdev, "Error %s %s rule for aggregate\n", + add ? "ADDING" : "REMOVING", + cp ? "CONTROL PACKET" : "LPORT"); goto err_cp_free; } - if (add) - lag->cp_rule_idx = le16_to_cpu(s_rule->index); - else - lag->cp_rule_idx = 0; + if (add) { + if (cp) + lag->cp_rule_idx = le16_to_cpu(s_rule->index); + else + lag->act_act_rule_idx = le16_to_cpu(s_rule->index); + } else { + if (cp) + lag->cp_rule_idx = 0; + else + lag->act_act_rule_idx = 0; + } err_cp_free: kfree(s_rule); } +/** + * ice_lag_cfg_pf_fltrs - set filters up for PF traffic + * @lag: local interfaces lag struct + * @ptr: opaque data containing notifier event + */ +static void +ice_lag_cfg_pf_fltrs(struct ice_lag *lag, void *ptr) +{ + struct netdev_notifier_bonding_info *info = ptr; + struct netdev_bonding_info *bonding_info; + struct net_device *event_netdev; + + event_netdev = netdev_notifier_info_to_dev(ptr); + if (event_netdev != lag->netdev) + return; + + bonding_info = &info->bonding_info; + + if (lag->bond_aa) { + if (lag->need_fltr_cfg) { + ice_lag_cfg_lp_fltr(lag, true, false); + lag->need_fltr_cfg = false; + } + } else { + ice_lag_cfg_pf_fltrs_act_bkup(lag, bonding_info); + } +} + /** * ice_display_lag_info - print LAG info * @lag: LAG info struct @@ -648,7 +690,7 @@ ice_lag_move_vf_node_tc(struct ice_lag *lag, u8 oldport, u8 newport, } if (ice_aq_cfg_lan_txq(&lag->pf->hw, qbuf, qbuf_size, valq, oldport, - newport, NULL)) { + newport, ICE_AQC_Q_CFG_TC_CHNG, NULL)) { dev_warn(dev, "Failure to configure queues for LAG failover\n"); goto qbuf_err; } @@ -784,10 +826,17 @@ void ice_lag_move_new_vf_nodes(struct ice_vf *vf) if (lag->upper_netdev) ice_lag_build_netdev_list(lag, &ndlist); - if (ice_is_feature_supported(pf, ICE_F_SRIOV_LAG) && - lag->bonded && lag->primary && pri_port != act_port && - !list_empty(lag->netdev_head)) - ice_lag_move_single_vf_nodes(lag, pri_port, act_port, vsi->idx); + if (lag->bonded && lag->primary && !list_empty(lag->netdev_head)) { + if (lag->bond_aa && + ice_is_feature_supported(pf, ICE_F_SRIOV_AA_LAG)) + ice_lag_aa_failover(lag, ICE_LAGS_IDX, NULL); + + if (!lag->bond_aa && + ice_is_feature_supported(pf, ICE_F_SRIOV_LAG) && + pri_port != act_port) + ice_lag_move_single_vf_nodes(lag, pri_port, act_port, + vsi->idx); + } ice_lag_destroy_netdev_list(lag, &ndlist); @@ -851,11 +900,20 @@ u8 ice_lag_prepare_vf_reset(struct ice_lag *lag) u8 pri_prt, act_prt; if (lag && lag->bonded && lag->primary && lag->upper_netdev) { - pri_prt = lag->pf->hw.port_info->lport; - act_prt = lag->active_port; - if (act_prt != pri_prt && act_prt != ICE_LAG_INVALID_PORT) { - ice_lag_move_vf_nodes_cfg(lag, act_prt, pri_prt); - return act_prt; + if (!lag->bond_aa) { + pri_prt = lag->pf->hw.port_info->lport; + act_prt = lag->active_port; + if (act_prt != pri_prt && + act_prt != ICE_LAG_INVALID_PORT) { + ice_lag_move_vf_nodes_cfg(lag, act_prt, pri_prt); + return act_prt; + } + } else { + if (lag->port_bitmap & ICE_LAGS_M) { + lag->port_bitmap &= ~ICE_LAGS_M; + ice_lag_aa_failover(lag, ICE_LAGP_IDX, NULL); + lag->port_bitmap |= ICE_LAGS_M; + } } } @@ -873,10 +931,15 @@ void ice_lag_complete_vf_reset(struct ice_lag *lag, u8 act_prt) { u8 pri_prt; - if (lag && lag->bonded && lag->primary && - act_prt != ICE_LAG_INVALID_PORT) { - pri_prt = lag->pf->hw.port_info->lport; - ice_lag_move_vf_nodes_cfg(lag, pri_prt, act_prt); + if (lag && lag->bonded && lag->primary) { + if (!lag->bond_aa) { + pri_prt = lag->pf->hw.port_info->lport; + if (act_prt != ICE_LAG_INVALID_PORT) + ice_lag_move_vf_nodes_cfg(lag, pri_prt, + act_prt); + } else { + ice_lag_aa_failover(lag, ICE_LAGS_IDX, NULL); + } } } @@ -912,7 +975,7 @@ static void ice_lag_info_event(struct ice_lag *lag, void *ptr) } if (bonding_info->slave.state) - ice_lag_set_backup(lag); + ice_lag_set_bkup(lag); else ice_lag_set_primary(lag); @@ -920,6 +983,295 @@ static void ice_lag_info_event(struct ice_lag *lag, void *ptr) ice_display_lag_info(lag); } +/** + * ice_lag_aa_qbuf_recfg - fill a single queue buffer for recfg cmd + * @hw: HW struct that contains the queue context + * @qbuf: pointer to single queue buffer + * @vsi_num: index of the VF VSI in PF space + * @qnum: queue index + * + * Return: Zero on success, error code on failure. + */ +static int +ice_lag_aa_qbuf_recfg(struct ice_hw *hw, struct ice_aqc_cfg_txqs_buf *qbuf, + u16 vsi_num, int qnum) +{ + struct ice_pf *pf = hw->back; + struct ice_q_ctx *q_ctx; + u16 q_id; + + q_ctx = ice_get_lan_q_ctx(hw, vsi_num, 0, qnum); + if (!q_ctx) { + dev_dbg(ice_hw_to_dev(hw), "LAG queue %d no Q context\n", qnum); + return -ENOENT; + } + + if (q_ctx->q_teid == ICE_INVAL_TEID) { + dev_dbg(ice_hw_to_dev(hw), "LAG queue %d INVAL TEID\n", qnum); + return -EINVAL; + } + + if (q_ctx->q_handle == ICE_INVAL_Q_HANDLE) { + dev_dbg(ice_hw_to_dev(hw), "LAG queue %d INVAL Q HANDLE\n", qnum); + return -EINVAL; + } + + q_id = pf->vsi[vsi_num]->txq_map[q_ctx->q_handle]; + qbuf->queue_info[0].q_handle = cpu_to_le16(q_id); + qbuf->queue_info[0].tc = 0; + qbuf->queue_info[0].q_teid = cpu_to_le32(q_ctx->q_teid); + + return 0; +} + +/** + * ice_lag_aa_move_vf_qs - Move some/all VF queues to destination + * @lag: primary interface's lag struct + * @dest: index of destination port + * @vsi_num: index of VF VSI in PF space + * @all: if true move all queues to destination + * @odd: VF wide q indicator for odd/even + * @e_pf: PF struct for the event interface + * + * the parameter "all" is to control whether we are splitting the queues + * between two interfaces or moving them all to the destination interface + */ +static void ice_lag_aa_move_vf_qs(struct ice_lag *lag, u8 dest, u16 vsi_num, + bool all, bool *odd, struct ice_pf *e_pf) +{ + DEFINE_RAW_FLEX(struct ice_aqc_cfg_txqs_buf, qbuf, queue_info, 1); + struct ice_hw *old_hw, *new_hw, *pri_hw, *sec_hw; + struct device *dev = ice_pf_to_dev(lag->pf); + struct ice_vsi_ctx *pv_ctx, *sv_ctx; + struct ice_lag_netdev_list ndlist; + u16 num_q, qbuf_size, sec_vsi_num; + u8 pri_lport, sec_lport; + u32 pvf_teid, svf_teid; + u16 vf_id; + + vf_id = lag->pf->vsi[vsi_num]->vf->vf_id; + /* If sec_vf[] not defined, then no second interface to share with */ + if (lag->sec_vf[vf_id]) + sec_vsi_num = lag->sec_vf[vf_id]->idx; + else + return; + + pri_lport = lag->bond_lport_pri; + sec_lport = lag->bond_lport_sec; + + if (pri_lport == ICE_LAG_INVALID_PORT || + sec_lport == ICE_LAG_INVALID_PORT) + return; + + if (!e_pf) + ice_lag_build_netdev_list(lag, &ndlist); + + pri_hw = &lag->pf->hw; + if (e_pf && lag->pf != e_pf) + sec_hw = &e_pf->hw; + else + sec_hw = ice_lag_find_hw_by_lport(lag, sec_lport); + + if (!pri_hw || !sec_hw) + return; + + if (dest == ICE_LAGP_IDX) { + struct ice_vsi *vsi; + + vsi = ice_get_main_vsi(lag->pf); + if (!vsi) + return; + + old_hw = sec_hw; + new_hw = pri_hw; + ice_lag_config_eswitch(lag, vsi->netdev); + } else { + struct ice_pf *sec_pf = sec_hw->back; + struct ice_vsi *vsi; + + vsi = ice_get_main_vsi(sec_pf); + if (!vsi) + return; + + old_hw = pri_hw; + new_hw = sec_hw; + ice_lag_config_eswitch(lag, vsi->netdev); + } + + pv_ctx = ice_get_vsi_ctx(pri_hw, vsi_num); + if (!pv_ctx) { + dev_warn(dev, "Unable to locate primary VSI %d context for LAG failover\n", + vsi_num); + return; + } + + sv_ctx = ice_get_vsi_ctx(sec_hw, sec_vsi_num); + if (!sv_ctx) { + dev_warn(dev, "Unable to locate secondary VSI %d context for LAG failover\n", + vsi_num); + return; + } + + num_q = pv_ctx->num_lan_q_entries[0]; + qbuf_size = __struct_size(qbuf); + + /* Suspend traffic for primary VSI VF */ + pvf_teid = le32_to_cpu(pv_ctx->sched.vsi_node[0]->info.node_teid); + ice_sched_suspend_resume_elems(pri_hw, 1, &pvf_teid, true); + + /* Suspend traffic for secondary VSI VF */ + svf_teid = le32_to_cpu(sv_ctx->sched.vsi_node[0]->info.node_teid); + ice_sched_suspend_resume_elems(sec_hw, 1, &svf_teid, true); + + for (int i = 0; i < num_q; i++) { + struct ice_sched_node *n_prt, *q_node, *parent; + struct ice_port_info *pi, *new_pi; + struct ice_vsi_ctx *src_ctx; + struct ice_sched_node *p; + struct ice_q_ctx *q_ctx; + u16 dst_vsi_num; + + pi = old_hw->port_info; + new_pi = new_hw->port_info; + + *odd = !(*odd); + if ((dest == ICE_LAGP_IDX && *odd && !all) || + (dest == ICE_LAGS_IDX && !(*odd) && !all) || + lag->q_home[vf_id][i] == dest) + continue; + + if (dest == ICE_LAGP_IDX) + dst_vsi_num = vsi_num; + else + dst_vsi_num = sec_vsi_num; + + n_prt = ice_sched_get_free_qparent(new_hw->port_info, + dst_vsi_num, 0, + ICE_SCHED_NODE_OWNER_LAN); + if (!n_prt) + continue; + + q_ctx = ice_get_lan_q_ctx(pri_hw, vsi_num, 0, i); + if (!q_ctx) + continue; + + if (dest == ICE_LAGP_IDX) + src_ctx = sv_ctx; + else + src_ctx = pv_ctx; + + q_node = ice_sched_find_node_by_teid(src_ctx->sched.vsi_node[0], + q_ctx->q_teid); + if (!q_node) + continue; + + qbuf->src_parent_teid = q_node->info.parent_teid; + qbuf->dst_parent_teid = n_prt->info.node_teid; + + /* Move the node in the HW/FW */ + if (ice_lag_aa_qbuf_recfg(pri_hw, qbuf, vsi_num, i)) + continue; + + if (dest == ICE_LAGP_IDX) + ice_aq_cfg_lan_txq(pri_hw, qbuf, qbuf_size, 1, + sec_lport, pri_lport, + ICE_AQC_Q_CFG_MOVE_TC_CHNG, + NULL); + else + ice_aq_cfg_lan_txq(pri_hw, qbuf, qbuf_size, 1, + pri_lport, sec_lport, + ICE_AQC_Q_CFG_MOVE_TC_CHNG, + NULL); + + /* Move the node in the SW */ + parent = q_node->parent; + if (!parent) + continue; + + for (int n = 0; n < parent->num_children; n++) { + int j; + + if (parent->children[n] != q_node) + continue; + + for (j = n + 1; j < parent->num_children; + j++) { + parent->children[j - 1] = + parent->children[j]; + } + parent->children[j] = NULL; + parent->num_children--; + break; + } + + p = pi->sib_head[0][q_node->tx_sched_layer]; + while (p) { + if (p->sibling == q_node) { + p->sibling = q_node->sibling; + break; + } + p = p->sibling; + } + + if (pi->sib_head[0][q_node->tx_sched_layer] == q_node) + pi->sib_head[0][q_node->tx_sched_layer] = + q_node->sibling; + + q_node->parent = n_prt; + q_node->info.parent_teid = n_prt->info.node_teid; + q_node->sibling = NULL; + p = new_pi->sib_head[0][q_node->tx_sched_layer]; + if (p) { + while (p) { + if (!p->sibling) { + p->sibling = q_node; + break; + } + p = p->sibling; + } + } else { + new_pi->sib_head[0][q_node->tx_sched_layer] = + q_node; + } + + n_prt->children[n_prt->num_children++] = q_node; + lag->q_home[vf_id][i] = dest; + } + + ice_sched_suspend_resume_elems(pri_hw, 1, &pvf_teid, false); + ice_sched_suspend_resume_elems(sec_hw, 1, &svf_teid, false); + + if (!e_pf) + ice_lag_destroy_netdev_list(lag, &ndlist); +} + +/** + * ice_lag_aa_failover - move VF queues in A/A mode + * @lag: primary lag struct + * @dest: index of destination port + * @e_pf: PF struct for event port + */ +void ice_lag_aa_failover(struct ice_lag *lag, u8 dest, struct ice_pf *e_pf) +{ + bool odd = true, all = false; + int i; + + /* Primary can be a target if down (cleanup), but secondary can't */ + if (dest == ICE_LAGS_IDX && !(lag->port_bitmap & ICE_LAGS_M)) + return; + + /* Move all queues to a destination if only one port is active, + * or no ports are active and dest is primary. + */ + if ((lag->port_bitmap ^ (ICE_LAGP_M | ICE_LAGS_M)) || + (!lag->port_bitmap && dest == ICE_LAGP_IDX)) + all = true; + + ice_for_each_vsi(lag->pf, i) + if (lag->pf->vsi[i] && lag->pf->vsi[i]->type == ICE_VSI_VF) + ice_lag_aa_move_vf_qs(lag, dest, i, all, &odd, e_pf); +} + /** * ice_lag_reclaim_vf_tc - move scheduling nodes back to primary interface * @lag: primary interface lag struct @@ -982,7 +1334,7 @@ ice_lag_reclaim_vf_tc(struct ice_lag *lag, struct ice_hw *src_hw, u16 vsi_num, if (ice_aq_cfg_lan_txq(hw, qbuf, qbuf_size, numq, src_hw->port_info->lport, hw->port_info->lport, - NULL)) { + ICE_AQC_Q_CFG_TC_CHNG, NULL)) { dev_warn(dev, "Failure to configure queues for LAG failover\n"); goto reclaim_qerr; } @@ -1053,14 +1405,15 @@ static void ice_lag_link(struct ice_lag *lag) lag->bonded = true; lag->role = ICE_LAG_UNSET; + lag->need_fltr_cfg = true; netdev_info(lag->netdev, "Shared SR-IOV resources in bond are active\n"); } /** - * ice_lag_unlink - handle unlink event + * ice_lag_act_bkup_unlink - handle unlink event for A/B bond * @lag: LAG info struct */ -static void ice_lag_unlink(struct ice_lag *lag) +static void ice_lag_act_bkup_unlink(struct ice_lag *lag) { u8 pri_port, act_port, loc_port; struct ice_pf *pf = lag->pf; @@ -1096,10 +1449,32 @@ static void ice_lag_unlink(struct ice_lag *lag) } } } +} - lag->bonded = false; - lag->role = ICE_LAG_NONE; - lag->upper_netdev = NULL; +/** + * ice_lag_aa_unlink - handle unlink event for Active-Active bond + * @lag: LAG info struct + */ +static void ice_lag_aa_unlink(struct ice_lag *lag) +{ + struct ice_lag *pri_lag; + + if (lag->primary) { + pri_lag = lag; + lag->port_bitmap &= ~ICE_LAGP_M; + } else { + pri_lag = ice_lag_find_primary(lag); + if (pri_lag) + pri_lag->port_bitmap &= ICE_LAGS_M; + } + + if (pri_lag) { + ice_lag_aa_failover(pri_lag, ICE_LAGP_IDX, lag->pf); + if (lag->primary) + pri_lag->bond_lport_pri = ICE_LAG_INVALID_PORT; + else + pri_lag->bond_lport_sec = ICE_LAG_INVALID_PORT; + } } /** @@ -1115,10 +1490,20 @@ static void ice_lag_link_unlink(struct ice_lag *lag, void *ptr) if (netdev != lag->netdev) return; - if (info->linking) + if (info->linking) { ice_lag_link(lag); - else - ice_lag_unlink(lag); + } else { + if (lag->bond_aa) + ice_lag_aa_unlink(lag); + else + ice_lag_act_bkup_unlink(lag); + + lag->bonded = false; + lag->role = ICE_LAG_NONE; + lag->upper_netdev = NULL; + lag->bond_aa = false; + lag->need_fltr_cfg = false; + } } /** @@ -1320,6 +1705,11 @@ static void ice_lag_init_feature_support_flag(struct ice_pf *pf) ice_set_feature_support(pf, ICE_F_SRIOV_LAG); else ice_clear_feature_support(pf, ICE_F_SRIOV_LAG); + + if (caps->sriov_aa_lag && ice_pkg_has_lport_extract(&pf->hw)) + ice_set_feature_support(pf, ICE_F_SRIOV_AA_LAG); + else + ice_clear_feature_support(pf, ICE_F_SRIOV_AA_LAG); } /** @@ -1353,6 +1743,9 @@ static void ice_lag_changeupper_event(struct ice_lag *lag, void *ptr) /* Configure primary's SWID to be shared */ ice_lag_primary_swid(lag, true); primary_lag = lag; + lag->bond_lport_pri = lag->pf->hw.port_info->lport; + lag->bond_lport_sec = ICE_LAG_INVALID_PORT; + lag->port_bitmap = 0; } else { u16 swid; @@ -1362,16 +1755,29 @@ static void ice_lag_changeupper_event(struct ice_lag *lag, void *ptr) swid = primary_lag->pf->hw.port_info->sw_id; ice_lag_set_swid(swid, lag, true); ice_lag_add_prune_list(primary_lag, lag->pf); - ice_lag_cfg_drop_fltr(lag, true); + primary_lag->bond_lport_sec = + lag->pf->hw.port_info->lport; } /* add filter for primary control packets */ - ice_lag_cfg_cp_fltr(lag, true); + ice_lag_cfg_lp_fltr(lag, true, true); } else { if (!primary_lag && lag->primary) primary_lag = lag; + if (primary_lag) { + for (int i = 0; i < ICE_MAX_SRIOV_VFS; i++) { + if (primary_lag->sec_vf[i]) { + ice_vsi_release(primary_lag->sec_vf[i]); + primary_lag->sec_vf[i] = NULL; + } + } + } + if (!lag->primary) { ice_lag_set_swid(0, lag, false); + if (primary_lag) + primary_lag->bond_lport_sec = + ICE_LAG_INVALID_PORT; } else { if (primary_lag && lag->primary) { ice_lag_primary_swid(lag, false); @@ -1379,7 +1785,7 @@ static void ice_lag_changeupper_event(struct ice_lag *lag, void *ptr) } } /* remove filter for control packets */ - ice_lag_cfg_cp_fltr(lag, false); + ice_lag_cfg_lp_fltr(lag, false, !lag->bond_aa); } } @@ -1405,18 +1811,34 @@ static void ice_lag_monitor_link(struct ice_lag *lag, void *ptr) if (!netif_is_same_ice(lag->pf, event_netdev)) return; + if (info->upper_dev != lag->upper_netdev) + return; + + if (info->linking) + return; + pf = lag->pf; prim_hw = &pf->hw; prim_port = prim_hw->port_info->lport; - if (info->upper_dev != lag->upper_netdev) - return; + /* Since there are only two interfaces allowed in SRIOV+LAG, if + * one port is leaving, then nodes need to be on primary + * interface. + */ + if (lag->bond_aa) { + struct ice_netdev_priv *e_ndp; + struct ice_pf *e_pf; - if (!info->linking) { - /* Since there are only two interfaces allowed in SRIOV+LAG, if - * one port is leaving, then nodes need to be on primary - * interface. - */ + e_ndp = netdev_priv(event_netdev); + e_pf = e_ndp->vsi->back; + + if (lag->bond_lport_pri != ICE_LAG_INVALID_PORT && + lag->port_bitmap & ICE_LAGS_M) { + lag->port_bitmap &= ~ICE_LAGS_M; + ice_lag_aa_failover(lag, ICE_LAGP_IDX, e_pf); + lag->bond_lport_sec = ICE_LAG_INVALID_PORT; + } + } else { if (prim_port != lag->active_port && lag->active_port != ICE_LAG_INVALID_PORT) { active_hw = ice_lag_find_hw_by_lport(lag, @@ -1428,44 +1850,32 @@ static void ice_lag_monitor_link(struct ice_lag *lag, void *ptr) } /** - * ice_lag_monitor_active - main PF keep track of which port is active + * ice_lag_monitor_act_bkup - keep track of which port is active in A/B LAG * @lag: lag info struct - * @ptr: opaque data containing notifier event + * @b_info: bonding info + * @event_netdev: net_device got target netdev * * This function is for the primary PF to monitor changes in which port is * active and handle changes for SRIOV VF functionality */ -static void ice_lag_monitor_active(struct ice_lag *lag, void *ptr) +static void ice_lag_monitor_act_bkup(struct ice_lag *lag, + struct netdev_bonding_info *b_info, + struct net_device *event_netdev) { - struct netdev_notifier_bonding_info *info = ptr; - struct net_device *event_netdev, *event_upper; - struct netdev_bonding_info *bonding_info; struct ice_netdev_priv *event_np; struct ice_pf *pf, *event_pf; u8 prim_port, event_port; - if (!lag->primary) - return; - pf = lag->pf; if (!pf) return; - event_netdev = netdev_notifier_info_to_dev(ptr); - rcu_read_lock(); - event_upper = netdev_master_upper_dev_get_rcu(event_netdev); - rcu_read_unlock(); - if (!netif_is_ice(event_netdev) || event_upper != lag->upper_netdev) - return; - event_np = netdev_priv(event_netdev); event_pf = event_np->vsi->back; event_port = event_pf->hw.port_info->lport; prim_port = pf->hw.port_info->lport; - bonding_info = &info->bonding_info; - - if (!bonding_info->slave.state) { + if (!b_info->slave.state) { /* if no port is currently active, then nodes and filters exist * on primary port, check if we need to move them */ @@ -1501,6 +1911,128 @@ static void ice_lag_monitor_active(struct ice_lag *lag, void *ptr) } } +/** + * ice_lag_aa_clear_spoof - adjust the placeholder VSI spoofing for A/A LAG + * @vsi: placeholder VSI to adjust + */ +static void ice_lag_aa_clear_spoof(struct ice_vsi *vsi) +{ + ice_vsi_update_security(vsi, ice_vsi_ctx_clear_antispoof); +} + +/** + * ice_lag_monitor_act_act - Keep track of active ports in A/A LAG + * @lag: lag struct for primary interface + * @b_info: bonding_info for event + * @event_netdev: net_device for target netdev + */ +static void ice_lag_monitor_act_act(struct ice_lag *lag, + struct netdev_bonding_info *b_info, + struct net_device *event_netdev) +{ + struct ice_netdev_priv *event_np; + u8 prim_port, event_port; + struct ice_pf *event_pf; + + event_np = netdev_priv(event_netdev); + event_pf = event_np->vsi->back; + event_port = event_pf->hw.port_info->lport; + prim_port = lag->pf->hw.port_info->lport; + + if (b_info->slave.link == BOND_LINK_UP) { + /* Port is coming up */ + if (prim_port == event_port) { + /* Processing event for primary interface */ + if (lag->bond_lport_pri == ICE_LAG_INVALID_PORT) + return; + + if (!(lag->port_bitmap & ICE_LAGP_M)) { + /* Primary port was not marked up before, move + * some|all VF queues to it and mark as up + */ + lag->port_bitmap |= ICE_LAGP_M; + ice_lag_aa_failover(lag, ICE_LAGP_IDX, event_pf); + } + } else { + if (lag->bond_lport_sec == ICE_LAG_INVALID_PORT) + return; + + /* Create placeholder VSIs on secondary PF. + * The placeholder is necessary so that we have + * an element that represents the VF on the secondary + * interface's scheduling tree. This will be a tree + * root for scheduling nodes when they are moved to + * the secondary interface. + */ + if (!lag->sec_vf[0]) { + struct ice_vsi_cfg_params params = {}; + struct ice_vsi *nvsi; + struct ice_vf *vf; + unsigned int bkt; + + params.type = ICE_VSI_VF; + params.port_info = event_pf->hw.port_info; + params.flags = ICE_VSI_FLAG_INIT; + + ice_for_each_vf(lag->pf, bkt, vf) { + params.vf = vf; + nvsi = ice_vsi_setup(event_pf, + ¶ms); + ice_lag_aa_clear_spoof(nvsi); + lag->sec_vf[vf->vf_id] = nvsi; + } + } + + if (!(lag->port_bitmap & ICE_LAGS_M)) { + /* Secondary port was not marked up before, + * move some|all VF queues to it and mark as up + */ + lag->port_bitmap |= ICE_LAGS_M; + ice_lag_aa_failover(lag, ICE_LAGS_IDX, event_pf); + } + } + } else { + /* Port is going down */ + if (prim_port == event_port) { + lag->port_bitmap &= ~ICE_LAGP_M; + ice_lag_aa_failover(lag, ICE_LAGS_IDX, event_pf); + } else { + lag->port_bitmap &= ~ICE_LAGS_M; + ice_lag_aa_failover(lag, ICE_LAGP_IDX, event_pf); + } + } +} + +/** + * ice_lag_monitor_info - Calls relevant A/A or A/B monitoring function + * @lag: lag info struct + * @ptr: opaque data containing notifier event + * + * This function is for the primary PF to monitor changes in which port is + * active and handle changes for SRIOV VF functionality + */ +static void ice_lag_monitor_info(struct ice_lag *lag, void *ptr) +{ + struct netdev_notifier_bonding_info *info = ptr; + struct net_device *event_netdev, *event_upper; + struct netdev_bonding_info *bonding_info; + + if (!lag->primary) + return; + + event_netdev = netdev_notifier_info_to_dev(ptr); + bonding_info = &info->bonding_info; + rcu_read_lock(); + event_upper = netdev_master_upper_dev_get_rcu(event_netdev); + rcu_read_unlock(); + if (!netif_is_ice(event_netdev) || event_upper != lag->upper_netdev) + return; + + if (lag->bond_aa) + ice_lag_monitor_act_act(lag, bonding_info, event_netdev); + else + ice_lag_monitor_act_bkup(lag, bonding_info, event_netdev); +} /** * ice_lag_chk_comp - evaluate bonded interface for feature support * @lag: lag info struct @@ -1516,6 +2048,14 @@ ice_lag_chk_comp(struct ice_lag *lag, void *ptr) struct device *dev; int count = 0; + /* All members need to know if bond A/A or A/B */ + bonding_info = &info->bonding_info; + lag->bond_mode = bonding_info->master.bond_mode; + if (lag->bond_mode != BOND_MODE_ACTIVEBACKUP) + lag->bond_aa = true; + else + lag->bond_aa = false; + if (!lag->primary) return true; @@ -1536,12 +2076,9 @@ ice_lag_chk_comp(struct ice_lag *lag, void *ptr) return false; } - bonding_info = &info->bonding_info; - lag->bond_mode = bonding_info->master.bond_mode; - if (lag->bond_mode != BOND_MODE_ACTIVEBACKUP) { - dev_info(dev, "Bond Mode not ACTIVE-BACKUP - VF LAG disabled\n"); + if (lag->bond_aa && !ice_is_feature_supported(lag->pf, + ICE_F_SRIOV_AA_LAG)) return false; - } list_for_each(tmp, lag->netdev_head) { struct ice_dcbx_cfg *dcb_cfg, *peer_dcb_cfg; @@ -1699,6 +2236,26 @@ static void ice_lag_disable_sriov_bond(struct ice_lag *lag) struct ice_pf *pf = np->vsi->back; ice_clear_feature_support(pf, ICE_F_SRIOV_LAG); + ice_clear_feature_support(pf, ICE_F_SRIOV_AA_LAG); +} + +/** + * ice_lag_preset_drop_fltr - preset drop filter for A/B bonds + * @lag: local lag struct + * @ptr: opaque data containing event + * + * Sets the initial drop filter for secondary interface in an + * active-backup bond + */ +static void ice_lag_preset_drop_fltr(struct ice_lag *lag, void *ptr) +{ + struct net_device *netdev = netdev_notifier_info_to_dev(ptr); + + if (netdev != lag->netdev || lag->primary || !lag->need_fltr_cfg) + return; + + ice_lag_cfg_drop_fltr(lag, true); + lag->need_fltr_cfg = false; } /** @@ -1739,10 +2296,12 @@ static void ice_lag_process_event(struct work_struct *work) ice_lag_unregister(lag_work->lag, netdev); goto lag_cleanup; } - ice_lag_monitor_active(lag_work->lag, - &lag_work->info.bonding_info); ice_lag_cfg_pf_fltrs(lag_work->lag, &lag_work->info.bonding_info); + ice_lag_preset_drop_fltr(lag_work->lag, + &lag_work->info.bonding_info); + ice_lag_monitor_info(lag_work->lag, + &lag_work->info.bonding_info); } ice_lag_info_event(lag_work->lag, &lag_work->info.bonding_info); break; @@ -1993,7 +2552,8 @@ ice_lag_move_vf_nodes_tc_sync(struct ice_lag *lag, struct ice_hw *dest_hw, } if (ice_aq_cfg_lan_txq(hw, qbuf, qbuf_size, numq, hw->port_info->lport, - dest_hw->port_info->lport, NULL)) { + dest_hw->port_info->lport, + ICE_AQC_Q_CFG_TC_CHNG, NULL)) { dev_warn(dev, "Failure to configure queues for LAG reset rebuild\n"); goto sync_qerr; } @@ -2089,9 +2649,13 @@ int ice_init_lag(struct ice_pf *pf) lag->netdev = vsi->netdev; lag->role = ICE_LAG_NONE; lag->active_port = ICE_LAG_INVALID_PORT; + lag->port_bitmap = 0x0; lag->bonded = false; + lag->bond_aa = false; + lag->need_fltr_cfg = false; lag->upper_netdev = NULL; lag->notif_block.notifier_call = NULL; + memset(lag->sec_vf, 0, sizeof(lag->sec_vf)); err = ice_register_lag_handler(lag); if (err) { @@ -2109,6 +2673,11 @@ int ice_init_lag(struct ice_pf *pf) if (err) goto free_rcp_res; + err = ice_create_lag_recipe(&pf->hw, &lag->act_act_recipe, + ice_lport_rcp, 1); + if (err) + goto free_lport_res; + /* associate recipes to profiles */ for (n = 0; n < ICE_PROFID_IPV6_GTPU_IPV6_TCP_INNER; n++) { err = ice_aq_get_recipe_to_profile(&pf->hw, n, @@ -2118,7 +2687,8 @@ int ice_init_lag(struct ice_pf *pf) if (recipe_bits & BIT(ICE_SW_LKUP_DFLT)) { recipe_bits |= BIT(lag->pf_recipe) | - BIT(lag->lport_recipe); + BIT(lag->lport_recipe) | + BIT(lag->act_act_recipe); ice_aq_map_recipe_to_profile(&pf->hw, n, recipe_bits, NULL); } @@ -2129,9 +2699,13 @@ int ice_init_lag(struct ice_pf *pf) dev_dbg(dev, "INIT LAG complete\n"); return 0; +free_lport_res: + ice_free_hw_res(&pf->hw, ICE_AQC_RES_TYPE_RECIPE, 1, + &lag->lport_recipe); + free_rcp_res: ice_free_hw_res(&pf->hw, ICE_AQC_RES_TYPE_RECIPE, 1, - &pf->lag->pf_recipe); + &lag->pf_recipe); lag_error: kfree(lag); pf->lag = NULL; @@ -2216,11 +2790,15 @@ void ice_lag_rebuild(struct ice_pf *pf) ice_lag_move_vf_nodes_sync(prim_lag, &pf->hw); } - ice_lag_cfg_cp_fltr(lag, true); + if (!lag->bond_aa) { + ice_lag_cfg_lp_fltr(lag, true, true); + if (lag->pf_rx_rule_id) + if (ice_lag_cfg_dflt_fltr(lag, true)) + dev_err(ice_pf_to_dev(pf), "Error adding default VSI rule in rebuild\n"); + } else { + ice_lag_cfg_lp_fltr(lag, true, false); + } - if (lag->pf_rx_rule_id) - if (ice_lag_cfg_dflt_fltr(lag, true)) - dev_err(ice_pf_to_dev(pf), "Error adding default VSI rule in rebuild\n"); ice_clear_rdma_cap(pf); lag_rebuild_out: diff --git a/drivers/net/ethernet/intel/ice/ice_lag.h b/drivers/net/ethernet/intel/ice/ice_lag.h index 69347d9f986b..e2a0a782bdd7 100644 --- a/drivers/net/ethernet/intel/ice/ice_lag.h +++ b/drivers/net/ethernet/intel/ice/ice_lag.h @@ -14,7 +14,11 @@ enum ice_lag_role { ICE_LAG_UNSET }; -#define ICE_LAG_INVALID_PORT 0xFF +#define ICE_LAG_INVALID_PORT 0xFF +#define ICE_LAGP_IDX 0 +#define ICE_LAGS_IDX 1 +#define ICE_LAGP_M 0x1 +#define ICE_LAGS_M 0x2 #define ICE_LAG_RESET_RETRIES 5 #define ICE_SW_DEFAULT_PROFILE 0 @@ -41,12 +45,26 @@ struct ice_lag { u8 active_port; /* lport value for the current active port */ u8 bonded:1; /* currently bonded */ u8 primary:1; /* this is primary */ + u8 bond_aa:1; /* is this bond active-active */ + u8 need_fltr_cfg:1; /* fltrs for A/A bond still need to be make */ + u8 port_bitmap:2; /* bitmap of active ports */ + u8 bond_lport_pri; /* lport values for primary PF */ + u8 bond_lport_sec; /* lport values for secondary PF */ + + /* q_home keeps track of which interface the q is currently on */ + u8 q_home[ICE_MAX_SRIOV_VFS][ICE_MAX_RSS_QS_PER_VF]; + + /* placeholder VSI for hanging VF queues from on secondary interface */ + struct ice_vsi *sec_vf[ICE_MAX_SRIOV_VFS]; + u16 pf_recipe; u16 lport_recipe; + u16 act_act_recipe; u16 pf_rx_rule_id; u16 pf_tx_rule_id; u16 cp_rule_idx; u16 lport_rule_idx; + u16 act_act_rule_idx; u8 role; }; @@ -65,6 +83,7 @@ struct ice_lag_work { }; void ice_lag_move_new_vf_nodes(struct ice_vf *vf); +void ice_lag_aa_failover(struct ice_lag *lag, u8 dest, struct ice_pf *e_pf); int ice_init_lag(struct ice_pf *pf); void ice_deinit_lag(struct ice_pf *pf); void ice_lag_rebuild(struct ice_pf *pf); diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index 2b07d5e48847..8d19efc1df72 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -296,6 +296,7 @@ struct ice_hw_common_caps { bool roce_lag; bool sriov_lag; + bool sriov_aa_lag; bool nvm_update_pending_nvm; bool nvm_update_pending_orom; diff --git a/include/linux/net/intel/libie/adminq.h b/include/linux/net/intel/libie/adminq.h index dbe93f940ef0..ba62f703df43 100644 --- a/include/linux/net/intel/libie/adminq.h +++ b/include/linux/net/intel/libie/adminq.h @@ -194,6 +194,7 @@ LIBIE_CHECK_STRUCT_LEN(16, libie_aqc_list_caps); #define LIBIE_AQC_CAPS_FW_LAG_SUPPORT 0x0092 #define LIBIE_AQC_BIT_ROCEV2_LAG BIT(0) #define LIBIE_AQC_BIT_SRIOV_LAG BIT(1) +#define LIBIE_AQC_BIT_SRIOV_AA_LAG BIT(2) #define LIBIE_AQC_CAPS_FLEX10 0x00F1 #define LIBIE_AQC_CAPS_CEM 0x00F2 From 355b82c54c122e59487c52c084a146101bedc2c8 Mon Sep 17 00:00:00 2001 From: Jijie Shao Date: Wed, 13 Aug 2025 20:45:42 +0800 Subject: [PATCH 00872/11391] net: phy: motorcomm: Add support for PHY LEDs on YT8521 Add minimal LED controller driver supporting the most common uses with the 'netdev' trigger. Signed-off-by: Jijie Shao Tested-by: Heiko Stuebner Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20250813124542.3450447-1-shaojijie@huawei.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/motorcomm.c | 117 ++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c index 0e91f5d1a4fd..a3593e663059 100644 --- a/drivers/net/phy/motorcomm.c +++ b/drivers/net/phy/motorcomm.c @@ -213,6 +213,20 @@ #define YT8521_RC1R_RGMII_2_100_NS 14 #define YT8521_RC1R_RGMII_2_250_NS 15 +/* LED CONFIG */ +#define YT8521_MAX_LEDS 3 +#define YT8521_LED0_CFG_REG 0xA00C +#define YT8521_LED1_CFG_REG 0xA00D +#define YT8521_LED2_CFG_REG 0xA00E +#define YT8521_LED_ACT_BLK_IND BIT(13) +#define YT8521_LED_FDX_ON_EN BIT(12) +#define YT8521_LED_HDX_ON_EN BIT(11) +#define YT8521_LED_TXACT_BLK_EN BIT(10) +#define YT8521_LED_RXACT_BLK_EN BIT(9) +#define YT8521_LED_1000_ON_EN BIT(6) +#define YT8521_LED_100_ON_EN BIT(5) +#define YT8521_LED_10_ON_EN BIT(4) + #define YTPHY_MISC_CONFIG_REG 0xA006 #define YTPHY_MCR_FIBER_SPEED_MASK BIT(0) #define YTPHY_MCR_FIBER_1000BX (0x1 << 0) @@ -1681,6 +1695,106 @@ static int yt8521_config_init(struct phy_device *phydev) return phy_restore_page(phydev, old_page, ret); } +static const unsigned long supported_trgs = (BIT(TRIGGER_NETDEV_FULL_DUPLEX) | + BIT(TRIGGER_NETDEV_HALF_DUPLEX) | + BIT(TRIGGER_NETDEV_LINK) | + BIT(TRIGGER_NETDEV_LINK_10) | + BIT(TRIGGER_NETDEV_LINK_100) | + BIT(TRIGGER_NETDEV_LINK_1000) | + BIT(TRIGGER_NETDEV_RX) | + BIT(TRIGGER_NETDEV_TX)); + +static int yt8521_led_hw_is_supported(struct phy_device *phydev, u8 index, + unsigned long rules) +{ + if (index >= YT8521_MAX_LEDS) + return -EINVAL; + + /* All combinations of the supported triggers are allowed */ + if (rules & ~supported_trgs) + return -EOPNOTSUPP; + + return 0; +} + +static int yt8521_led_hw_control_set(struct phy_device *phydev, u8 index, + unsigned long rules) +{ + u16 val = 0; + + if (index >= YT8521_MAX_LEDS) + return -EINVAL; + + if (test_bit(TRIGGER_NETDEV_LINK, &rules)) { + val |= YT8521_LED_10_ON_EN; + val |= YT8521_LED_100_ON_EN; + val |= YT8521_LED_1000_ON_EN; + } + + if (test_bit(TRIGGER_NETDEV_LINK_10, &rules)) + val |= YT8521_LED_10_ON_EN; + + if (test_bit(TRIGGER_NETDEV_LINK_100, &rules)) + val |= YT8521_LED_100_ON_EN; + + if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) + val |= YT8521_LED_1000_ON_EN; + + if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &rules)) + val |= YT8521_LED_HDX_ON_EN; + + if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &rules)) + val |= YT8521_LED_FDX_ON_EN; + + if (test_bit(TRIGGER_NETDEV_TX, &rules) || + test_bit(TRIGGER_NETDEV_RX, &rules)) + val |= YT8521_LED_ACT_BLK_IND; + + if (test_bit(TRIGGER_NETDEV_TX, &rules)) + val |= YT8521_LED_TXACT_BLK_EN; + + if (test_bit(TRIGGER_NETDEV_RX, &rules)) + val |= YT8521_LED_RXACT_BLK_EN; + + return ytphy_write_ext(phydev, YT8521_LED0_CFG_REG + index, val); +} + +static int yt8521_led_hw_control_get(struct phy_device *phydev, u8 index, + unsigned long *rules) +{ + int val; + + if (index >= YT8521_MAX_LEDS) + return -EINVAL; + + val = ytphy_read_ext(phydev, YT8521_LED0_CFG_REG + index); + if (val < 0) + return val; + + if (val & YT8521_LED_TXACT_BLK_EN || val & YT8521_LED_ACT_BLK_IND) + __set_bit(TRIGGER_NETDEV_TX, rules); + + if (val & YT8521_LED_RXACT_BLK_EN || val & YT8521_LED_ACT_BLK_IND) + __set_bit(TRIGGER_NETDEV_RX, rules); + + if (val & YT8521_LED_FDX_ON_EN) + __set_bit(TRIGGER_NETDEV_FULL_DUPLEX, rules); + + if (val & YT8521_LED_HDX_ON_EN) + __set_bit(TRIGGER_NETDEV_HALF_DUPLEX, rules); + + if (val & YT8521_LED_1000_ON_EN) + __set_bit(TRIGGER_NETDEV_LINK_1000, rules); + + if (val & YT8521_LED_100_ON_EN) + __set_bit(TRIGGER_NETDEV_LINK_100, rules); + + if (val & YT8521_LED_10_ON_EN) + __set_bit(TRIGGER_NETDEV_LINK_10, rules); + + return 0; +} + static int yt8531_config_init(struct phy_device *phydev) { struct device_node *node = phydev->mdio.dev.of_node; @@ -2920,6 +3034,9 @@ static struct phy_driver motorcomm_phy_drvs[] = { .soft_reset = yt8521_soft_reset, .suspend = yt8521_suspend, .resume = yt8521_resume, + .led_hw_is_supported = yt8521_led_hw_is_supported, + .led_hw_control_set = yt8521_led_hw_control_set, + .led_hw_control_get = yt8521_led_hw_control_get, }, { PHY_ID_MATCH_EXACT(PHY_ID_YT8531), From 34167f1a024d2c5abae0b0325a6d0b8257160f86 Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Wed, 13 Aug 2025 01:44:07 -0400 Subject: [PATCH 00873/11391] net: phy: realtek: convert RTL8226-CG to c45 only Short: Convert the RTL8226-CG to c45 so it can be used in its Realtek based ecosystems. Long: The RTL8226-CG can be mainly found on devices of the Realtek Otto switch platform. Devices like the Zyxel XGS1210-12 are based on it. These implement a hardware based phy polling in the background to update SoC status registers. The hardware provides 4 smi busses where phys are attached to. For each bus one can decide if it is polled in c45 or c22 mode. See https://svanheule.net/realtek/longan/register/smi_glb_ctrl With this setting the register access will be limited by the hardware. This is very complex (including caching and special c45-over-c22 handling). But basically it boils down to "enable protocol x and SoC will disable register access via protocol y". Mainline already gained support for the rtl9300 mdio driver in commit 24e31e474769 ("net: mdio: Add RTL9300 MDIO driver"). It covers the basic features, but a lot effort is still needed to understand hardware properly. So it runs a simple setup by selecting the proper bus mode during startup. /* Put the interfaces into C45 mode if required */ glb_ctrl_mask = GENMASK(19, 16); for (i = 0; i < MAX_SMI_BUSSES; i++) if (priv->smi_bus_is_c45[i]) glb_ctrl_val |= GLB_CTRL_INTF_SEL(i); ... err = regmap_update_bits(regmap, SMI_GLB_CTRL, glb_ctrl_mask, glb_ctrl_val); To avoid complex coding later on, it limits access by only providing either c22 or c45: bus->name = "Realtek Switch MDIO Bus"; if (priv->smi_bus_is_c45[mdio_bus]) { bus->read_c45 = rtl9300_mdio_read_c45; bus->write_c45 = rtl9300_mdio_write_c45; } else { bus->read = rtl9300_mdio_read_c22; bus->write = rtl9300_mdio_write_c22; } Because of these limitations the existing RTL8226 phy driver is not working at all on Realtek switches. Convert the driver to c45-only. Luckily the RTL8226 seems to support proper MDIO_PMA_EXTABLE flags. So standard function genphy_c45_pma_read_abilities() can call genphy_c45_pma_read_ext_abilities() and 10/100/1000 is populated right. Thus conversion is straight forward. Outputs before - REMARK: For this a "hacked" bus was used that toggles the mode for each c22/c45 access. But that is slow and produces unstable data in the SoC status registers). Settings for lan9: Supported ports: [ TP MII ] Supported link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Full 2500baseT/Full Supported pause frame use: Symmetric Receive-only Supports auto-negotiation: Yes Supported FEC modes: Not reported Advertised link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Full 2500baseT/Full Advertised pause frame use: Symmetric Receive-only Advertised auto-negotiation: Yes Advertised FEC modes: Not reported Speed: Unknown! Duplex: Unknown! (255) Port: Twisted Pair PHYAD: 24 Transceiver: external Auto-negotiation: on MDI-X: Unknown Supports Wake-on: d Wake-on: d Link detected: no Outputs with this commit: Settings for lan9: Supported ports: [ TP ] Supported link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Full 2500baseT/Full Supported pause frame use: Symmetric Receive-only Supports auto-negotiation: Yes Supported FEC modes: Not reported Advertised link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Full 2500baseT/Full Advertised pause frame use: Symmetric Receive-only Advertised auto-negotiation: Yes Advertised FEC modes: Not reported Speed: Unknown! Duplex: Unknown! (255) Port: Twisted Pair PHYAD: 24 Transceiver: external Auto-negotiation: on MDI-X: Unknown Supports Wake-on: d Wake-on: d Link detected: no Signed-off-by: Markus Stockhausen Link: https://patch.msgid.link/20250813054407.1108285-1-markus.stockhausen@gmx.de Signed-off-by: Jakub Kicinski --- drivers/net/phy/realtek/realtek_main.c | 28 +++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index dd0d675149ad..a7541899e327 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -1280,6 +1280,21 @@ static int rtl822x_c45_read_status(struct phy_device *phydev) return 0; } +static int rtl822x_c45_soft_reset(struct phy_device *phydev) +{ + int ret, val; + + ret = phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1, + MDIO_CTRL1_RESET, MDIO_CTRL1_RESET); + if (ret < 0) + return ret; + + return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_PMAPMD, + MDIO_CTRL1, val, + !(val & MDIO_CTRL1_RESET), + 5000, 100000, true); +} + static int rtl822xb_c45_read_status(struct phy_device *phydev) { int ret; @@ -1675,13 +1690,12 @@ static struct phy_driver realtek_drvs[] = { }, { PHY_ID_MATCH_EXACT(0x001cc838), .name = "RTL8226-CG 2.5Gbps PHY", - .get_features = rtl822x_get_features, - .config_aneg = rtl822x_config_aneg, - .read_status = rtl822x_read_status, - .suspend = genphy_suspend, - .resume = rtlgen_resume, - .read_page = rtl821x_read_page, - .write_page = rtl821x_write_page, + .soft_reset = rtl822x_c45_soft_reset, + .get_features = rtl822x_c45_get_features, + .config_aneg = rtl822x_c45_config_aneg, + .read_status = rtl822x_c45_read_status, + .suspend = genphy_c45_pma_suspend, + .resume = rtlgen_c45_resume, }, { PHY_ID_MATCH_EXACT(0x001cc848), .name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY", From c6f68f69416d0950965e5744489382ccebdc72b4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 13 Aug 2025 08:51:22 +0300 Subject: [PATCH 00874/11391] nfc: pn533: Delete an unnecessary check The "rc" variable is set like this: if (IS_ERR(resp)) { rc = PTR_ERR(resp); We know that "rc" is negative so there is no need to check. Signed-off-by: Dan Carpenter Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/aJwn2ox5g9WsD2Vx@stanley.mountain Signed-off-by: Jakub Kicinski --- drivers/nfc/pn533/pn533.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/nfc/pn533/pn533.c b/drivers/nfc/pn533/pn533.c index 14661249c690..2b043a9f9533 100644 --- a/drivers/nfc/pn533/pn533.c +++ b/drivers/nfc/pn533/pn533.c @@ -1412,11 +1412,9 @@ static int pn533_autopoll_complete(struct pn533 *dev, void *arg, if (dev->poll_mod_count != 0) return rc; goto stop_poll; - } else if (rc < 0) { - nfc_err(dev->dev, - "Error %d when running autopoll\n", rc); - goto stop_poll; } + nfc_err(dev->dev, "Error %d when running autopoll\n", rc); + goto stop_poll; } nbtg = resp->data[0]; @@ -1505,11 +1503,9 @@ static int pn533_poll_complete(struct pn533 *dev, void *arg, if (dev->poll_mod_count != 0) return rc; goto stop_poll; - } else if (rc < 0) { - nfc_err(dev->dev, - "Error %d when running poll\n", rc); - goto stop_poll; } + nfc_err(dev->dev, "Error %d when running poll\n", rc); + goto stop_poll; } cur_mod = dev->poll_mod_active[dev->poll_mod_curr]; From 0ebc0bcd0aa0037019aac996c50166c7baf44ff8 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Wed, 13 Aug 2025 12:44:16 +0300 Subject: [PATCH 00875/11391] devlink/port: Simplify return checks Drop always returning 0 from the helper routine and simplify its callers. Reviewed-by: Jiri Pirko Signed-off-by: Parav Pandit Link: https://patch.msgid.link/20250813094417.7269-2-parav@nvidia.com Signed-off-by: Jakub Kicinski --- net/devlink/port.c | 29 ++++++----------------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/net/devlink/port.c b/net/devlink/port.c index cb8d4df61619..aaca1b23aa5f 100644 --- a/net/devlink/port.c +++ b/net/devlink/port.c @@ -1333,8 +1333,8 @@ int devlink_port_netdevice_event(struct notifier_block *nb, return NOTIFY_OK; } -static int __devlink_port_attrs_set(struct devlink_port *devlink_port, - enum devlink_port_flavour flavour) +static void __devlink_port_attrs_set(struct devlink_port *devlink_port, + enum devlink_port_flavour flavour) { struct devlink_port_attrs *attrs = &devlink_port->attrs; @@ -1347,7 +1347,6 @@ static int __devlink_port_attrs_set(struct devlink_port *devlink_port, } else { devlink_port->switch_port = false; } - return 0; } /** @@ -1359,14 +1358,10 @@ static int __devlink_port_attrs_set(struct devlink_port *devlink_port, void devlink_port_attrs_set(struct devlink_port *devlink_port, struct devlink_port_attrs *attrs) { - int ret; - ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port); devlink_port->attrs = *attrs; - ret = __devlink_port_attrs_set(devlink_port, attrs->flavour); - if (ret) - return; + __devlink_port_attrs_set(devlink_port, attrs->flavour); WARN_ON(attrs->splittable && attrs->split); } EXPORT_SYMBOL_GPL(devlink_port_attrs_set); @@ -1383,14 +1378,10 @@ void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port, u32 contro u16 pf, bool external) { struct devlink_port_attrs *attrs = &devlink_port->attrs; - int ret; ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port); - ret = __devlink_port_attrs_set(devlink_port, - DEVLINK_PORT_FLAVOUR_PCI_PF); - if (ret) - return; + __devlink_port_attrs_set(devlink_port, DEVLINK_PORT_FLAVOUR_PCI_PF); attrs->pci_pf.controller = controller; attrs->pci_pf.pf = pf; attrs->pci_pf.external = external; @@ -1411,14 +1402,10 @@ void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port, u32 contro u16 pf, u16 vf, bool external) { struct devlink_port_attrs *attrs = &devlink_port->attrs; - int ret; ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port); - ret = __devlink_port_attrs_set(devlink_port, - DEVLINK_PORT_FLAVOUR_PCI_VF); - if (ret) - return; + __devlink_port_attrs_set(devlink_port, DEVLINK_PORT_FLAVOUR_PCI_VF); attrs->pci_vf.controller = controller; attrs->pci_vf.pf = pf; attrs->pci_vf.vf = vf; @@ -1439,14 +1426,10 @@ void devlink_port_attrs_pci_sf_set(struct devlink_port *devlink_port, u32 contro u16 pf, u32 sf, bool external) { struct devlink_port_attrs *attrs = &devlink_port->attrs; - int ret; ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port); - ret = __devlink_port_attrs_set(devlink_port, - DEVLINK_PORT_FLAVOUR_PCI_SF); - if (ret) - return; + __devlink_port_attrs_set(devlink_port, DEVLINK_PORT_FLAVOUR_PCI_SF); attrs->pci_sf.controller = controller; attrs->pci_sf.pf = pf; attrs->pci_sf.sf = sf; From 41a6e8ab18642741437da932c2f5762b185e928c Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Wed, 13 Aug 2025 12:44:17 +0300 Subject: [PATCH 00876/11391] devlink/port: Check attributes early and constify Constify the devlink port attributes to indicate they are read only and does not depend on anything else. Therefore, validate it early before setting in the devlink port. Reviewed-by: Jiri Pirko Signed-off-by: Parav Pandit Link: https://patch.msgid.link/20250813094417.7269-3-parav@nvidia.com Signed-off-by: Jakub Kicinski --- include/net/devlink.h | 2 +- net/devlink/port.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/net/devlink.h b/include/net/devlink.h index b32c9ceeb81d..3119d053bc4d 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -1743,7 +1743,7 @@ void devlink_port_type_ib_set(struct devlink_port *devlink_port, struct ib_device *ibdev); void devlink_port_type_clear(struct devlink_port *devlink_port); void devlink_port_attrs_set(struct devlink_port *devlink_port, - struct devlink_port_attrs *devlink_port_attrs); + const struct devlink_port_attrs *attrs); void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port, u32 controller, u16 pf, bool external); void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port, u32 controller, diff --git a/net/devlink/port.c b/net/devlink/port.c index aaca1b23aa5f..93d8a25bb920 100644 --- a/net/devlink/port.c +++ b/net/devlink/port.c @@ -1356,13 +1356,13 @@ static void __devlink_port_attrs_set(struct devlink_port *devlink_port, * @attrs: devlink port attrs */ void devlink_port_attrs_set(struct devlink_port *devlink_port, - struct devlink_port_attrs *attrs) + const struct devlink_port_attrs *attrs) { ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port); + WARN_ON(attrs->splittable && attrs->split); devlink_port->attrs = *attrs; __devlink_port_attrs_set(devlink_port, attrs->flavour); - WARN_ON(attrs->splittable && attrs->split); } EXPORT_SYMBOL_GPL(devlink_port_attrs_set); From 4b6dc4c891cc270699c3214557621df7df7c05cc Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Wed, 13 Aug 2025 17:50:24 +0800 Subject: [PATCH 00877/11391] ptp: ptp_clockmatrix: Remove redundant semicolons Remove unnecessary semicolons. Signed-off-by: Liao Yuanhong Link: https://patch.msgid.link/20250813095024.559085-1-liaoyuanhong@vivo.com Signed-off-by: Jakub Kicinski --- drivers/ptp/ptp_clockmatrix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ptp/ptp_clockmatrix.c b/drivers/ptp/ptp_clockmatrix.c index b8d4df8c6da2..59cd6bbb33f3 100644 --- a/drivers/ptp/ptp_clockmatrix.c +++ b/drivers/ptp/ptp_clockmatrix.c @@ -1161,7 +1161,7 @@ static int set_pll_output_mask(struct idtcm *idtcm, u16 addr, u8 val) SET_U16_MSB(idtcm->channel[3].output_mask, val); break; default: - err = -EFAULT; /* Bad address */; + err = -EFAULT; /* Bad address */ break; } From eeea7688632e0c697f66bdd71708c8faf36f6540 Mon Sep 17 00:00:00 2001 From: Yue Haibing Date: Wed, 13 Aug 2025 20:55:26 +0800 Subject: [PATCH 00878/11391] net/sched: Use TC_RTAB_SIZE instead of magic number Replace magic number with TC_RTAB_SIZE to make it more informative. Signed-off-by: Yue Haibing Link: https://patch.msgid.link/20250813125526.853895-1-yuehaibing@huawei.com Signed-off-by: Jakub Kicinski --- net/sched/sch_api.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index d7c767b861a4..1e058b46d3e1 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -431,7 +431,7 @@ struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, for (rtab = qdisc_rtab_list; rtab; rtab = rtab->next) { if (!memcmp(&rtab->rate, r, sizeof(struct tc_ratespec)) && - !memcmp(&rtab->data, nla_data(tab), 1024)) { + !memcmp(&rtab->data, nla_data(tab), TC_RTAB_SIZE)) { rtab->refcnt++; return rtab; } @@ -441,7 +441,7 @@ struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, if (rtab) { rtab->rate = *r; rtab->refcnt = 1; - memcpy(rtab->data, nla_data(tab), 1024); + memcpy(rtab->data, nla_data(tab), TC_RTAB_SIZE); if (r->linklayer == TC_LINKLAYER_UNAWARE) r->linklayer = __detect_linklayer(r, rtab->data); rtab->next = qdisc_rtab_list; From 20e1b75b38fd51ad7fb215943cd80fd78d1e767b Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 13 Aug 2025 21:10:23 +0300 Subject: [PATCH 00879/11391] net: dsa: realtek: remove unnecessary file, dentry, inode declarations These are present since commit d8652956cf37 ("net: dsa: realtek-smi: Add Realtek SMI driver") and never needed. Apparently the driver was not cleaned up sufficiently for submission. Signed-off-by: Vladimir Oltean Reviewed-by: Linus Walleij Link: https://patch.msgid.link/20250813181023.808528-1-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/realtek/realtek.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/dsa/realtek/realtek.h b/drivers/net/dsa/realtek/realtek.h index a1b2e0b529d5..c03485a80d93 100644 --- a/drivers/net/dsa/realtek/realtek.h +++ b/drivers/net/dsa/realtek/realtek.h @@ -19,9 +19,6 @@ struct phylink_mac_ops; struct realtek_ops; -struct dentry; -struct inode; -struct file; struct rtl8366_mib_counter { unsigned int base; From df979273bd716a93ca9ffa8f84aeb205c9bf2ab6 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 13 Aug 2025 10:44:54 +0300 Subject: [PATCH 00880/11391] net: phy: mscc: report and configure in-band auto-negotiation for SGMII/QSGMII The following Vitesse/Microsemi/Microchip PHYs, among those supported by this driver, have the host interface configurable as SGMII or QSGMII: - VSC8504 - VSC8514 - VSC8552 - VSC8562 - VSC8572 - VSC8574 - VSC8575 - VSC8582 - VSC8584 All these PHYs are documented to have bit 7 of "MAC SerDes PCS Control" as "MAC SerDes ANEG enable". Out of these, I could test the VSC8514 quad PHY in QSGMII. This works both with the in-band autoneg on and off, on the NXP LS1028A-RDB and T1040-RDB boards. Notably, the bit is sticky (survives soft resets), so giving Linux the tools to read and modify this settings makes it robust to changes made to it by previous boot layers (U-Boot). Signed-off-by: Vladimir Oltean Reviewed-by: Russell King (Oracle) Link: https://patch.msgid.link/20250813074454.63224-1-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/mscc/mscc.h | 3 +++ drivers/net/phy/mscc/mscc_main.c | 40 ++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/drivers/net/phy/mscc/mscc.h b/drivers/net/phy/mscc/mscc.h index 6a3d8a754eb8..138355f1ab0b 100644 --- a/drivers/net/phy/mscc/mscc.h +++ b/drivers/net/phy/mscc/mscc.h @@ -196,6 +196,9 @@ enum rgmii_clock_delay { #define MSCC_PHY_EXTENDED_INT_MS_EGR BIT(9) /* Extended Page 3 Registers */ +#define MSCC_PHY_SERDES_PCS_CTRL 16 +#define MSCC_PHY_SERDES_ANEG BIT(7) + #define MSCC_PHY_SERDES_TX_VALID_CNT 21 #define MSCC_PHY_SERDES_TX_CRC_ERR_CNT 22 #define MSCC_PHY_SERDES_RX_VALID_CNT 28 diff --git a/drivers/net/phy/mscc/mscc_main.c b/drivers/net/phy/mscc/mscc_main.c index 7ed6522fb0ef..3bcf48febb1f 100644 --- a/drivers/net/phy/mscc/mscc_main.c +++ b/drivers/net/phy/mscc/mscc_main.c @@ -2202,6 +2202,28 @@ static int vsc85xx_read_status(struct phy_device *phydev) return genphy_read_status(phydev); } +static unsigned int vsc85xx_inband_caps(struct phy_device *phydev, + phy_interface_t interface) +{ + if (interface != PHY_INTERFACE_MODE_SGMII && + interface != PHY_INTERFACE_MODE_QSGMII) + return 0; + + return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE; +} + +static int vsc85xx_config_inband(struct phy_device *phydev, unsigned int modes) +{ + u16 reg_val = 0; + + if (modes == LINK_INBAND_ENABLE) + reg_val = MSCC_PHY_SERDES_ANEG; + + return phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED_3, + MSCC_PHY_SERDES_PCS_CTRL, MSCC_PHY_SERDES_ANEG, + reg_val); +} + static int vsc8514_probe(struct phy_device *phydev) { struct vsc8531_private *vsc8531; @@ -2409,6 +2431,8 @@ static struct phy_driver vsc85xx_driver[] = { .get_sset_count = &vsc85xx_get_sset_count, .get_strings = &vsc85xx_get_strings, .get_stats = &vsc85xx_get_stats, + .inband_caps = vsc85xx_inband_caps, + .config_inband = vsc85xx_config_inband, }, { .phy_id = PHY_ID_VSC8514, @@ -2432,6 +2456,8 @@ static struct phy_driver vsc85xx_driver[] = { .get_sset_count = &vsc85xx_get_sset_count, .get_strings = &vsc85xx_get_strings, .get_stats = &vsc85xx_get_stats, + .inband_caps = vsc85xx_inband_caps, + .config_inband = vsc85xx_config_inband, }, { .phy_id = PHY_ID_VSC8530, @@ -2552,6 +2578,8 @@ static struct phy_driver vsc85xx_driver[] = { .get_sset_count = &vsc85xx_get_sset_count, .get_strings = &vsc85xx_get_strings, .get_stats = &vsc85xx_get_stats, + .inband_caps = vsc85xx_inband_caps, + .config_inband = vsc85xx_config_inband, }, { .phy_id = PHY_ID_VSC856X, @@ -2574,6 +2602,8 @@ static struct phy_driver vsc85xx_driver[] = { .get_sset_count = &vsc85xx_get_sset_count, .get_strings = &vsc85xx_get_strings, .get_stats = &vsc85xx_get_stats, + .inband_caps = vsc85xx_inband_caps, + .config_inband = vsc85xx_config_inband, }, { .phy_id = PHY_ID_VSC8572, @@ -2599,6 +2629,8 @@ static struct phy_driver vsc85xx_driver[] = { .get_sset_count = &vsc85xx_get_sset_count, .get_strings = &vsc85xx_get_strings, .get_stats = &vsc85xx_get_stats, + .inband_caps = vsc85xx_inband_caps, + .config_inband = vsc85xx_config_inband, }, { .phy_id = PHY_ID_VSC8574, @@ -2624,6 +2656,8 @@ static struct phy_driver vsc85xx_driver[] = { .get_sset_count = &vsc85xx_get_sset_count, .get_strings = &vsc85xx_get_strings, .get_stats = &vsc85xx_get_stats, + .inband_caps = vsc85xx_inband_caps, + .config_inband = vsc85xx_config_inband, }, { .phy_id = PHY_ID_VSC8575, @@ -2647,6 +2681,8 @@ static struct phy_driver vsc85xx_driver[] = { .get_sset_count = &vsc85xx_get_sset_count, .get_strings = &vsc85xx_get_strings, .get_stats = &vsc85xx_get_stats, + .inband_caps = vsc85xx_inband_caps, + .config_inband = vsc85xx_config_inband, }, { .phy_id = PHY_ID_VSC8582, @@ -2670,6 +2706,8 @@ static struct phy_driver vsc85xx_driver[] = { .get_sset_count = &vsc85xx_get_sset_count, .get_strings = &vsc85xx_get_strings, .get_stats = &vsc85xx_get_stats, + .inband_caps = vsc85xx_inband_caps, + .config_inband = vsc85xx_config_inband, }, { .phy_id = PHY_ID_VSC8584, @@ -2694,6 +2732,8 @@ static struct phy_driver vsc85xx_driver[] = { .get_strings = &vsc85xx_get_strings, .get_stats = &vsc85xx_get_stats, .link_change_notify = &vsc85xx_link_change_notify, + .inband_caps = vsc85xx_inband_caps, + .config_inband = vsc85xx_config_inband, } }; From f09fc24dd9a5ec989dfdde7090624924ede6ddc7 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 12 Aug 2025 07:20:54 -0700 Subject: [PATCH 00881/11391] selftests: drv-net: wait for carrier On fast machines the tests run in quick succession so even when tests clean up after themselves the carrier may need some time to come back. Specifically in NIPA when ping.py runs right after netpoll_basic.py the first ping command fails. Since the context manager callbacks are now common NetDrvEpEnv gets an ip link up call as well. Reviewed-by: Joe Damato Link: https://patch.msgid.link/20250812142054.750282-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- .../selftests/drivers/net/lib/py/__init__.py | 2 +- .../selftests/drivers/net/lib/py/env.py | 41 +++++++++---------- tools/testing/selftests/net/lib/py/utils.py | 18 ++++++++ 3 files changed, 39 insertions(+), 22 deletions(-) diff --git a/tools/testing/selftests/drivers/net/lib/py/__init__.py b/tools/testing/selftests/drivers/net/lib/py/__init__.py index 8711c67ad658..a07b56a75c8a 100644 --- a/tools/testing/selftests/drivers/net/lib/py/__init__.py +++ b/tools/testing/selftests/drivers/net/lib/py/__init__.py @@ -15,7 +15,7 @@ try: NlError, RtnlFamily, DevlinkFamily from net.lib.py import CmdExitFailure from net.lib.py import bkg, cmd, bpftool, bpftrace, defer, ethtool, \ - fd_read_timeout, ip, rand_port, tool, wait_port_listen + fd_read_timeout, ip, rand_port, tool, wait_port_listen, wait_file from net.lib.py import fd_read_timeout from net.lib.py import KsftSkipEx, KsftFailEx, KsftXfailEx from net.lib.py import ksft_disruptive, ksft_exit, ksft_pr, ksft_run, \ diff --git a/tools/testing/selftests/drivers/net/lib/py/env.py b/tools/testing/selftests/drivers/net/lib/py/env.py index 1b8bd648048f..c1f3b608c6d8 100644 --- a/tools/testing/selftests/drivers/net/lib/py/env.py +++ b/tools/testing/selftests/drivers/net/lib/py/env.py @@ -4,7 +4,7 @@ import os import time from pathlib import Path from lib.py import KsftSkipEx, KsftXfailEx -from lib.py import ksft_setup +from lib.py import ksft_setup, wait_file from lib.py import cmd, ethtool, ip, CmdExitFailure from lib.py import NetNS, NetdevSimDev from .remote import Remote @@ -25,6 +25,9 @@ class NetDrvEnvBase: self.env = self._load_env_file() + # Following attrs must be set be inheriting classes + self.dev = None + def _load_env_file(self): env = os.environ.copy() @@ -48,6 +51,22 @@ class NetDrvEnvBase: env[pair[0]] = pair[1] return ksft_setup(env) + def __del__(self): + pass + + def __enter__(self): + ip(f"link set dev {self.dev['ifname']} up") + wait_file(f"/sys/class/net/{self.dev['ifname']}/carrier", + lambda x: x.strip() == "1") + + return self + + def __exit__(self, ex_type, ex_value, ex_tb): + """ + __exit__ gets called at the end of a "with" block. + """ + self.__del__() + class NetDrvEnv(NetDrvEnvBase): """ @@ -72,17 +91,6 @@ class NetDrvEnv(NetDrvEnvBase): self.ifname = self.dev['ifname'] self.ifindex = self.dev['ifindex'] - def __enter__(self): - ip(f"link set dev {self.dev['ifname']} up") - - return self - - def __exit__(self, ex_type, ex_value, ex_tb): - """ - __exit__ gets called at the end of a "with" block. - """ - self.__del__() - def __del__(self): if self._ns: self._ns.remove() @@ -219,15 +227,6 @@ class NetDrvEpEnv(NetDrvEnvBase): raise Exception("Can't resolve remote interface name, multiple interfaces match") return v6[0]["ifname"] if v6 else v4[0]["ifname"] - def __enter__(self): - return self - - def __exit__(self, ex_type, ex_value, ex_tb): - """ - __exit__ gets called at the end of a "with" block. - """ - self.__del__() - def __del__(self): if self._ns: self._ns.remove() diff --git a/tools/testing/selftests/net/lib/py/utils.py b/tools/testing/selftests/net/lib/py/utils.py index 4ac9249c85ab..b188cac49738 100644 --- a/tools/testing/selftests/net/lib/py/utils.py +++ b/tools/testing/selftests/net/lib/py/utils.py @@ -252,3 +252,21 @@ def wait_port_listen(port, proto="tcp", ns=None, host=None, sleep=0.005, deadlin if time.monotonic() > end: raise Exception("Waiting for port listen timed out") time.sleep(sleep) + + +def wait_file(fname, test_fn, sleep=0.005, deadline=5, encoding='utf-8'): + """ + Wait for file contents on the local system to satisfy a condition. + test_fn() should take one argument (file contents) and return whether + condition is met. + """ + end = time.monotonic() + deadline + + with open(fname, "r", encoding=encoding) as fp: + while True: + if test_fn(fp.read()): + break + fp.seek(0) + if time.monotonic() > end: + raise TimeoutError("Wait for file contents failed", fname) + time.sleep(sleep) From 3d05b24429e1de7a17c8fdccb04a04dbc8ad297b Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 12 Aug 2025 11:02:12 +0300 Subject: [PATCH 00882/11391] bridge: Redirect to backup port when port is administratively down If a backup port is configured for a bridge port, the bridge will redirect known unicast traffic towards the backup port when the primary port is administratively up but without a carrier. This is useful, for example, in MLAG configurations where a system is connected to two switches and there is a peer link between both switches. The peer link serves as the backup port in case one of the switches loses its connection to the multi-homed system. In order to avoid flooding when the primary port loses its carrier, the bridge does not flush dynamic FDB entries pointing to the port upon STP disablement, if the port has a backup port. The above means that known unicast traffic destined to the primary port will be blackholed when the port is put administratively down, until the FDB entries pointing to it are aged-out. Given that the current behavior is quite weird and unlikely to be depended on by anyone, amend the bridge to redirect to the backup port also when the primary port is administratively down and not only when it does not have a carrier. The change is motivated by a report from a user who expected traffic to be redirected to the backup port when the primary port was put administratively down while debugging a network issue. Reviewed-by: Petr Machata Signed-off-by: Ido Schimmel Acked-by: Nikolay Aleksandrov Link: https://patch.msgid.link/20250812080213.325298-2-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- net/bridge/br_forward.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index 29097e984b4f..870bdf2e082c 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c @@ -148,7 +148,8 @@ void br_forward(const struct net_bridge_port *to, goto out; /* redirect to backup link if the destination port is down */ - if (rcu_access_pointer(to->backup_port) && !netif_carrier_ok(to->dev)) { + if (rcu_access_pointer(to->backup_port) && + (!netif_carrier_ok(to->dev) || !netif_running(to->dev))) { struct net_bridge_port *backup_port; backup_port = rcu_dereference(to->backup_port); From 51ca1e67f416000bfd9a2a49c868538e744a317e Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 12 Aug 2025 11:02:13 +0300 Subject: [PATCH 00883/11391] selftests: net: Test bridge backup port when port is administratively down Test that packets are redirected to the backup port when the primary port is administratively down. With the previous patch: # ./test_bridge_backup_port.sh [...] TEST: swp1 administratively down [ OK ] TEST: No forwarding out of swp1 [ OK ] TEST: Forwarding out of vx0 [ OK ] TEST: swp1 administratively up [ OK ] TEST: Forwarding out of swp1 [ OK ] TEST: No forwarding out of vx0 [ OK ] [...] Tests passed: 89 Tests failed: 0 Without the previous patch: # ./test_bridge_backup_port.sh [...] TEST: swp1 administratively down [ OK ] TEST: No forwarding out of swp1 [ OK ] TEST: Forwarding out of vx0 [FAIL] TEST: swp1 administratively up [ OK ] TEST: Forwarding out of swp1 [ OK ] [...] Tests passed: 85 Tests failed: 4 Signed-off-by: Ido Schimmel Acked-by: Nikolay Aleksandrov Link: https://patch.msgid.link/20250812080213.325298-3-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- .../selftests/net/test_bridge_backup_port.sh | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/net/test_bridge_backup_port.sh b/tools/testing/selftests/net/test_bridge_backup_port.sh index 1b3f89e2b86e..2a7224fe74f2 100755 --- a/tools/testing/selftests/net/test_bridge_backup_port.sh +++ b/tools/testing/selftests/net/test_bridge_backup_port.sh @@ -315,6 +315,29 @@ backup_port() tc_check_packets $sw1 "dev vx0 egress" 101 1 log_test $? 0 "No forwarding out of vx0" + # Check that packets are forwarded out of vx0 when swp1 is + # administratively down and out of swp1 when it is administratively up + # again. + run_cmd "ip -n $sw1 link set dev swp1 down" + busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 disabled + log_test $? 0 "swp1 administratively down" + + run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" + tc_check_packets $sw1 "dev swp1 egress" 101 3 + log_test $? 0 "No forwarding out of swp1" + tc_check_packets $sw1 "dev vx0 egress" 101 2 + log_test $? 0 "Forwarding out of vx0" + + run_cmd "ip -n $sw1 link set dev swp1 up" + busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 forwarding + log_test $? 0 "swp1 administratively up" + + run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" + tc_check_packets $sw1 "dev swp1 egress" 101 4 + log_test $? 0 "Forwarding out of swp1" + tc_check_packets $sw1 "dev vx0 egress" 101 2 + log_test $? 0 "No forwarding out of vx0" + # Remove vx0 as the backup port of swp1 and check that packets are no # longer forwarded out of vx0 when swp1 does not have a carrier. run_cmd "bridge -n $sw1 link set dev swp1 nobackup_port" @@ -322,9 +345,9 @@ backup_port() log_test $? 1 "vx0 not configured as backup port of swp1" run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" - tc_check_packets $sw1 "dev swp1 egress" 101 4 + tc_check_packets $sw1 "dev swp1 egress" 101 5 log_test $? 0 "Forwarding out of swp1" - tc_check_packets $sw1 "dev vx0 egress" 101 1 + tc_check_packets $sw1 "dev vx0 egress" 101 2 log_test $? 0 "No forwarding out of vx0" run_cmd "ip -n $sw1 link set dev swp1 carrier off" @@ -332,9 +355,9 @@ backup_port() log_test $? 0 "swp1 carrier off" run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" - tc_check_packets $sw1 "dev swp1 egress" 101 4 + tc_check_packets $sw1 "dev swp1 egress" 101 5 log_test $? 0 "No forwarding out of swp1" - tc_check_packets $sw1 "dev vx0 egress" 101 1 + tc_check_packets $sw1 "dev vx0 egress" 101 2 log_test $? 0 "No forwarding out of vx0" } From 6398d8a856fb8be01f53cf84b481b3cdac978607 Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Tue, 12 Aug 2025 14:50:26 +0800 Subject: [PATCH 00884/11391] sfc: replace min/max nesting with clamp() The clamp() macro explicitly expresses the intent of constraining a value within bounds.Therefore, replacing min(max(a, b), c) with clamp(val, lo, hi) can improve code readability. Signed-off-by: Xichao Zhao Reviewed-by: Joe Damato Reviewed-by: Edward Cree Link: https://patch.msgid.link/20250812065026.620115-1-zhao.xichao@vivo.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/sfc/efx_channels.c | 4 ++-- drivers/net/ethernet/sfc/falcon/efx.c | 5 ++--- drivers/net/ethernet/sfc/siena/efx_channels.c | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/sfc/efx_channels.c b/drivers/net/ethernet/sfc/efx_channels.c index 06b4f52713ef..0f66324ed351 100644 --- a/drivers/net/ethernet/sfc/efx_channels.c +++ b/drivers/net/ethernet/sfc/efx_channels.c @@ -216,8 +216,8 @@ static int efx_allocate_msix_channels(struct efx_nic *efx, if (efx_separate_tx_channels) { efx->n_tx_channels = - min(max(n_channels / 2, 1U), - efx->max_tx_channels); + clamp(n_channels / 2, 1U, + efx->max_tx_channels); efx->tx_channel_offset = n_channels - efx->n_tx_channels; efx->n_rx_channels = diff --git a/drivers/net/ethernet/sfc/falcon/efx.c b/drivers/net/ethernet/sfc/falcon/efx.c index b07f7e4e2877..d19fbf8732ff 100644 --- a/drivers/net/ethernet/sfc/falcon/efx.c +++ b/drivers/net/ethernet/sfc/falcon/efx.c @@ -1394,9 +1394,8 @@ static int ef4_probe_interrupts(struct ef4_nic *efx) if (n_channels > extra_channels) n_channels -= extra_channels; if (ef4_separate_tx_channels) { - efx->n_tx_channels = min(max(n_channels / 2, - 1U), - efx->max_tx_channels); + efx->n_tx_channels = clamp(n_channels / 2, 1U, + efx->max_tx_channels); efx->n_rx_channels = max(n_channels - efx->n_tx_channels, 1U); diff --git a/drivers/net/ethernet/sfc/siena/efx_channels.c b/drivers/net/ethernet/sfc/siena/efx_channels.c index d120b3c83ac0..703419866d18 100644 --- a/drivers/net/ethernet/sfc/siena/efx_channels.c +++ b/drivers/net/ethernet/sfc/siena/efx_channels.c @@ -217,8 +217,8 @@ static int efx_allocate_msix_channels(struct efx_nic *efx, if (efx_siena_separate_tx_channels) { efx->n_tx_channels = - min(max(n_channels / 2, 1U), - efx->max_tx_channels); + clamp(n_channels / 2, 1U, + efx->max_tx_channels); efx->tx_channel_offset = n_channels - efx->n_tx_channels; efx->n_rx_channels = From 7f95f04fe1903a31b61085e3ab1b4730f9d72941 Mon Sep 17 00:00:00 2001 From: Kyle Hendry Date: Wed, 13 Aug 2025 17:25:27 -0700 Subject: [PATCH 00885/11391] net: dsa: b53: mmap: Add gphy port to phy info for bcm63268 Add gphy mask to bcm63xx phy info struct and add data for bcm63268 Signed-off-by: Kyle Hendry Reviewed-by: Florian Fainelli Link: https://patch.msgid.link/20250814002530.5866-2-kylehendrydev@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/b53/b53_mmap.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/dsa/b53/b53_mmap.c b/drivers/net/dsa/b53/b53_mmap.c index f06c3e0cc42a..87e1338765c2 100644 --- a/drivers/net/dsa/b53/b53_mmap.c +++ b/drivers/net/dsa/b53/b53_mmap.c @@ -31,6 +31,7 @@ #define BCM63XX_EPHY_REG 0x3C struct b53_phy_info { + u32 gphy_port_mask; u32 ephy_enable_mask; u32 ephy_port_mask; u32 ephy_bias_bit; @@ -65,6 +66,7 @@ static const struct b53_phy_info bcm6368_ephy_info = { static const u32 bcm63268_ephy_offsets[] = {4, 9, 14}; static const struct b53_phy_info bcm63268_ephy_info = { + .gphy_port_mask = BIT(3), .ephy_enable_mask = GENMASK(4, 0), .ephy_port_mask = GENMASK((ARRAY_SIZE(bcm63268_ephy_offsets) - 1), 0), .ephy_bias_bit = 24, From 61730ac10ba90c52563861a0119504f6a9be9868 Mon Sep 17 00:00:00 2001 From: Kyle Hendry Date: Wed, 13 Aug 2025 17:25:28 -0700 Subject: [PATCH 00886/11391] net: dsa: b53: mmap: Implement bcm63268 gphy power control Add check for gphy in enable/disable phy calls and set power bits in gphy control register. Signed-off-by: Kyle Hendry Reviewed-by: Florian Fainelli Link: https://patch.msgid.link/20250814002530.5866-3-kylehendrydev@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/b53/b53_mmap.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/drivers/net/dsa/b53/b53_mmap.c b/drivers/net/dsa/b53/b53_mmap.c index 87e1338765c2..f4a59d8fbdd6 100644 --- a/drivers/net/dsa/b53/b53_mmap.c +++ b/drivers/net/dsa/b53/b53_mmap.c @@ -29,6 +29,10 @@ #include "b53_priv.h" #define BCM63XX_EPHY_REG 0x3C +#define BCM63268_GPHY_REG 0x54 + +#define GPHY_CTRL_LOW_PWR BIT(3) +#define GPHY_CTRL_IDDQ_BIAS BIT(0) struct b53_phy_info { u32 gphy_port_mask; @@ -292,13 +296,30 @@ static int bcm63xx_ephy_set(struct b53_device *dev, int port, bool enable) return regmap_update_bits(gpio_ctrl, BCM63XX_EPHY_REG, mask, val); } +static int bcm63268_gphy_set(struct b53_device *dev, bool enable) +{ + struct b53_mmap_priv *priv = dev->priv; + struct regmap *gpio_ctrl = priv->gpio_ctrl; + u32 mask = GPHY_CTRL_IDDQ_BIAS | GPHY_CTRL_LOW_PWR; + u32 val = 0; + + if (!enable) + val = mask; + + return regmap_update_bits(gpio_ctrl, BCM63268_GPHY_REG, mask, val); +} + static void b53_mmap_phy_enable(struct b53_device *dev, int port) { struct b53_mmap_priv *priv = dev->priv; int ret = 0; - if (priv->phy_info && (BIT(port) & priv->phy_info->ephy_port_mask)) - ret = bcm63xx_ephy_set(dev, port, true); + if (priv->phy_info) { + if (BIT(port) & priv->phy_info->ephy_port_mask) + ret = bcm63xx_ephy_set(dev, port, true); + else if (BIT(port) & priv->phy_info->gphy_port_mask) + ret = bcm63268_gphy_set(dev, true); + } if (!ret) priv->phys_enabled |= BIT(port); @@ -309,8 +330,12 @@ static void b53_mmap_phy_disable(struct b53_device *dev, int port) struct b53_mmap_priv *priv = dev->priv; int ret = 0; - if (priv->phy_info && (BIT(port) & priv->phy_info->ephy_port_mask)) - ret = bcm63xx_ephy_set(dev, port, false); + if (priv->phy_info) { + if (BIT(port) & priv->phy_info->ephy_port_mask) + ret = bcm63xx_ephy_set(dev, port, false); + else if (BIT(port) & priv->phy_info->gphy_port_mask) + ret = bcm63268_gphy_set(dev, false); + } if (!ret) priv->phys_enabled &= ~BIT(port); From 5e04ff729f93fff16ec760e9cd7b72499963663f Mon Sep 17 00:00:00 2001 From: John Hubbard Date: Fri, 18 Jul 2025 16:26:06 +0900 Subject: [PATCH 00887/11391] gpu: nova-core: register: minor grammar and spelling fixes There is only one top-level macro in this file at the moment, but the "macros.rs" file name allows for more. Change the wording so that it will remain valid even if additional macros are added to the file. Fix a couple of spelling errors and grammatical errors, and break up a run-on sentence, for clarity. Cc: Alexandre Courbot Cc: Danilo Krummrich Signed-off-by: John Hubbard Reviewed-by: Daniel Almeida Reviewed-by: Lyude Paul Link: https://lore.kernel.org/r/20250718-nova-regs-v2-1-7b6a762aa1cd@nvidia.com Signed-off-by: Alexandre Courbot --- drivers/gpu/nova-core/regs/macros.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/nova-core/regs/macros.rs b/drivers/gpu/nova-core/regs/macros.rs index a3e6de1779d4..6d4080a65ee4 100644 --- a/drivers/gpu/nova-core/regs/macros.rs +++ b/drivers/gpu/nova-core/regs/macros.rs @@ -1,17 +1,17 @@ // SPDX-License-Identifier: GPL-2.0 -//! Macro to define register layout and accessors. +//! `register!` macro to define register layout and accessors. //! //! A single register typically includes several fields, which are accessed through a combination //! of bit-shift and mask operations that introduce a class of potential mistakes, notably because //! not all possible field values are necessarily valid. //! -//! The macro in this module allow to define, using an intruitive and readable syntax, a dedicated -//! type for each register with its own field accessors that can return an error is a field's value -//! is invalid. +//! The `register!` macro in this module provides an intuitive and readable syntax for defining a +//! dedicated type for each register. Each such type comes with its own field accessors that can +//! return an error if a field's value is invalid. -/// Defines a dedicated type for a register with an absolute offset, alongside with getter and -/// setter methods for its fields and methods to read and write it from an `Io` region. +/// Defines a dedicated type for a register with an absolute offset, including getter and setter +/// methods for its fields and methods to read and write it from an `Io` region. /// /// Example: /// @@ -24,7 +24,7 @@ /// ``` /// /// This defines a `BOOT_0` type which can be read or written from offset `0x100` of an `Io` -/// region. It is composed of 3 fields, for instance `minor_revision` is made of the 4 less +/// region. It is composed of 3 fields, for instance `minor_revision` is made of the 4 least /// significant bits of the register. Each field can be accessed and modified using accessor /// methods: /// From f10512e2c44e6ee3242314d43102acab7340e2d3 Mon Sep 17 00:00:00 2001 From: Hendrik Hamerlinck Date: Wed, 13 Aug 2025 11:22:39 +0200 Subject: [PATCH 00888/11391] dt-bindings: riscv: spacemit: Add OrangePi RV2 board Document the compatible string for the OrangePi RV2 board [1]. The board is described as using the Ky X1 SoC, which, based on available downstream sources and testing, appears to be identical or very closely related to the SpacemiT K1 SoC [2]. Link: http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/details/Orange-Pi-RV2.html [1] Link: https://www.spacemit.com/en/key-stone-k1 [2] Signed-off-by: Hendrik Hamerlinck Reviewed-by: Yixun Lan Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250813092240.180333-2-hendrik.hamerlinck@hammernet.be Signed-off-by: Yixun Lan --- Documentation/devicetree/bindings/riscv/spacemit.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/riscv/spacemit.yaml b/Documentation/devicetree/bindings/riscv/spacemit.yaml index 077b94f10dca..c56b62a6299a 100644 --- a/Documentation/devicetree/bindings/riscv/spacemit.yaml +++ b/Documentation/devicetree/bindings/riscv/spacemit.yaml @@ -22,6 +22,7 @@ properties: - enum: - bananapi,bpi-f3 - milkv,jupiter + - xunlong,orangepi-rv2 - const: spacemit,k1 additionalProperties: true From bab8dea259100a99e047fd11a48940b229d30031 Mon Sep 17 00:00:00 2001 From: Hendrik Hamerlinck Date: Wed, 13 Aug 2025 11:22:40 +0200 Subject: [PATCH 00889/11391] riscv: dts: spacemit: Add OrangePi RV2 board device tree Add initial device tree support for the OrangePi RV2 board [1]. The board is described as using the Ky X1 SoC, which, based on available downstream sources and testing, appears to be identical or very closely related to the SpacemiT K1 SoC [2]. The device tree is adapted from the OrangePi vendor tree [3], and similar integration can be found in the Banana Pi kernel tree [4], confirming SoC compatibility. The main difference with the current Banana Pi BPI-F3 tree is that status led is using GPIO_ACTIVE_LOW. This minimal device tree enables booting into a serial console with UART output and a blinking LED. Link: http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/details/Orange-Pi-RV2.html [1] Link: https://www.spacemit.com/en/key-stone-k1 [2] Link: https://github.com/BPI-SINOVOIP/pi-linux/blob/linux-6.6.63-k1/arch/riscv/boot/dts/spacemit/k1-x_orangepi-rv2.dts [3] Link: https://github.com/orangepi-xunlong/linux-orangepi/tree/orange-pi-6.6-ky [4] Signed-off-by: Hendrik Hamerlinck Reviewed-by: Yixun Lan Link: https://lore.kernel.org/r/20250813092240.180333-3-hendrik.hamerlinck@hammernet.be Signed-off-by: Yixun Lan --- arch/riscv/boot/dts/spacemit/Makefile | 1 + .../boot/dts/spacemit/k1-orangepi-rv2.dts | 40 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 arch/riscv/boot/dts/spacemit/k1-orangepi-rv2.dts diff --git a/arch/riscv/boot/dts/spacemit/Makefile b/arch/riscv/boot/dts/spacemit/Makefile index 92e13ce1c16d..152832644870 100644 --- a/arch/riscv/boot/dts/spacemit/Makefile +++ b/arch/riscv/boot/dts/spacemit/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 dtb-$(CONFIG_ARCH_SPACEMIT) += k1-bananapi-f3.dtb dtb-$(CONFIG_ARCH_SPACEMIT) += k1-milkv-jupiter.dtb +dtb-$(CONFIG_ARCH_SPACEMIT) += k1-orangepi-rv2.dtb diff --git a/arch/riscv/boot/dts/spacemit/k1-orangepi-rv2.dts b/arch/riscv/boot/dts/spacemit/k1-orangepi-rv2.dts new file mode 100644 index 000000000000..337240ebb7b7 --- /dev/null +++ b/arch/riscv/boot/dts/spacemit/k1-orangepi-rv2.dts @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2024 Yangyu Chen + * Copyright (C) 2025 Hendrik Hamerlinck + */ + +/dts-v1/; + +#include "k1.dtsi" +#include "k1-pinctrl.dtsi" + +/ { + model = "OrangePi RV2"; + compatible = "xunlong,orangepi-rv2", "spacemit,k1"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0"; + }; + + leds { + compatible = "gpio-leds"; + + led1 { + label = "sys-led"; + gpios = <&gpio K1_GPIO(96) GPIO_ACTIVE_LOW>; + linux,default-trigger = "heartbeat"; + default-state = "on"; + }; + }; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_2_cfg>; + status = "okay"; +}; From be3536a4bdda53ff5a91b7e542b167d12bddb317 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 18 Jul 2025 16:26:07 +0900 Subject: [PATCH 00890/11391] gpu: nova-core: register: add missing space in register!() A space was missing between arguments in this invocation. [acourbot@nvidia.com: use more descriptive commit title] Reviewed-by: Daniel Almeida Reviewed-by: Boqun Feng Reviewed-by: Lyude Paul Link: https://lore.kernel.org/r/20250718-nova-regs-v2-2-7b6a762aa1cd@nvidia.com Signed-off-by: Alexandre Courbot --- drivers/gpu/nova-core/regs/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/nova-core/regs/macros.rs b/drivers/gpu/nova-core/regs/macros.rs index 6d4080a65ee4..9cc612f41f12 100644 --- a/drivers/gpu/nova-core/regs/macros.rs +++ b/drivers/gpu/nova-core/regs/macros.rs @@ -116,7 +116,7 @@ macro_rules! register { ) => { register!(@common $name @ $offset $(, $comment)?); register!(@field_accessors $name { $($fields)* }); - register!(@io$name @ + $offset); + register!(@io $name @ + $offset); }; // Creates a alias register of relative offset register `alias` with its own fields. From 7f224967aee7d5ad88b6db76ca161be622ae7b34 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 31 Jul 2025 09:15:52 +0200 Subject: [PATCH 00891/11391] scsi: ufs: qcom: dt-bindings: Split common part to qcom,ufs-common.yaml The binding for Qualcomm SoC UFS controllers grew and it will grow further. It already includes several conditionals, partially for difference in handling encryption block (ICE, either as phandle or as I/O address space) but it will further grow for MCQ. Prepare for splitting this one big binding into several ones for common group of devices by defining common part for all Qualcomm UFS schemas. This only moves code, no functional impact expected. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250731-dt-bindings-ufs-qcom-v2-1-53bb634bf95a@linaro.org Reviewed-by: Rob Herring (Arm) Signed-off-by: Martin K. Petersen --- .../bindings/ufs/qcom,ufs-common.yaml | 67 +++++++++++++++++++ .../devicetree/bindings/ufs/qcom,ufs.yaml | 53 +-------------- 2 files changed, 68 insertions(+), 52 deletions(-) create mode 100644 Documentation/devicetree/bindings/ufs/qcom,ufs-common.yaml diff --git a/Documentation/devicetree/bindings/ufs/qcom,ufs-common.yaml b/Documentation/devicetree/bindings/ufs/qcom,ufs-common.yaml new file mode 100644 index 000000000000..962dffcd28b4 --- /dev/null +++ b/Documentation/devicetree/bindings/ufs/qcom,ufs-common.yaml @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/ufs/qcom,ufs-common.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Universal Flash Storage (UFS) Controller Common Properties + +maintainers: + - Bjorn Andersson + +properties: + clocks: + minItems: 7 + maxItems: 9 + + clock-names: + minItems: 7 + maxItems: 9 + + dma-coherent: true + + interconnects: + minItems: 2 + maxItems: 2 + + interconnect-names: + items: + - const: ufs-ddr + - const: cpu-ufs + + iommus: + minItems: 1 + maxItems: 2 + + phys: + maxItems: 1 + + phy-names: + items: + - const: ufsphy + + power-domains: + maxItems: 1 + + required-opps: + maxItems: 1 + + resets: + maxItems: 1 + + '#reset-cells': + const: 1 + + reset-names: + items: + - const: rst + + reset-gpios: + maxItems: 1 + description: + GPIO connected to the RESET pin of the UFS memory device. + +allOf: + - $ref: ufs-common.yaml + +additionalProperties: true diff --git a/Documentation/devicetree/bindings/ufs/qcom,ufs.yaml b/Documentation/devicetree/bindings/ufs/qcom,ufs.yaml index 6c6043d9809e..fc0f7b8d1cd1 100644 --- a/Documentation/devicetree/bindings/ufs/qcom,ufs.yaml +++ b/Documentation/devicetree/bindings/ufs/qcom,ufs.yaml @@ -47,39 +47,6 @@ properties: - const: qcom,ufshc - const: jedec,ufs-2.0 - clocks: - minItems: 7 - maxItems: 9 - - clock-names: - minItems: 7 - maxItems: 9 - - dma-coherent: true - - interconnects: - minItems: 2 - maxItems: 2 - - interconnect-names: - items: - - const: ufs-ddr - - const: cpu-ufs - - iommus: - minItems: 1 - maxItems: 2 - - phys: - maxItems: 1 - - phy-names: - items: - - const: ufsphy - - power-domains: - maxItems: 1 - qcom,ice: $ref: /schemas/types.yaml#/definitions/phandle description: phandle to the Inline Crypto Engine node @@ -93,30 +60,12 @@ properties: - const: std - const: ice - required-opps: - maxItems: 1 - - resets: - maxItems: 1 - - '#reset-cells': - const: 1 - - reset-names: - items: - - const: rst - - reset-gpios: - maxItems: 1 - description: - GPIO connected to the RESET pin of the UFS memory device. - required: - compatible - reg allOf: - - $ref: ufs-common.yaml + - $ref: qcom,ufs-common.yaml - if: properties: From 655c8f511926250e0da9e8b1a9b8f1cf2c173b41 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 31 Jul 2025 09:15:53 +0200 Subject: [PATCH 00892/11391] scsi: ufs: qcom: dt-bindings: Split SC7180 and similar The binding for Qualcomm SoC UFS controllers grew and it will grow further. Split SC7180 and several other devices which: 1. Do not reference ICE as I/O address space, but as a phandle, 2. Have same order of clocks (SC7180 has one clock less than SC7280 and other variants in split binding). The split allows easier review and maintenance of the binding. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250731-dt-bindings-ufs-qcom-v2-2-53bb634bf95a@linaro.org Reviewed-by: Rob Herring (Arm) Signed-off-by: Martin K. Petersen --- .../bindings/ufs/qcom,sc7180-ufshc.yaml | 167 ++++++++++++++++++ .../devicetree/bindings/ufs/qcom,ufs.yaml | 104 ++++------- 2 files changed, 202 insertions(+), 69 deletions(-) create mode 100644 Documentation/devicetree/bindings/ufs/qcom,sc7180-ufshc.yaml diff --git a/Documentation/devicetree/bindings/ufs/qcom,sc7180-ufshc.yaml b/Documentation/devicetree/bindings/ufs/qcom,sc7180-ufshc.yaml new file mode 100644 index 000000000000..d94ef4e6b85a --- /dev/null +++ b/Documentation/devicetree/bindings/ufs/qcom,sc7180-ufshc.yaml @@ -0,0 +1,167 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/ufs/qcom,sc7180-ufshc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SC7180 and Other SoCs UFS Controllers + +maintainers: + - Bjorn Andersson + +# Select only our matches, not all jedec,ufs-2.0 +select: + properties: + compatible: + contains: + enum: + - qcom,msm8998-ufshc + - qcom,qcs8300-ufshc + - qcom,sa8775p-ufshc + - qcom,sc7180-ufshc + - qcom,sc7280-ufshc + - qcom,sc8180x-ufshc + - qcom,sc8280xp-ufshc + - qcom,sm8250-ufshc + - qcom,sm8350-ufshc + - qcom,sm8450-ufshc + - qcom,sm8550-ufshc + required: + - compatible + +properties: + compatible: + items: + - enum: + - qcom,msm8998-ufshc + - qcom,qcs8300-ufshc + - qcom,sa8775p-ufshc + - qcom,sc7180-ufshc + - qcom,sc7280-ufshc + - qcom,sc8180x-ufshc + - qcom,sc8280xp-ufshc + - qcom,sm8250-ufshc + - qcom,sm8350-ufshc + - qcom,sm8450-ufshc + - qcom,sm8550-ufshc + - const: qcom,ufshc + - const: jedec,ufs-2.0 + + reg: + maxItems: 1 + + reg-names: + items: + - const: std + + clocks: + minItems: 7 + maxItems: 8 + + clock-names: + minItems: 7 + items: + - const: core_clk + - const: bus_aggr_clk + - const: iface_clk + - const: core_clk_unipro + - const: ref_clk + - const: tx_lane0_sync_clk + - const: rx_lane0_sync_clk + - const: rx_lane1_sync_clk + + qcom,ice: + $ref: /schemas/types.yaml#/definitions/phandle + description: phandle to the Inline Crypto Engine node + +required: + - compatible + - reg + +allOf: + - $ref: qcom,ufs-common.yaml + + - if: + properties: + compatible: + contains: + enum: + - qcom,sc7180-ufshc + then: + properties: + clocks: + maxItems: 7 + clock-names: + maxItems: 7 + else: + properties: + clocks: + minItems: 8 + clock-names: + minItems: 8 + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + #include + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + ufs@1d84000 { + compatible = "qcom,sm8450-ufshc", "qcom,ufshc", + "jedec,ufs-2.0"; + reg = <0x0 0x01d84000 0x0 0x3000>; + interrupts = ; + phys = <&ufs_mem_phy_lanes>; + phy-names = "ufsphy"; + lanes-per-direction = <2>; + #reset-cells = <1>; + resets = <&gcc GCC_UFS_PHY_BCR>; + reset-names = "rst"; + reset-gpios = <&tlmm 210 GPIO_ACTIVE_LOW>; + + vcc-supply = <&vreg_l7b_2p5>; + vcc-max-microamp = <1100000>; + vccq-supply = <&vreg_l9b_1p2>; + vccq-max-microamp = <1200000>; + + power-domains = <&gcc UFS_PHY_GDSC>; + iommus = <&apps_smmu 0xe0 0x0>; + interconnects = <&aggre1_noc MASTER_UFS_MEM &mc_virt SLAVE_EBI1>, + <&gem_noc MASTER_APPSS_PROC &config_noc SLAVE_UFS_MEM_CFG>; + interconnect-names = "ufs-ddr", "cpu-ufs"; + + clocks = <&gcc GCC_UFS_PHY_AXI_CLK>, + <&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>, + <&gcc GCC_UFS_PHY_AHB_CLK>, + <&gcc GCC_UFS_PHY_UNIPRO_CORE_CLK>, + <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>, + <&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>, + <&gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>; + clock-names = "core_clk", + "bus_aggr_clk", + "iface_clk", + "core_clk_unipro", + "ref_clk", + "tx_lane0_sync_clk", + "rx_lane0_sync_clk", + "rx_lane1_sync_clk"; + freq-table-hz = <75000000 300000000>, + <0 0>, + <0 0>, + <75000000 300000000>, + <75000000 300000000>, + <0 0>, + <0 0>, + <0 0>; + qcom,ice = <&ice>; + }; + }; diff --git a/Documentation/devicetree/bindings/ufs/qcom,ufs.yaml b/Documentation/devicetree/bindings/ufs/qcom,ufs.yaml index fc0f7b8d1cd1..191b88120d13 100644 --- a/Documentation/devicetree/bindings/ufs/qcom,ufs.yaml +++ b/Documentation/devicetree/bindings/ufs/qcom,ufs.yaml @@ -15,7 +15,17 @@ select: properties: compatible: contains: - const: qcom,ufshc + enum: + - qcom,msm8994-ufshc + - qcom,msm8996-ufshc + - qcom,qcs615-ufshc + - qcom,sdm845-ufshc + - qcom,sm6115-ufshc + - qcom,sm6125-ufshc + - qcom,sm6350-ufshc + - qcom,sm8150-ufshc + - qcom,sm8650-ufshc + - qcom,sm8750-ufshc required: - compatible @@ -25,23 +35,12 @@ properties: - enum: - qcom,msm8994-ufshc - qcom,msm8996-ufshc - - qcom,msm8998-ufshc - qcom,qcs615-ufshc - - qcom,qcs8300-ufshc - - qcom,sa8775p-ufshc - - qcom,sc7180-ufshc - - qcom,sc7280-ufshc - - qcom,sc8180x-ufshc - - qcom,sc8280xp-ufshc - qcom,sdm845-ufshc - qcom,sm6115-ufshc - qcom,sm6125-ufshc - qcom,sm6350-ufshc - qcom,sm8150-ufshc - - qcom,sm8250-ufshc - - qcom,sm8350-ufshc - - qcom,sm8450-ufshc - - qcom,sm8550-ufshc - qcom,sm8650-ufshc - qcom,sm8750-ufshc - const: qcom,ufshc @@ -72,41 +71,6 @@ allOf: compatible: contains: enum: - - qcom,sc7180-ufshc - then: - properties: - clocks: - minItems: 7 - maxItems: 7 - clock-names: - items: - - const: core_clk - - const: bus_aggr_clk - - const: iface_clk - - const: core_clk_unipro - - const: ref_clk - - const: tx_lane0_sync_clk - - const: rx_lane0_sync_clk - reg: - maxItems: 1 - reg-names: - maxItems: 1 - - - if: - properties: - compatible: - contains: - enum: - - qcom,msm8998-ufshc - - qcom,qcs8300-ufshc - - qcom,sa8775p-ufshc - - qcom,sc7280-ufshc - - qcom,sc8180x-ufshc - - qcom,sc8280xp-ufshc - - qcom,sm8250-ufshc - - qcom,sm8350-ufshc - - qcom,sm8450-ufshc - - qcom,sm8550-ufshc - qcom,sm8650-ufshc - qcom,sm8750-ufshc then: @@ -246,10 +210,10 @@ unevaluatedProperties: false examples: - | - #include + #include #include #include - #include + #include #include soc { @@ -257,9 +221,12 @@ examples: #size-cells = <2>; ufs@1d84000 { - compatible = "qcom,sm8450-ufshc", "qcom,ufshc", + compatible = "qcom,sm8150-ufshc", "qcom,ufshc", "jedec,ufs-2.0"; - reg = <0 0x01d84000 0 0x3000>; + reg = <0x0 0x01d84000 0x0 0x2500>, + <0x0 0x01d90000 0x0 0x8000>; + reg-names = "std", "ice"; + interrupts = ; phys = <&ufs_mem_phy_lanes>; phy-names = "ufsphy"; @@ -275,19 +242,8 @@ examples: vccq-max-microamp = <1200000>; power-domains = <&gcc UFS_PHY_GDSC>; - iommus = <&apps_smmu 0xe0 0x0>; - interconnects = <&aggre1_noc MASTER_UFS_MEM &mc_virt SLAVE_EBI1>, - <&gem_noc MASTER_APPSS_PROC &config_noc SLAVE_UFS_MEM_CFG>; - interconnect-names = "ufs-ddr", "cpu-ufs"; + iommus = <&apps_smmu 0x300 0>; - clock-names = "core_clk", - "bus_aggr_clk", - "iface_clk", - "core_clk_unipro", - "ref_clk", - "tx_lane0_sync_clk", - "rx_lane0_sync_clk", - "rx_lane1_sync_clk"; clocks = <&gcc GCC_UFS_PHY_AXI_CLK>, <&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>, <&gcc GCC_UFS_PHY_AHB_CLK>, @@ -295,15 +251,25 @@ examples: <&rpmhcc RPMH_CXO_CLK>, <&gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>, <&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>, - <&gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>; - freq-table-hz = <75000000 300000000>, + <&gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>, + <&gcc GCC_UFS_PHY_ICE_CORE_CLK>; + clock-names = "core_clk", + "bus_aggr_clk", + "iface_clk", + "core_clk_unipro", + "ref_clk", + "tx_lane0_sync_clk", + "rx_lane0_sync_clk", + "rx_lane1_sync_clk", + "ice_core_clk"; + freq-table-hz = <37500000 300000000>, <0 0>, <0 0>, - <75000000 300000000>, - <75000000 300000000>, + <37500000 300000000>, <0 0>, <0 0>, - <0 0>; - qcom,ice = <&ice>; + <0 0>, + <0 0>, + <0 300000000>; }; }; From 149009f2dc6f781f490a13264eaa565281e4d490 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 31 Jul 2025 09:15:54 +0200 Subject: [PATCH 00893/11391] scsi: ufs: qcom: dt-bindings: Split SM8650 and similar The binding for Qualcomm SoC UFS controllers grew and it will grow further. Split SM8650 and SM8750 UFS controllers which: 1. Do not reference ICE as IO address space, but as phandle, 2. Have same order of clocks. 3. Have MCQ I/O address space. Document that MCQ address space as optional to maintain backwards compatibility and because Linux drivers can operate perfectly fine without it (thus without MCQ feature). Linux driver already uses "mcq" as possible name for "reg-names" property. The split allows easier review and maintenance of the binding. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250731-dt-bindings-ufs-qcom-v2-3-53bb634bf95a@linaro.org Reviewed-by: Rob Herring (Arm) Acked-by: Manivannan Sadhasivam Signed-off-by: Martin K. Petersen --- .../bindings/ufs/qcom,sm8650-ufshc.yaml | 178 ++++++++++++++++++ .../devicetree/bindings/ufs/qcom,ufs.yaml | 32 ---- 2 files changed, 178 insertions(+), 32 deletions(-) create mode 100644 Documentation/devicetree/bindings/ufs/qcom,sm8650-ufshc.yaml diff --git a/Documentation/devicetree/bindings/ufs/qcom,sm8650-ufshc.yaml b/Documentation/devicetree/bindings/ufs/qcom,sm8650-ufshc.yaml new file mode 100644 index 000000000000..aaa0bbb5bfe1 --- /dev/null +++ b/Documentation/devicetree/bindings/ufs/qcom,sm8650-ufshc.yaml @@ -0,0 +1,178 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/ufs/qcom,sm8650-ufshc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SM8650 and Other SoCs UFS Controllers + +maintainers: + - Bjorn Andersson + +# Select only our matches, not all jedec,ufs-2.0 +select: + properties: + compatible: + contains: + enum: + - qcom,sm8650-ufshc + - qcom,sm8750-ufshc + required: + - compatible + +properties: + compatible: + items: + - enum: + - qcom,sm8650-ufshc + - qcom,sm8750-ufshc + - const: qcom,ufshc + - const: jedec,ufs-2.0 + + reg: + minItems: 1 + maxItems: 2 + + reg-names: + minItems: 1 + items: + - const: std + - const: mcq + + clocks: + minItems: 8 + maxItems: 8 + + clock-names: + items: + - const: core_clk + - const: bus_aggr_clk + - const: iface_clk + - const: core_clk_unipro + - const: ref_clk + - const: tx_lane0_sync_clk + - const: rx_lane0_sync_clk + - const: rx_lane1_sync_clk + + qcom,ice: + $ref: /schemas/types.yaml#/definitions/phandle + description: phandle to the Inline Crypto Engine node + +required: + - compatible + - reg + +allOf: + - $ref: qcom,ufs-common.yaml + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + #include + #include + #include + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + ufshc@1d84000 { + compatible = "qcom,sm8650-ufshc", "qcom,ufshc", "jedec,ufs-2.0"; + reg = <0x0 0x01d84000 0x0 0x3000>; + + interrupts = ; + + clocks = <&gcc GCC_UFS_PHY_AXI_CLK>, + <&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>, + <&gcc GCC_UFS_PHY_AHB_CLK>, + <&gcc GCC_UFS_PHY_UNIPRO_CORE_CLK>, + <&tcsr TCSR_UFS_PAD_CLKREF_EN>, + <&gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>, + <&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>, + <&gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>; + clock-names = "core_clk", + "bus_aggr_clk", + "iface_clk", + "core_clk_unipro", + "ref_clk", + "tx_lane0_sync_clk", + "rx_lane0_sync_clk", + "rx_lane1_sync_clk"; + + resets = <&gcc GCC_UFS_PHY_BCR>; + reset-names = "rst"; + reset-gpios = <&tlmm 210 GPIO_ACTIVE_LOW>; + + interconnects = <&aggre1_noc MASTER_UFS_MEM QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &config_noc SLAVE_UFS_MEM_CFG QCOM_ICC_TAG_ACTIVE_ONLY>; + interconnect-names = "ufs-ddr", + "cpu-ufs"; + + power-domains = <&gcc UFS_PHY_GDSC>; + required-opps = <&rpmhpd_opp_nom>; + + operating-points-v2 = <&ufs_opp_table>; + + iommus = <&apps_smmu 0x60 0>; + + lanes-per-direction = <2>; + qcom,ice = <&ice>; + + phys = <&ufs_mem_phy>; + phy-names = "ufsphy"; + + #reset-cells = <1>; + + vcc-supply = <&vreg_l7b_2p5>; + vcc-max-microamp = <1100000>; + vccq-supply = <&vreg_l9b_1p2>; + vccq-max-microamp = <1200000>; + + ufs_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-100000000 { + opp-hz = /bits/ 64 <100000000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <100000000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-201500000 { + opp-hz = /bits/ 64 <201500000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <201500000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-403000000 { + opp-hz = /bits/ 64 <403000000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <403000000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/ufs/qcom,ufs.yaml b/Documentation/devicetree/bindings/ufs/qcom,ufs.yaml index 191b88120d13..1dd41f6d5258 100644 --- a/Documentation/devicetree/bindings/ufs/qcom,ufs.yaml +++ b/Documentation/devicetree/bindings/ufs/qcom,ufs.yaml @@ -24,8 +24,6 @@ select: - qcom,sm6125-ufshc - qcom,sm6350-ufshc - qcom,sm8150-ufshc - - qcom,sm8650-ufshc - - qcom,sm8750-ufshc required: - compatible @@ -41,8 +39,6 @@ properties: - qcom,sm6125-ufshc - qcom,sm6350-ufshc - qcom,sm8150-ufshc - - qcom,sm8650-ufshc - - qcom,sm8750-ufshc - const: qcom,ufshc - const: jedec,ufs-2.0 @@ -66,34 +62,6 @@ required: allOf: - $ref: qcom,ufs-common.yaml - - if: - properties: - compatible: - contains: - enum: - - qcom,sm8650-ufshc - - qcom,sm8750-ufshc - then: - properties: - clocks: - minItems: 8 - maxItems: 8 - clock-names: - items: - - const: core_clk - - const: bus_aggr_clk - - const: iface_clk - - const: core_clk_unipro - - const: ref_clk - - const: tx_lane0_sync_clk - - const: rx_lane0_sync_clk - - const: rx_lane1_sync_clk - reg: - minItems: 1 - maxItems: 1 - reg-names: - maxItems: 1 - - if: properties: compatible: From 6c00c493a344b65fb0a356cb3f328a647085687b Mon Sep 17 00:00:00 2001 From: Peter Wang Date: Mon, 11 Aug 2025 21:11:17 +0800 Subject: [PATCH 00894/11391] scsi: ufs: host: mediatek: Simplify variable usage Simplify the code by using 'info->vcc' instead of 'hba->vreg_info.vcc', as they refer to the same value. This change improves code readability. Signed-off-by: Peter Wang Link: https://lore.kernel.org/r/20250811131423.3444014-2-peter.wang@mediatek.com Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-mediatek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index 86ae73b89d4d..1d2df63457bf 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -1018,7 +1018,7 @@ static int ufs_mtk_vreg_fix_vcc(struct ufs_hba *hba) struct arm_smccc_res res; int err, ver; - if (hba->vreg_info.vcc) + if (info->vcc) return 0; if (of_property_read_bool(np, "mediatek,ufs-vcc-by-num")) { From aa86602a483ba48f51044fbaefa1ebbf6da194a4 Mon Sep 17 00:00:00 2001 From: Peter Wang Date: Mon, 11 Aug 2025 21:11:18 +0800 Subject: [PATCH 00895/11391] scsi: ufs: host: mediatek: Fix auto-hibern8 timer configuration Move the configuration of the Auto-Hibern8 (AHIT) timer from the post-link stage to the 'fixup_dev_quirks' function. This change allows setting the AHIT based on the vendor requirements: (a) Samsung: 3.5 ms (b) Micron: 2 ms (c) Others: 1 ms Additionally, the clock gating timer is adjusted based on the AHIT scale, with a maximum setting of 10 ms. This ensures that the clock gating delay is appropriately configured to match the AHIT settings. Signed-off-by: Peter Wang Link: https://lore.kernel.org/r/20250811131423.3444014-3-peter.wang@mediatek.com Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-mediatek.c | 86 ++++++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 22 deletions(-) diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index 1d2df63457bf..e1eac1b428f8 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -1075,6 +1075,69 @@ static void ufs_mtk_vreg_fix_vccqx(struct ufs_hba *hba) } } +static void ufs_mtk_setup_clk_gating(struct ufs_hba *hba) +{ + unsigned long flags; + u32 ah_ms = 10; + u32 ah_scale, ah_timer; + u32 scale_us[] = {1, 10, 100, 1000, 10000, 100000}; + + if (ufshcd_is_clkgating_allowed(hba)) { + if (ufshcd_is_auto_hibern8_supported(hba) && hba->ahit) { + ah_scale = FIELD_GET(UFSHCI_AHIBERN8_SCALE_MASK, + hba->ahit); + ah_timer = FIELD_GET(UFSHCI_AHIBERN8_TIMER_MASK, + hba->ahit); + if (ah_scale <= 5) + ah_ms = ah_timer * scale_us[ah_scale] / 1000; + } + + spin_lock_irqsave(hba->host->host_lock, flags); + hba->clk_gating.delay_ms = max(ah_ms, 10U); + spin_unlock_irqrestore(hba->host->host_lock, flags); + } +} + +/* Convert microseconds to Auto-Hibernate Idle Timer register value */ +static u32 ufs_mtk_us_to_ahit(unsigned int timer) +{ + unsigned int scale; + + for (scale = 0; timer > UFSHCI_AHIBERN8_TIMER_MASK; ++scale) + timer /= UFSHCI_AHIBERN8_SCALE_FACTOR; + + return FIELD_PREP(UFSHCI_AHIBERN8_TIMER_MASK, timer) | + FIELD_PREP(UFSHCI_AHIBERN8_SCALE_MASK, scale); +} + +static void ufs_mtk_fix_ahit(struct ufs_hba *hba) +{ + unsigned int us; + + if (ufshcd_is_auto_hibern8_supported(hba)) { + switch (hba->dev_info.wmanufacturerid) { + case UFS_VENDOR_SAMSUNG: + /* configure auto-hibern8 timer to 3.5 ms */ + us = 3500; + break; + + case UFS_VENDOR_MICRON: + /* configure auto-hibern8 timer to 2 ms */ + us = 2000; + break; + + default: + /* configure auto-hibern8 timer to 1 ms */ + us = 1000; + break; + } + + hba->ahit = ufs_mtk_us_to_ahit(us); + } + + ufs_mtk_setup_clk_gating(hba); +} + static void ufs_mtk_init_mcq_irq(struct ufs_hba *hba) { struct ufs_mtk_host *host = ufshcd_get_variant(hba); @@ -1369,32 +1432,10 @@ static int ufs_mtk_pre_link(struct ufs_hba *hba) return ret; } - -static void ufs_mtk_setup_clk_gating(struct ufs_hba *hba) -{ - u32 ah_ms; - - if (ufshcd_is_clkgating_allowed(hba)) { - if (ufshcd_is_auto_hibern8_supported(hba) && hba->ahit) - ah_ms = FIELD_GET(UFSHCI_AHIBERN8_TIMER_MASK, - hba->ahit); - else - ah_ms = 10; - ufshcd_clkgate_delay_set(hba->dev, ah_ms + 5); - } -} - static void ufs_mtk_post_link(struct ufs_hba *hba) { /* enable unipro clock gating feature */ ufs_mtk_cfg_unipro_cg(hba, true); - - /* will be configured during probe hba */ - if (ufshcd_is_auto_hibern8_supported(hba)) - hba->ahit = FIELD_PREP(UFSHCI_AHIBERN8_TIMER_MASK, 10) | - FIELD_PREP(UFSHCI_AHIBERN8_SCALE_MASK, 3); - - ufs_mtk_setup_clk_gating(hba); } static int ufs_mtk_link_startup_notify(struct ufs_hba *hba, @@ -1726,6 +1767,7 @@ static void ufs_mtk_fixup_dev_quirks(struct ufs_hba *hba) ufs_mtk_vreg_fix_vcc(hba); ufs_mtk_vreg_fix_vccqx(hba); + ufs_mtk_fix_ahit(hba); } static void ufs_mtk_event_notify(struct ufs_hba *hba, From f91c6c70d103a619c58aa02bddf3c27c6433556a Mon Sep 17 00:00:00 2001 From: Peter Wang Date: Mon, 11 Aug 2025 21:11:19 +0800 Subject: [PATCH 00896/11391] scsi: ufs: host: mediatek: Add debug information for Auto-Hibern8 Enhance the clock gating logic by adding debug information for the Auto-Hibern8 (AHIT) register. This additional logging aids in troubleshooting by providing insights into the AHIT configuration when the clock is not turned off as expected. Signed-off-by: Peter Wang Link: https://lore.kernel.org/r/20250811131423.3444014-4-peter.wang@mediatek.com Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-mediatek.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index e1eac1b428f8..32f8d8da381e 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -798,8 +798,14 @@ static int ufs_mtk_setup_clocks(struct ufs_hba *hba, bool on, clk_pwr_off = true; } - if (clk_pwr_off) + if (clk_pwr_off) { ufs_mtk_pwr_ctrl(hba, false); + } else { + dev_warn(hba->dev, "Clock is not turned off, hba->ahit = 0x%x, AHIT = 0x%x\n", + hba->ahit, + ufshcd_readl(hba, + REG_AUTO_HIBERNATE_IDLE_TIMER)); + } ufs_mtk_mcq_disable_irq(hba); } else if (on && status == POST_CHANGE) { ufs_mtk_pwr_ctrl(hba, true); From 86a678a25108705657e2f3bb00c42f9e5e5d692b Mon Sep 17 00:00:00 2001 From: Peter Wang Date: Mon, 11 Aug 2025 21:11:20 +0800 Subject: [PATCH 00897/11391] scsi: ufs: host: mediatek: Fine-tune clock scaling Disable clock scaling for UFS versions below 4.0. Clock scaling is unnecessary for these versions, and this change ensures that the feature is only enabled for compatible UFS versions. Signed-off-by: Peter Wang Link: https://lore.kernel.org/r/20250811131423.3444014-5-peter.wang@mediatek.com Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-mediatek.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index 32f8d8da381e..2b55e77d5100 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -29,6 +29,7 @@ #include "ufs-mediatek-sip.h" static int ufs_mtk_config_mcq(struct ufs_hba *hba, bool irq); +static void _ufs_mtk_clk_scale(struct ufs_hba *hba, bool scale_up); #define CREATE_TRACE_POINTS #include "ufs-mediatek-trace.h" @@ -1144,6 +1145,17 @@ static void ufs_mtk_fix_ahit(struct ufs_hba *hba) ufs_mtk_setup_clk_gating(hba); } +static void ufs_mtk_fix_clock_scaling(struct ufs_hba *hba) +{ + /* UFS version is below 4.0, clock scaling is not necessary */ + if ((hba->dev_info.wspecversion < 0x0400) && + ufs_mtk_is_clk_scale_ready(hba)) { + hba->caps &= ~UFSHCD_CAP_CLK_SCALING; + + _ufs_mtk_clk_scale(hba, false); + } +} + static void ufs_mtk_init_mcq_irq(struct ufs_hba *hba) { struct ufs_mtk_host *host = ufshcd_get_variant(hba); @@ -1774,6 +1786,7 @@ static void ufs_mtk_fixup_dev_quirks(struct ufs_hba *hba) ufs_mtk_vreg_fix_vcc(hba); ufs_mtk_vreg_fix_vccqx(hba); ufs_mtk_fix_ahit(hba); + ufs_mtk_fix_clock_scaling(hba); } static void ufs_mtk_event_notify(struct ufs_hba *hba, From 7212d624f8638f8ea8ad1ecbb80622c7987bc7a1 Mon Sep 17 00:00:00 2001 From: Peter Wang Date: Mon, 11 Aug 2025 21:11:21 +0800 Subject: [PATCH 00898/11391] scsi: ufs: host: mediatek: Fix PWM mode switch issue Address a failure in switching to PWM mode by ensuring proper configuration of power modes and adaptation settings. The changes include checks for SLOW_MODE and adjustments to the desired working mode and adaptation configuration based on the device's power mode and hardware version. Signed-off-by: Peter Wang Link: https://lore.kernel.org/r/20250811131423.3444014-6-peter.wang@mediatek.com Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-mediatek.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index 2b55e77d5100..56f6dd01c470 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -1321,6 +1321,10 @@ static bool ufs_mtk_pmc_via_fastauto(struct ufs_hba *hba, dev_req_params->gear_rx < UFS_HS_G4) return false; + if (dev_req_params->pwr_tx == SLOW_MODE || + dev_req_params->pwr_rx == SLOW_MODE) + return false; + return true; } @@ -1336,6 +1340,10 @@ static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba, host_params.hs_rx_gear = UFS_HS_G5; host_params.hs_tx_gear = UFS_HS_G5; + if (dev_max_params->pwr_rx == SLOW_MODE || + dev_max_params->pwr_tx == SLOW_MODE) + host_params.desired_working_mode = UFS_PWM_MODE; + ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params); if (ret) { pr_info("%s: failed to determine capabilities\n", @@ -1368,10 +1376,21 @@ static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba, } } - if (host->hw_ver.major >= 3) { + if (dev_req_params->pwr_rx == FAST_MODE || + dev_req_params->pwr_rx == FASTAUTO_MODE) { + if (host->hw_ver.major >= 3) { + ret = ufshcd_dme_configure_adapt(hba, + dev_req_params->gear_tx, + PA_INITIAL_ADAPT); + } else { + ret = ufshcd_dme_configure_adapt(hba, + dev_req_params->gear_tx, + PA_NO_ADAPT); + } + } else { ret = ufshcd_dme_configure_adapt(hba, - dev_req_params->gear_tx, - PA_INITIAL_ADAPT); + dev_req_params->gear_tx, + PA_NO_ADAPT); } return ret; From 979feee0cf43b32d288931649d7c6d9a5524ea55 Mon Sep 17 00:00:00 2001 From: Alice Chao Date: Mon, 11 Aug 2025 21:11:22 +0800 Subject: [PATCH 00899/11391] scsi: ufs: host: mediatek: Assign power mode userdata before FASTAUTO mode change Assign power mode userdata settings before transitioning to FASTAUTO power mode. This ensures that default timeout values are set for various parameters, enhancing the reliability and performance of the power mode change process. Signed-off-by: Alice Chao Reviewed-by: Peter Wang Signed-off-by: Peter Wang Link: https://lore.kernel.org/r/20250811131423.3444014-7-peter.wang@mediatek.com Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-mediatek.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index 56f6dd01c470..bd6616598c33 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -1367,6 +1367,28 @@ static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba, ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXHSADAPTTYPE), PA_NO_ADAPT); + if (!(hba->quirks & UFSHCD_QUIRK_SKIP_DEF_UNIPRO_TIMEOUT_SETTING)) { + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA0), + DL_FC0ProtectionTimeOutVal_Default); + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA1), + DL_TC0ReplayTimeOutVal_Default); + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA2), + DL_AFC0ReqTimeOutVal_Default); + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA3), + DL_FC1ProtectionTimeOutVal_Default); + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA4), + DL_TC1ReplayTimeOutVal_Default); + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA5), + DL_AFC1ReqTimeOutVal_Default); + + ufshcd_dme_set(hba, UIC_ARG_MIB(DME_LocalFC0ProtectionTimeOutVal), + DL_FC0ProtectionTimeOutVal_Default); + ufshcd_dme_set(hba, UIC_ARG_MIB(DME_LocalTC0ReplayTimeOutVal), + DL_TC0ReplayTimeOutVal_Default); + ufshcd_dme_set(hba, UIC_ARG_MIB(DME_LocalAFC0ReqTimeOutVal), + DL_AFC0ReqTimeOutVal_Default); + } + ret = ufshcd_uic_change_pwr_mode(hba, FASTAUTO_MODE << 4 | FASTAUTO_MODE); From f1617ecf18aaf222482f683f44ab4b155976539d Mon Sep 17 00:00:00 2001 From: Peter Wang Date: Mon, 11 Aug 2025 21:11:23 +0800 Subject: [PATCH 00900/11391] scsi: ufs: host: mediatek: Optimize power mode change handling Optimize the power mode change process by skipping the adaptation setting toggle if the requested power mode configuration is already applied. This enhancement reduces unnecessary operations, improving efficiency during power mode transitions. Signed-off-by: Peter Wang Link: https://lore.kernel.org/r/20250811131423.3444014-8-peter.wang@mediatek.com Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-mediatek.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index bd6616598c33..1fb8a094d2af 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -1398,6 +1398,17 @@ static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba, } } + /* if already configured to the requested pwr_mode, skip adapt */ + if (dev_req_params->gear_rx == hba->pwr_info.gear_rx && + dev_req_params->gear_tx == hba->pwr_info.gear_tx && + dev_req_params->lane_rx == hba->pwr_info.lane_rx && + dev_req_params->lane_tx == hba->pwr_info.lane_tx && + dev_req_params->pwr_rx == hba->pwr_info.pwr_rx && + dev_req_params->pwr_tx == hba->pwr_info.pwr_tx && + dev_req_params->hs_rate == hba->pwr_info.hs_rate) { + return ret; + } + if (dev_req_params->pwr_rx == FAST_MODE || dev_req_params->pwr_rx == FASTAUTO_MODE) { if (host->hw_ver.major >= 3) { From bacb96ce06c05804fae4bfd38c4058b6d4c423b3 Mon Sep 17 00:00:00 2001 From: Peter Wang Date: Mon, 11 Aug 2025 21:11:24 +0800 Subject: [PATCH 00901/11391] scsi: ufs: host: mediatek: Fix UniPro setting for MT6989 Set the UniPro attribute 0xD09E[4] bit to enable the 1144 functions specifically for the MT6989 platform. This adjustment ensures proper functionality and compatibility with the MT6989 hardware. Signed-off-by: Peter Wang Link: https://lore.kernel.org/r/20250811131423.3444014-9-peter.wang@mediatek.com Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-mediatek.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index 1fb8a094d2af..e3d99981a802 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -1475,6 +1475,7 @@ static int ufs_mtk_pre_link(struct ufs_hba *hba) { int ret; u32 tmp; + struct ufs_mtk_host *host = ufshcd_get_variant(hba); ufs_mtk_get_controller_version(hba); @@ -1500,6 +1501,16 @@ static int ufs_mtk_pre_link(struct ufs_hba *hba) ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_SAVEPOWERCONTROL), tmp); + /* Enable the 1144 functions setting */ + if (host->ip_ver == IP_VER_MT6989) { + ret = ufshcd_dme_get(hba, UIC_ARG_MIB(VS_DEBUGOMC), &tmp); + if (ret) + return ret; + + tmp |= 0x10; + ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_DEBUGOMC), tmp); + } + return ret; } static void ufs_mtk_post_link(struct ufs_hba *hba) From 878ed88c50bfb14d972dd3b86a1c8188c58de4e5 Mon Sep 17 00:00:00 2001 From: Peter Wang Date: Mon, 11 Aug 2025 21:11:25 +0800 Subject: [PATCH 00902/11391] scsi: ufs: host: mediatek: Change reset sequence for improved stability Modify the reset sequence to ensure that the device reset pin is set low before the host is disabled. This change enhances the stability of the reset process by ensuring the correct order of operations. Signed-off-by: Peter Wang Link: https://lore.kernel.org/r/20250811131423.3444014-10-peter.wang@mediatek.com Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-mediatek.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index e3d99981a802..647b6eb05398 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -1543,11 +1543,11 @@ static int ufs_mtk_device_reset(struct ufs_hba *hba) { struct arm_smccc_res res; - /* disable hba before device reset */ - ufshcd_hba_stop(hba); - ufs_mtk_device_reset_ctrl(0, res); + /* disable hba in middle of device reset */ + ufshcd_hba_stop(hba); + /* * The reset signal is active low. UFS devices shall detect * more than or equal to 1us of positive or negative RST_n From 5863638598f5e4f64d2f85b03f376383ca1f2ab7 Mon Sep 17 00:00:00 2001 From: Alice Chao Date: Mon, 11 Aug 2025 21:11:26 +0800 Subject: [PATCH 00903/11391] scsi: ufs: host: mediatek: Fix invalid access in vccqx handling Add a NULL check before accessing the 'vccqx' pointer to prevent invalid memory access. This ensures that the function safely handles cases where 'vccq' and 'vccq2' are not initialized, improving the robustness of the power management code. Signed-off-by: Alice Chao Reviewed-by: Peter Wang Signed-off-by: Peter Wang Link: https://lore.kernel.org/r/20250811131423.3444014-11-peter.wang@mediatek.com Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-mediatek.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index 647b6eb05398..61c8fe135100 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -1629,6 +1629,9 @@ static void ufs_mtk_vccqx_set_lpm(struct ufs_hba *hba, bool lpm) { struct ufs_vreg *vccqx = NULL; + if (!hba->vreg_info.vccq && !hba->vreg_info.vccq2) + return; + if (hba->vreg_info.vccq) vccqx = hba->vreg_info.vccq; else From c5aeb264b6b27c52fc6c9ef3b50eaaebff5d9b60 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 18 Jul 2025 16:26:08 +0900 Subject: [PATCH 00904/11391] gpu: nova-core: register: allow fields named `offset` `offset` is a common field name, yet using it triggers a build error due to the conflict between the uppercased field constant (which becomes `OFFSET` in this case) containing the bitrange of the field, and the `OFFSET` constant constaining the offset of the register. Fix this by adding `_RANGE` the field's range constant to avoid the name collision. [acourbot@nvidia.com: fix merge conflict due to switch from `as u32` to `u32::from`.] Reported-by: Timur Tabi Reviewed-by: Daniel Almeida Reviewed-by: Lyude Paul Link: https://lore.kernel.org/r/20250718-nova-regs-v2-3-7b6a762aa1cd@nvidia.com Signed-off-by: Alexandre Courbot --- drivers/gpu/nova-core/regs.rs | 5 +++-- drivers/gpu/nova-core/regs/macros.rs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs index d49fddf6a3c6..c8f8adb24f6e 100644 --- a/drivers/gpu/nova-core/regs.rs +++ b/drivers/gpu/nova-core/regs.rs @@ -28,7 +28,7 @@ impl NV_PMC_BOOT_0 { /// Combines `architecture_0` and `architecture_1` to obtain the architecture of the chip. pub(crate) fn architecture(self) -> Result { Architecture::try_from( - self.architecture_0() | (self.architecture_1() << Self::ARCHITECTURE_0.len()), + self.architecture_0() | (self.architecture_1() << Self::ARCHITECTURE_0_RANGE.len()), ) } @@ -36,7 +36,8 @@ pub(crate) fn architecture(self) -> Result { pub(crate) fn chipset(self) -> Result { self.architecture() .map(|arch| { - ((arch as u32) << Self::IMPLEMENTATION.len()) | u32::from(self.implementation()) + ((arch as u32) << Self::IMPLEMENTATION_RANGE.len()) + | u32::from(self.implementation()) }) .and_then(Chipset::try_from) } diff --git a/drivers/gpu/nova-core/regs/macros.rs b/drivers/gpu/nova-core/regs/macros.rs index 9cc612f41f12..023748685412 100644 --- a/drivers/gpu/nova-core/regs/macros.rs +++ b/drivers/gpu/nova-core/regs/macros.rs @@ -278,7 +278,7 @@ impl $name { { $process:expr } $to_type:ty => $res_type:ty $(, $comment:literal)?; ) => { ::kernel::macros::paste!( - const [<$field:upper>]: ::core::ops::RangeInclusive = $lo..=$hi; + const [<$field:upper _RANGE>]: ::core::ops::RangeInclusive = $lo..=$hi; const [<$field:upper _MASK>]: u32 = ((((1 << $hi) - 1) << 1) + 1) - ((1 << $lo) - 1); const [<$field:upper _SHIFT>]: u32 = Self::[<$field:upper _MASK>].trailing_zeros(); ); From cb2607f3b27087120c15c13f57f1a950251445c9 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 18 Jul 2025 16:26:09 +0900 Subject: [PATCH 00905/11391] gpu: nova-core: register: improve documentation for basic registers Reword parts of the documentation that were a bit heavy to read, and harmonize/fix the examples. The relative registers section is about to be redesigned and its documentation rewritten, so do not touch this part. Reviewed-by: Daniel Almeida Reviewed-by: Lyude Paul Link: https://lore.kernel.org/r/20250718-nova-regs-v2-4-7b6a762aa1cd@nvidia.com Signed-off-by: Alexandre Courbot --- drivers/gpu/nova-core/regs/macros.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/nova-core/regs/macros.rs b/drivers/gpu/nova-core/regs/macros.rs index 023748685412..31df1827de77 100644 --- a/drivers/gpu/nova-core/regs/macros.rs +++ b/drivers/gpu/nova-core/regs/macros.rs @@ -33,25 +33,25 @@ /// let boot0 = BOOT_0::read(&bar); /// pr_info!("chip revision: {}.{}", boot0.major_revision(), boot0.minor_revision()); /// -/// // `Chipset::try_from` will be called with the value of the field and returns an error if the -/// // value is invalid. +/// // `Chipset::try_from` is called with the value of the `chipset` field and returns an +/// // error if it is invalid. /// let chipset = boot0.chipset()?; /// /// // Update some fields and write the value back. /// boot0.set_major_revision(3).set_minor_revision(10).write(&bar); /// -/// // Or just read and update the register in a single step: +/// // Or, just read and update the register in a single step: /// BOOT_0::alter(&bar, |r| r.set_major_revision(3).set_minor_revision(10)); /// ``` /// -/// Fields can be defined as follows: +/// Fields are defined as follows: /// -/// - `as ` simply returns the field value casted as the requested integer type, typically -/// `u32`, `u16`, `u8` or `bool`. Note that `bool` fields must have a range of 1 bit. +/// - `as ` simply returns the field value casted to , typically `u32`, `u16`, `u8` or +/// `bool`. Note that `bool` fields must have a range of 1 bit. /// - `as => ` calls ``'s `From::<>` implementation and returns /// the result. /// - `as ?=> ` calls ``'s `TryFrom::<>` implementation -/// and returns the result. This is useful on fields for which not all values are value. +/// and returns the result. This is useful with fields for which not all values are valid. /// /// The documentation strings are optional. If present, they will be added to the type's /// definition, or the field getter and setter methods they are attached to. @@ -76,15 +76,17 @@ /// for cases where a register's interpretation depends on the context: /// /// ```no_run -/// register!(SCRATCH_0 @ 0x0000100, "Scratch register 0" { +/// register!(SCRATCH @ 0x00000200, "Scratch register" { /// 31:0 value as u32, "Raw value"; +/// }); /// -/// register!(SCRATCH_0_BOOT_STATUS => SCRATCH_0, "Boot status of the firmware" { +/// register!(SCRATCH_BOOT_STATUS => SCRATCH, "Boot status of the firmware" { /// 0:0 completed as bool, "Whether the firmware has completed booting"; +/// }); /// ``` /// -/// In this example, `SCRATCH_0_BOOT_STATUS` uses the same I/O address as `SCRATCH_0`, while also -/// providing its own `completed` method. +/// In this example, `SCRATCH_0_BOOT_STATUS` uses the same I/O address as `SCRATCH`, while also +/// providing its own `completed` field. macro_rules! register { // Creates a register at a fixed offset of the MMIO space. ( From 4f7f8f847d4a9c2460ecd43a702e51ac31919e2f Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 18 Jul 2025 16:26:10 +0900 Subject: [PATCH 00906/11391] gpu: nova-core: register: simplify @leaf_accessor rule The `$type` metavariable is not used in the @leaf_accessor rule, so remove it. Reviewed-by: Daniel Almeida Reviewed-by: Lyude Paul Link: https://lore.kernel.org/r/20250718-nova-regs-v2-5-7b6a762aa1cd@nvidia.com Signed-off-by: Alexandre Courbot --- drivers/gpu/nova-core/regs/macros.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/nova-core/regs/macros.rs b/drivers/gpu/nova-core/regs/macros.rs index 31df1827de77..44e2a12dce52 100644 --- a/drivers/gpu/nova-core/regs/macros.rs +++ b/drivers/gpu/nova-core/regs/macros.rs @@ -230,7 +230,7 @@ impl $name { $(, $comment:literal)?; ) => { register!( - @leaf_accessor $name $hi:$lo $field as bool + @leaf_accessor $name $hi:$lo $field { |f| <$into_type>::from(if f != 0 { true } else { false }) } $into_type => $into_type $(, $comment)?; ); @@ -248,7 +248,7 @@ impl $name { @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt ?=> $try_into_type:ty $(, $comment:literal)?; ) => { - register!(@leaf_accessor $name $hi:$lo $field as $type + register!(@leaf_accessor $name $hi:$lo $field { |f| <$try_into_type>::try_from(f as $type) } $try_into_type => ::core::result::Result< $try_into_type, @@ -262,7 +262,7 @@ impl $name { @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt => $into_type:ty $(, $comment:literal)?; ) => { - register!(@leaf_accessor $name $hi:$lo $field as $type + register!(@leaf_accessor $name $hi:$lo $field { |f| <$into_type>::from(f as $type) } $into_type => $into_type $(, $comment)?;); }; @@ -276,7 +276,7 @@ impl $name { // Generates the accessor methods for a single field. ( - @leaf_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:ty + @leaf_accessor $name:ident $hi:tt:$lo:tt $field:ident { $process:expr } $to_type:ty => $res_type:ty $(, $comment:literal)?; ) => { ::kernel::macros::paste!( From b567daf4ea4e4565118436aca51d12adf8ab3e12 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 18 Jul 2025 16:26:11 +0900 Subject: [PATCH 00907/11391] gpu: nova-core: register: remove `try_` accessors for relative registers Relative registers are always accessed using a literal base, meaning their validity can always be checked at compile-time. Thus remove the `try_` accessors that have no purpose. Reviewed-by: Daniel Almeida Reviewed-by: Lyude Paul Link: https://lore.kernel.org/r/20250718-nova-regs-v2-6-7b6a762aa1cd@nvidia.com Signed-off-by: Alexandre Courbot --- drivers/gpu/nova-core/regs/macros.rs | 38 +--------------------------- 1 file changed, 1 insertion(+), 37 deletions(-) diff --git a/drivers/gpu/nova-core/regs/macros.rs b/drivers/gpu/nova-core/regs/macros.rs index 44e2a12dce52..0567b3aae4d2 100644 --- a/drivers/gpu/nova-core/regs/macros.rs +++ b/drivers/gpu/nova-core/regs/macros.rs @@ -57,9 +57,7 @@ /// definition, or the field getter and setter methods they are attached to. /// /// Putting a `+` before the address of the register makes it relative to a base: the `read` and -/// `write` methods take a `base` argument that is added to the specified address before access, -/// and `try_read` and `try_write` methods are also created, allowing access with offsets unknown -/// at compile-time: +/// `write` methods take a `base` argument that is added to the specified address before access: /// /// ```no_run /// register!(CPU_CTL @ +0x0000010, "CPU core control" { @@ -386,40 +384,6 @@ pub(crate) fn alter( let reg = f(Self::read(io, base)); reg.write(io, base); } - - #[inline] - pub(crate) fn try_read( - io: &T, - base: usize, - ) -> ::kernel::error::Result where - T: ::core::ops::Deref>, - { - io.try_read32(base + $offset).map(Self) - } - - #[inline] - pub(crate) fn try_write( - self, - io: &T, - base: usize, - ) -> ::kernel::error::Result<()> where - T: ::core::ops::Deref>, - { - io.try_write32(self.0, base + $offset) - } - - #[inline] - pub(crate) fn try_alter( - io: &T, - base: usize, - f: F, - ) -> ::kernel::error::Result<()> where - T: ::core::ops::Deref>, - F: ::core::ops::FnOnce(Self) -> Self, - { - let reg = f(Self::try_read(io, base)?); - reg.try_write(io, base) - } } }; } From 036c5fa25020d8b1619a96dabbcf9b156f4329bb Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 18 Jul 2025 16:26:12 +0900 Subject: [PATCH 00908/11391] gpu: nova-core: register: move OFFSET declaration to I/O impl block The OFFSET const is an I/O property, and having to pass it to the @common rule makes it impossible to make I/O optional, as we want to get to eventually. Thus, move OFFSET to the I/O impl block so it is not needed by the @common rule anymore. Reviewed-by: Daniel Almeida Reviewed-by: Lyude Paul Link: https://lore.kernel.org/r/20250718-nova-regs-v2-7-7b6a762aa1cd@nvidia.com Signed-off-by: Alexandre Courbot --- drivers/gpu/nova-core/regs/macros.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/nova-core/regs/macros.rs b/drivers/gpu/nova-core/regs/macros.rs index 0567b3aae4d2..3d4476cc2421 100644 --- a/drivers/gpu/nova-core/regs/macros.rs +++ b/drivers/gpu/nova-core/regs/macros.rs @@ -92,7 +92,7 @@ macro_rules! register { $($fields:tt)* } ) => { - register!(@common $name @ $offset $(, $comment)?); + register!(@common $name $(, $comment)?); register!(@field_accessors $name { $($fields)* }); register!(@io $name @ $offset); }; @@ -103,7 +103,7 @@ macro_rules! register { $($fields:tt)* } ) => { - register!(@common $name @ $alias::OFFSET $(, $comment)?); + register!(@common $name $(, $comment)?); register!(@field_accessors $name { $($fields)* }); register!(@io $name @ $alias::OFFSET); }; @@ -114,7 +114,7 @@ macro_rules! register { $($fields:tt)* } ) => { - register!(@common $name @ $offset $(, $comment)?); + register!(@common $name $(, $comment)?); register!(@field_accessors $name { $($fields)* }); register!(@io $name @ + $offset); }; @@ -125,7 +125,7 @@ macro_rules! register { $($fields:tt)* } ) => { - register!(@common $name @ $alias::OFFSET $(, $comment)?); + register!(@common $name $(, $comment)?); register!(@field_accessors $name { $($fields)* }); register!(@io $name @ + $alias::OFFSET); }; @@ -134,7 +134,7 @@ macro_rules! register { // Defines the wrapper `$name` type, as well as its relevant implementations (`Debug`, `BitOr`, // and conversion to regular `u32`). - (@common $name:ident @ $offset:expr $(, $comment:literal)?) => { + (@common $name:ident $(, $comment:literal)?) => { $( #[doc=$comment] )? @@ -142,11 +142,6 @@ macro_rules! register { #[derive(Clone, Copy, Default)] pub(crate) struct $name(u32); - #[allow(dead_code)] - impl $name { - pub(crate) const OFFSET: usize = $offset; - } - // TODO[REGA]: display the raw hex value, then the value of all the fields. This requires // matching the fields, which will complexify the syntax considerably... impl ::core::fmt::Debug for $name { @@ -319,6 +314,8 @@ pub(crate) fn [](mut self, value: $to_type) -> Self { (@io $name:ident @ $offset:expr) => { #[allow(dead_code)] impl $name { + pub(crate) const OFFSET: usize = $offset; + #[inline] pub(crate) fn read(io: &T) -> Self where T: ::core::ops::Deref>, @@ -351,6 +348,8 @@ pub(crate) fn alter( (@io $name:ident @ + $offset:literal) => { #[allow(dead_code)] impl $name { + pub(crate) const OFFSET: usize = $offset; + #[inline] pub(crate) fn read( io: &T, From e40d2b26167200b99fa4fb1df15d4c870489c82e Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 18 Jul 2025 16:26:13 +0900 Subject: [PATCH 00909/11391] gpu: nova-core: register: fix documentation and indentation Fix a few documentation inconsistencies, and harmonize indentation where possible. Reviewed-by: Daniel Almeida Reviewed-by: Lyude Paul Link: https://lore.kernel.org/r/20250718-nova-regs-v2-8-7b6a762aa1cd@nvidia.com Signed-off-by: Alexandre Courbot --- drivers/gpu/nova-core/regs/macros.rs | 34 ++++++++-------------------- 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/nova-core/regs/macros.rs b/drivers/gpu/nova-core/regs/macros.rs index 3d4476cc2421..5b3a320de1d3 100644 --- a/drivers/gpu/nova-core/regs/macros.rs +++ b/drivers/gpu/nova-core/regs/macros.rs @@ -87,44 +87,28 @@ /// providing its own `completed` field. macro_rules! register { // Creates a register at a fixed offset of the MMIO space. - ( - $name:ident @ $offset:literal $(, $comment:literal)? { - $($fields:tt)* - } - ) => { + ($name:ident @ $offset:literal $(, $comment:literal)? { $($fields:tt)* } ) => { register!(@common $name $(, $comment)?); register!(@field_accessors $name { $($fields)* }); register!(@io $name @ $offset); }; - // Creates a alias register of fixed offset register `alias` with its own fields. - ( - $name:ident => $alias:ident $(, $comment:literal)? { - $($fields:tt)* - } - ) => { + // Creates an alias register of fixed offset register `alias` with its own fields. + ($name:ident => $alias:ident $(, $comment:literal)? { $($fields:tt)* } ) => { register!(@common $name $(, $comment)?); register!(@field_accessors $name { $($fields)* }); register!(@io $name @ $alias::OFFSET); }; // Creates a register at a relative offset from a base address. - ( - $name:ident @ + $offset:literal $(, $comment:literal)? { - $($fields:tt)* - } - ) => { + ($name:ident @ + $offset:literal $(, $comment:literal)? { $($fields:tt)* } ) => { register!(@common $name $(, $comment)?); register!(@field_accessors $name { $($fields)* }); register!(@io $name @ + $offset); }; - // Creates a alias register of relative offset register `alias` with its own fields. - ( - $name:ident => + $alias:ident $(, $comment:literal)? { - $($fields:tt)* - } - ) => { + // Creates an alias register of relative offset register `alias` with its own fields. + ($name:ident => + $alias:ident $(, $comment:literal)? { $($fields:tt)* } ) => { register!(@common $name $(, $comment)?); register!(@field_accessors $name { $($fields)* }); register!(@io $name @ + $alias::OFFSET); @@ -259,7 +243,7 @@ impl $name { { |f| <$into_type>::from(f as $type) } $into_type => $into_type $(, $comment)?;); }; - // Shortcut for fields defined as non-`bool` without the `=>` or `?=>` syntax. + // Shortcut for non-boolean fields defined without the `=>` or `?=>` syntax. ( @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt $(, $comment:literal)?; @@ -310,7 +294,7 @@ pub(crate) fn [](mut self, value: $to_type) -> Self { ); }; - // Creates the IO accessors for a fixed offset register. + // Generates the IO accessors for a fixed offset register. (@io $name:ident @ $offset:expr) => { #[allow(dead_code)] impl $name { @@ -344,7 +328,7 @@ pub(crate) fn alter( } }; - // Create the IO accessors for a relative offset register. + // Generates the IO accessors for a relative offset register. (@io $name:ident @ + $offset:literal) => { #[allow(dead_code)] impl $name { From 9b2379f02423801d372bc588d38b62a1fa6cd05f Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 18 Jul 2025 16:26:14 +0900 Subject: [PATCH 00910/11391] gpu: nova-core: register: add missing doccomments for fixed registers I/O accessors Add the missing doccomments for these accessors, as having a bit of inline documentation is always helpful. Reviewed-by: Daniel Almeida Reviewed-by: Lyude Paul Link: https://lore.kernel.org/r/20250718-nova-regs-v2-9-7b6a762aa1cd@nvidia.com Signed-off-by: Alexandre Courbot --- drivers/gpu/nova-core/regs/macros.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/nova-core/regs/macros.rs b/drivers/gpu/nova-core/regs/macros.rs index 5b3a320de1d3..d5ce7cb67f21 100644 --- a/drivers/gpu/nova-core/regs/macros.rs +++ b/drivers/gpu/nova-core/regs/macros.rs @@ -300,6 +300,7 @@ pub(crate) fn [](mut self, value: $to_type) -> Self { impl $name { pub(crate) const OFFSET: usize = $offset; + /// Read the register from its address in `io`. #[inline] pub(crate) fn read(io: &T) -> Self where T: ::core::ops::Deref>, @@ -307,6 +308,7 @@ pub(crate) fn read(io: &T) -> Self where Self(io.read32($offset)) } + /// Write the value contained in `self` to the register address in `io`. #[inline] pub(crate) fn write(self, io: &T) where T: ::core::ops::Deref>, @@ -314,6 +316,8 @@ pub(crate) fn write(self, io: &T) where io.write32(self.0, $offset) } + /// Read the register from its address in `io` and run `f` on its value to obtain a new + /// value to write back. #[inline] pub(crate) fn alter( io: &T, From 7a9cb3dfb07d3e29c0eeebb26b11a34a19a889a4 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 18 Jul 2025 16:26:15 +0900 Subject: [PATCH 00911/11391] gpu: nova-core: register: add fields dispatcher internal rule Fields are complex and cumbersome to match in a rule, and were only captured in order to generate the field accessors. However, there are other places (like the `Debug` and `Default` implementations) where we would benefit from having access to at least some of the field information, but refrained from doing so because it would have meant matching the whole fields in a rule more complex than we need. Introduce a new `@fields_dispatcher` internal rule that captures all the field information and passes it to `@field_accessors`. It does not provide any functional change in itself, but allows us to reuse the captured field information partially to provide better `Debug` and `Default` implementations in following patches. Reviewed-by: Daniel Almeida Reviewed-by: Lyude Paul Link: https://lore.kernel.org/r/20250718-nova-regs-v2-10-7b6a762aa1cd@nvidia.com Signed-off-by: Alexandre Courbot --- drivers/gpu/nova-core/regs/macros.rs | 42 +++++++++++++++++++++------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/nova-core/regs/macros.rs b/drivers/gpu/nova-core/regs/macros.rs index d5ce7cb67f21..ff2deca6b1f3 100644 --- a/drivers/gpu/nova-core/regs/macros.rs +++ b/drivers/gpu/nova-core/regs/macros.rs @@ -88,37 +88,33 @@ macro_rules! register { // Creates a register at a fixed offset of the MMIO space. ($name:ident @ $offset:literal $(, $comment:literal)? { $($fields:tt)* } ) => { - register!(@common $name $(, $comment)?); - register!(@field_accessors $name { $($fields)* }); + register!(@core $name $(, $comment)? { $($fields)* } ); register!(@io $name @ $offset); }; // Creates an alias register of fixed offset register `alias` with its own fields. ($name:ident => $alias:ident $(, $comment:literal)? { $($fields:tt)* } ) => { - register!(@common $name $(, $comment)?); - register!(@field_accessors $name { $($fields)* }); + register!(@core $name $(, $comment)? { $($fields)* } ); register!(@io $name @ $alias::OFFSET); }; // Creates a register at a relative offset from a base address. ($name:ident @ + $offset:literal $(, $comment:literal)? { $($fields:tt)* } ) => { - register!(@common $name $(, $comment)?); - register!(@field_accessors $name { $($fields)* }); + register!(@core $name $(, $comment)? { $($fields)* } ); register!(@io $name @ + $offset); }; // Creates an alias register of relative offset register `alias` with its own fields. ($name:ident => + $alias:ident $(, $comment:literal)? { $($fields:tt)* } ) => { - register!(@common $name $(, $comment)?); - register!(@field_accessors $name { $($fields)* }); + register!(@core $name $(, $comment)? { $($fields)* } ); register!(@io $name @ + $alias::OFFSET); }; // All rules below are helpers. // Defines the wrapper `$name` type, as well as its relevant implementations (`Debug`, `BitOr`, - // and conversion to regular `u32`). - (@common $name:ident $(, $comment:literal)?) => { + // and conversion to the value type) and field accessor methods. + (@core $name:ident $(, $comment:literal)? { $($fields:tt)* }) => { $( #[doc=$comment] )? @@ -149,6 +145,32 @@ fn from(reg: $name) -> u32 { reg.0 } } + + register!(@fields_dispatcher $name { $($fields)* }); + }; + + // Captures the fields and passes them to all the implementers that require field information. + // + // Used to simplify the matching rules for implementers, so they don't need to match the entire + // complex fields rule even though they only make use of part of it. + (@fields_dispatcher $name:ident { + $($hi:tt:$lo:tt $field:ident as $type:tt + $(?=> $try_into_type:ty)? + $(=> $into_type:ty)? + $(, $comment:literal)? + ; + )* + } + ) => { + register!(@field_accessors $name { + $( + $hi:$lo $field as $type + $(?=> $try_into_type)? + $(=> $into_type)? + $(, $comment)? + ; + )* + }); }; // Defines all the field getter/methods methods for `$name`. From 6ecd6b73e0845e2a1ba0d4da273c7cc7c21c88db Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 18 Jul 2025 16:26:16 +0900 Subject: [PATCH 00912/11391] gpu: nova-core: register: improve `Debug` implementation Now that we have an internal rule to dispatch field information where needed, use it to generate a better `Debug` implementation where the raw hexadecimal value of the register is displayed, as well as the `Debug` values of its individual fields. Reviewed-by: Daniel Almeida Reviewed-by: Lyude Paul Link: https://lore.kernel.org/r/20250718-nova-regs-v2-11-7b6a762aa1cd@nvidia.com Signed-off-by: Alexandre Courbot --- drivers/gpu/nova-core/regs/macros.rs | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/nova-core/regs/macros.rs b/drivers/gpu/nova-core/regs/macros.rs index ff2deca6b1f3..c966e58b775d 100644 --- a/drivers/gpu/nova-core/regs/macros.rs +++ b/drivers/gpu/nova-core/regs/macros.rs @@ -122,16 +122,6 @@ macro_rules! register { #[derive(Clone, Copy, Default)] pub(crate) struct $name(u32); - // TODO[REGA]: display the raw hex value, then the value of all the fields. This requires - // matching the fields, which will complexify the syntax considerably... - impl ::core::fmt::Debug for $name { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - f.debug_tuple(stringify!($name)) - .field(&format_args!("0x{0:x}", &self.0)) - .finish() - } - } - impl ::core::ops::BitOr for $name { type Output = Self; @@ -171,6 +161,7 @@ fn from(reg: $name) -> u32 { ; )* }); + register!(@debug $name { $($field;)* }); }; // Defines all the field getter/methods methods for `$name`. @@ -316,6 +307,20 @@ pub(crate) fn [](mut self, value: $to_type) -> Self { ); }; + // Generates the `Debug` implementation for `$name`. + (@debug $name:ident { $($field:ident;)* }) => { + impl ::core::fmt::Debug for $name { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct(stringify!($name)) + .field("", &format_args!("{:#x}", &self.0)) + $( + .field(stringify!($field), &self.$field()) + )* + .finish() + } + } + }; + // Generates the IO accessors for a fixed offset register. (@io $name:ident @ $offset:expr) => { #[allow(dead_code)] From 3fa145bef533f899ed6de641fe99c70028e28481 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 18 Jul 2025 16:26:17 +0900 Subject: [PATCH 00913/11391] gpu: nova-core: register: generate correct `Default` implementation The `Default` implementation of a register should be the aggregate of the default values of all its fields, and not simply be zeroed. Reviewed-by: Daniel Almeida Reviewed-by: Lyude Paul Link: https://lore.kernel.org/r/20250718-nova-regs-v2-12-7b6a762aa1cd@nvidia.com Signed-off-by: Alexandre Courbot --- drivers/gpu/nova-core/regs/macros.rs | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/nova-core/regs/macros.rs b/drivers/gpu/nova-core/regs/macros.rs index c966e58b775d..e43e1ab7ae2e 100644 --- a/drivers/gpu/nova-core/regs/macros.rs +++ b/drivers/gpu/nova-core/regs/macros.rs @@ -112,14 +112,14 @@ macro_rules! register { // All rules below are helpers. - // Defines the wrapper `$name` type, as well as its relevant implementations (`Debug`, `BitOr`, - // and conversion to the value type) and field accessor methods. + // Defines the wrapper `$name` type, as well as its relevant implementations (`Debug`, + // `Default`, `BitOr`, and conversion to the value type) and field accessor methods. (@core $name:ident $(, $comment:literal)? { $($fields:tt)* }) => { $( #[doc=$comment] )? #[repr(transparent)] - #[derive(Clone, Copy, Default)] + #[derive(Clone, Copy)] pub(crate) struct $name(u32); impl ::core::ops::BitOr for $name { @@ -162,6 +162,7 @@ fn from(reg: $name) -> u32 { )* }); register!(@debug $name { $($field;)* }); + register!(@default $name { $($field;)* }); }; // Defines all the field getter/methods methods for `$name`. @@ -321,6 +322,25 @@ fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { } }; + // Generates the `Default` implementation for `$name`. + (@default $name:ident { $($field:ident;)* }) => { + /// Returns a value for the register where all fields are set to their default value. + impl ::core::default::Default for $name { + fn default() -> Self { + #[allow(unused_mut)] + let mut value = Self(Default::default()); + + ::kernel::macros::paste!( + $( + value.[](Default::default()); + )* + ); + + value + } + } + }; + // Generates the IO accessors for a fixed offset register. (@io $name:ident @ $offset:expr) => { #[allow(dead_code)] From fcdce54d645a0779892faaed1209105350e15d92 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 18 Jul 2025 16:26:18 +0900 Subject: [PATCH 00914/11391] gpu: nova-core: register: split @io rule into fixed and relative versions We used the same @io rule with different patterns to define both the fixed and relative I/O accessors. This can be confusing as the matching rules are very similar. Since all call sites know which version they want to call, split @io into @io_fixed and @io_relative to remove any ambiguity. Reviewed-by: Daniel Almeida Reviewed-by: Lyude Paul Link: https://lore.kernel.org/r/20250718-nova-regs-v2-13-7b6a762aa1cd@nvidia.com Signed-off-by: Alexandre Courbot --- drivers/gpu/nova-core/regs/macros.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/nova-core/regs/macros.rs b/drivers/gpu/nova-core/regs/macros.rs index e43e1ab7ae2e..432af02b3378 100644 --- a/drivers/gpu/nova-core/regs/macros.rs +++ b/drivers/gpu/nova-core/regs/macros.rs @@ -89,25 +89,25 @@ macro_rules! register { // Creates a register at a fixed offset of the MMIO space. ($name:ident @ $offset:literal $(, $comment:literal)? { $($fields:tt)* } ) => { register!(@core $name $(, $comment)? { $($fields)* } ); - register!(@io $name @ $offset); + register!(@io_fixed $name @ $offset); }; // Creates an alias register of fixed offset register `alias` with its own fields. ($name:ident => $alias:ident $(, $comment:literal)? { $($fields:tt)* } ) => { register!(@core $name $(, $comment)? { $($fields)* } ); - register!(@io $name @ $alias::OFFSET); + register!(@io_fixed $name @ $alias::OFFSET); }; // Creates a register at a relative offset from a base address. ($name:ident @ + $offset:literal $(, $comment:literal)? { $($fields:tt)* } ) => { register!(@core $name $(, $comment)? { $($fields)* } ); - register!(@io $name @ + $offset); + register!(@io_relative $name @ + $offset); }; // Creates an alias register of relative offset register `alias` with its own fields. ($name:ident => + $alias:ident $(, $comment:literal)? { $($fields:tt)* } ) => { register!(@core $name $(, $comment)? { $($fields)* } ); - register!(@io $name @ + $alias::OFFSET); + register!(@io_relative $name @ + $alias::OFFSET); }; // All rules below are helpers. @@ -342,7 +342,7 @@ fn default() -> Self { }; // Generates the IO accessors for a fixed offset register. - (@io $name:ident @ $offset:expr) => { + (@io_fixed $name:ident @ $offset:expr) => { #[allow(dead_code)] impl $name { pub(crate) const OFFSET: usize = $offset; @@ -380,7 +380,7 @@ pub(crate) fn alter( }; // Generates the IO accessors for a relative offset register. - (@io $name:ident @ + $offset:literal) => { + (@io_relative $name:ident @ + $offset:literal) => { #[allow(dead_code)] impl $name { pub(crate) const OFFSET: usize = $offset; From c6bc4225279d9a6eff8aafc94347183b2babc52a Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 18 Jul 2025 16:26:19 +0900 Subject: [PATCH 00915/11391] gpu: nova-core: register: use #[inline(always)] for all methods These methods should always be inlined, so use the strongest compiler hint that exists to maximize the chance they will indeed be. Reviewed-by: Daniel Almeida Reviewed-by: Lyude Paul Link: https://lore.kernel.org/r/20250718-nova-regs-v2-14-7b6a762aa1cd@nvidia.com Signed-off-by: Alexandre Courbot --- drivers/gpu/nova-core/regs/macros.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/nova-core/regs/macros.rs b/drivers/gpu/nova-core/regs/macros.rs index 432af02b3378..200fbe847571 100644 --- a/drivers/gpu/nova-core/regs/macros.rs +++ b/drivers/gpu/nova-core/regs/macros.rs @@ -280,7 +280,7 @@ impl $name { #[doc="Returns the value of this field:"] #[doc=$comment] )? - #[inline] + #[inline(always)] pub(crate) fn $field(self) -> $res_type { ::kernel::macros::paste!( const MASK: u32 = $name::[<$field:upper _MASK>]; @@ -296,7 +296,7 @@ pub(crate) fn $field(self) -> $res_type { #[doc="Sets the value of this field:"] #[doc=$comment] )? - #[inline] + #[inline(always)] pub(crate) fn [](mut self, value: $to_type) -> Self { const MASK: u32 = $name::[<$field:upper _MASK>]; const SHIFT: u32 = $name::[<$field:upper _SHIFT>]; @@ -348,7 +348,7 @@ impl $name { pub(crate) const OFFSET: usize = $offset; /// Read the register from its address in `io`. - #[inline] + #[inline(always)] pub(crate) fn read(io: &T) -> Self where T: ::core::ops::Deref>, { @@ -356,7 +356,7 @@ pub(crate) fn read(io: &T) -> Self where } /// Write the value contained in `self` to the register address in `io`. - #[inline] + #[inline(always)] pub(crate) fn write(self, io: &T) where T: ::core::ops::Deref>, { @@ -365,7 +365,7 @@ pub(crate) fn write(self, io: &T) where /// Read the register from its address in `io` and run `f` on its value to obtain a new /// value to write back. - #[inline] + #[inline(always)] pub(crate) fn alter( io: &T, f: F, @@ -385,7 +385,7 @@ pub(crate) fn alter( impl $name { pub(crate) const OFFSET: usize = $offset; - #[inline] + #[inline(always)] pub(crate) fn read( io: &T, base: usize, @@ -395,7 +395,7 @@ pub(crate) fn read( Self(io.read32(base + $offset)) } - #[inline] + #[inline(always)] pub(crate) fn write( self, io: &T, @@ -406,7 +406,7 @@ pub(crate) fn write( io.write32(self.0, base + $offset) } - #[inline] + #[inline(always)] pub(crate) fn alter( io: &T, base: usize, From af10924fc471d1c693b8689249f53ea10b0519b7 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 18 Jul 2025 16:26:20 +0900 Subject: [PATCH 00916/11391] gpu: nova-core: register: redesign relative registers The relative registers are currently very unsafe to use: callers can specify any constant as the base address for access, meaning they can effectively interpret any I/O address as any relative register. Ideally, valid base addresses for a family of registers should be explicitly defined in the code, and could only be used with the relevant registers This patch changes the relative register declaration from e.g.: register!(CPU_CTL @ +0x0000010, "CPU core control" { 0:0 start as bool, "Start the CPU core"; }); into: register!(CPU_CTL @ CpuCtlBase[0x10], "CPU core control" { 0:0 start as bool, "Start the CPU core"; }); Where `CpuCtlBase` is the name of a ZST used as a parameter of the `RegisterBase<>` trait to define a trait unique to a class of register. This specialized trait is then implemented for every type that provides a valid base address, enabling said types to be passed as the base address provider for the register's I/O accessor methods. This design thus makes it impossible to pass an unexpected base address to a relative register, and, since the valid bases are all known at compile-time, also guarantees that all I/O accesses are done within the valid bounds of the I/O range. [acourbot@nvidia.com: add example in the commit log.] Reviewed-by: Lyude Paul Link: https://lore.kernel.org/r/20250718-nova-regs-v2-15-7b6a762aa1cd@nvidia.com Signed-off-by: Alexandre Courbot --- Documentation/gpu/nova/core/todo.rst | 1 - drivers/gpu/nova-core/falcon.rs | 67 +++++----- drivers/gpu/nova-core/falcon/gsp.rs | 12 +- drivers/gpu/nova-core/falcon/hal/ga102.rs | 14 +- drivers/gpu/nova-core/falcon/sec2.rs | 9 +- drivers/gpu/nova-core/regs.rs | 50 +++---- drivers/gpu/nova-core/regs/macros.rs | 156 ++++++++++++++++++---- 7 files changed, 212 insertions(+), 97 deletions(-) diff --git a/Documentation/gpu/nova/core/todo.rst b/Documentation/gpu/nova/core/todo.rst index 894a1e9c3741..a1d12c1b289d 100644 --- a/Documentation/gpu/nova/core/todo.rst +++ b/Documentation/gpu/nova/core/todo.rst @@ -131,7 +131,6 @@ crate so it can be used by other components as well. Features desired before this happens: -* Relative register with build-time base address validation, * Arrays of registers with build-time index validation, * Make I/O optional I/O (for field values that are not registers), * Support other sizes than `u32`, diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs index 50437c67c14a..67265a0b5d7b 100644 --- a/drivers/gpu/nova-core/falcon.rs +++ b/drivers/gpu/nova-core/falcon.rs @@ -14,6 +14,7 @@ use crate::driver::Bar0; use crate::gpu::Chipset; use crate::regs; +use crate::regs::macros::RegisterBase; use crate::util; pub(crate) mod gsp; @@ -274,10 +275,16 @@ fn from(value: bool) -> Self { } } -/// Trait defining the parameters of a given Falcon instance. -pub(crate) trait FalconEngine: Sync { - /// Base I/O address for the falcon, relative from which its registers are accessed. - const BASE: usize; +/// Type used to represent the `PFALCON` registers address base for a given falcon engine. +pub(crate) struct PFalconBase(()); + +/// Trait defining the parameters of a given Falcon engine. +/// +/// Each engine provides one base for `PFALCON` and `PFALCON2` registers. The `ID` constant is used +/// to identify a given Falcon instance with register I/O methods. +pub(crate) trait FalconEngine: Sync + RegisterBase + Sized { + /// Singleton of the engine, used to identify it with register I/O methods. + const ID: Self; } /// Represents a portion of the firmware to be loaded into a particular memory (e.g. IMEM or DMEM). @@ -343,13 +350,13 @@ pub(crate) fn new( bar: &Bar0, need_riscv: bool, ) -> Result { - let hwcfg1 = regs::NV_PFALCON_FALCON_HWCFG1::read(bar, E::BASE); + let hwcfg1 = regs::NV_PFALCON_FALCON_HWCFG1::read(bar, &E::ID); // Check that the revision and security model contain valid values. let _ = hwcfg1.core_rev()?; let _ = hwcfg1.security_model()?; if need_riscv { - let hwcfg2 = regs::NV_PFALCON_FALCON_HWCFG2::read(bar, E::BASE); + let hwcfg2 = regs::NV_PFALCON_FALCON_HWCFG2::read(bar, &E::ID); if !hwcfg2.riscv() { dev_err!( dev, @@ -369,7 +376,7 @@ pub(crate) fn new( fn reset_wait_mem_scrubbing(&self, bar: &Bar0) -> Result { // TIMEOUT: memory scrubbing should complete in less than 20ms. util::wait_on(Delta::from_millis(20), || { - if regs::NV_PFALCON_FALCON_HWCFG2::read(bar, E::BASE).mem_scrubbing_done() { + if regs::NV_PFALCON_FALCON_HWCFG2::read(bar, &E::ID).mem_scrubbing_done() { Some(()) } else { None @@ -379,12 +386,12 @@ fn reset_wait_mem_scrubbing(&self, bar: &Bar0) -> Result { /// Reset the falcon engine. fn reset_eng(&self, bar: &Bar0) -> Result { - let _ = regs::NV_PFALCON_FALCON_HWCFG2::read(bar, E::BASE); + let _ = regs::NV_PFALCON_FALCON_HWCFG2::read(bar, &E::ID); // According to OpenRM's `kflcnPreResetWait_GA102` documentation, HW sometimes does not set // RESET_READY so a non-failing timeout is used. let _ = util::wait_on(Delta::from_micros(150), || { - let r = regs::NV_PFALCON_FALCON_HWCFG2::read(bar, E::BASE); + let r = regs::NV_PFALCON_FALCON_HWCFG2::read(bar, &E::ID); if r.reset_ready() { Some(()) } else { @@ -392,13 +399,13 @@ fn reset_eng(&self, bar: &Bar0) -> Result { } }); - regs::NV_PFALCON_FALCON_ENGINE::alter(bar, E::BASE, |v| v.set_reset(true)); + regs::NV_PFALCON_FALCON_ENGINE::alter(bar, &E::ID, |v| v.set_reset(true)); // TODO[DLAY]: replace with udelay() or equivalent once available. // TIMEOUT: falcon engine should not take more than 10us to reset. let _: Result = util::wait_on(Delta::from_micros(10), || None); - regs::NV_PFALCON_FALCON_ENGINE::alter(bar, E::BASE, |v| v.set_reset(false)); + regs::NV_PFALCON_FALCON_ENGINE::alter(bar, &E::ID, |v| v.set_reset(false)); self.reset_wait_mem_scrubbing(bar)?; @@ -413,7 +420,7 @@ pub(crate) fn reset(&self, bar: &Bar0) -> Result { regs::NV_PFALCON_FALCON_RM::default() .set_value(regs::NV_PMC_BOOT_0::read(bar).into()) - .write(bar, E::BASE); + .write(bar, &E::ID); Ok(()) } @@ -464,10 +471,10 @@ fn dma_wr>( regs::NV_PFALCON_FALCON_DMATRFBASE::default() .set_base((dma_start >> 8) as u32) - .write(bar, E::BASE); + .write(bar, &E::ID); regs::NV_PFALCON_FALCON_DMATRFBASE1::default() .set_base((dma_start >> 40) as u16) - .write(bar, E::BASE); + .write(bar, &E::ID); let cmd = regs::NV_PFALCON_FALCON_DMATRFCMD::default() .set_size(DmaTrfCmdSize::Size256B) @@ -478,17 +485,17 @@ fn dma_wr>( // Perform a transfer of size `DMA_LEN`. regs::NV_PFALCON_FALCON_DMATRFMOFFS::default() .set_offs(load_offsets.dst_start + pos) - .write(bar, E::BASE); + .write(bar, &E::ID); regs::NV_PFALCON_FALCON_DMATRFFBOFFS::default() .set_offs(src_start + pos) - .write(bar, E::BASE); - cmd.write(bar, E::BASE); + .write(bar, &E::ID); + cmd.write(bar, &E::ID); // Wait for the transfer to complete. // TIMEOUT: arbitrarily large value, no DMA transfer to the falcon's small memories // should ever take that long. util::wait_on(Delta::from_secs(2), || { - let r = regs::NV_PFALCON_FALCON_DMATRFCMD::read(bar, E::BASE); + let r = regs::NV_PFALCON_FALCON_DMATRFCMD::read(bar, &E::ID); if r.idle() { Some(()) } else { @@ -502,9 +509,9 @@ fn dma_wr>( /// Perform a DMA load into `IMEM` and `DMEM` of `fw`, and prepare the falcon to run it. pub(crate) fn dma_load>(&self, bar: &Bar0, fw: &F) -> Result { - regs::NV_PFALCON_FBIF_CTL::alter(bar, E::BASE, |v| v.set_allow_phys_no_ctx(true)); - regs::NV_PFALCON_FALCON_DMACTL::default().write(bar, E::BASE); - regs::NV_PFALCON_FBIF_TRANSCFG::alter(bar, E::BASE, |v| { + regs::NV_PFALCON_FBIF_CTL::alter(bar, &E::ID, |v| v.set_allow_phys_no_ctx(true)); + regs::NV_PFALCON_FALCON_DMACTL::default().write(bar, &E::ID); + regs::NV_PFALCON_FBIF_TRANSCFG::alter(bar, &E::ID, |v| { v.set_target(FalconFbifTarget::CoherentSysmem) .set_mem_type(FalconFbifMemType::Physical) }); @@ -517,7 +524,7 @@ pub(crate) fn dma_load>(&self, bar: &Bar0, fw: &F) // Set `BootVec` to start of non-secure code. regs::NV_PFALCON_FALCON_BOOTVEC::default() .set_value(fw.boot_addr()) - .write(bar, E::BASE); + .write(bar, &E::ID); Ok(()) } @@ -538,27 +545,27 @@ pub(crate) fn boot( if let Some(mbox0) = mbox0 { regs::NV_PFALCON_FALCON_MAILBOX0::default() .set_value(mbox0) - .write(bar, E::BASE); + .write(bar, &E::ID); } if let Some(mbox1) = mbox1 { regs::NV_PFALCON_FALCON_MAILBOX1::default() .set_value(mbox1) - .write(bar, E::BASE); + .write(bar, &E::ID); } - match regs::NV_PFALCON_FALCON_CPUCTL::read(bar, E::BASE).alias_en() { + match regs::NV_PFALCON_FALCON_CPUCTL::read(bar, &E::ID).alias_en() { true => regs::NV_PFALCON_FALCON_CPUCTL_ALIAS::default() .set_startcpu(true) - .write(bar, E::BASE), + .write(bar, &E::ID), false => regs::NV_PFALCON_FALCON_CPUCTL::default() .set_startcpu(true) - .write(bar, E::BASE), + .write(bar, &E::ID), } // TIMEOUT: arbitrarily large value, firmwares should complete in less than 2 seconds. util::wait_on(Delta::from_secs(2), || { - let r = regs::NV_PFALCON_FALCON_CPUCTL::read(bar, E::BASE); + let r = regs::NV_PFALCON_FALCON_CPUCTL::read(bar, &E::ID); if r.halted() { Some(()) } else { @@ -567,8 +574,8 @@ pub(crate) fn boot( })?; let (mbox0, mbox1) = ( - regs::NV_PFALCON_FALCON_MAILBOX0::read(bar, E::BASE).value(), - regs::NV_PFALCON_FALCON_MAILBOX1::read(bar, E::BASE).value(), + regs::NV_PFALCON_FALCON_MAILBOX0::read(bar, &E::ID).value(), + regs::NV_PFALCON_FALCON_MAILBOX1::read(bar, &E::ID).value(), ); Ok((mbox0, mbox1)) diff --git a/drivers/gpu/nova-core/falcon/gsp.rs b/drivers/gpu/nova-core/falcon/gsp.rs index d622e9a64470..0db9f94036a6 100644 --- a/drivers/gpu/nova-core/falcon/gsp.rs +++ b/drivers/gpu/nova-core/falcon/gsp.rs @@ -2,23 +2,27 @@ use crate::{ driver::Bar0, - falcon::{Falcon, FalconEngine}, - regs, + falcon::{Falcon, FalconEngine, PFalconBase}, + regs::{self, macros::RegisterBase}, }; /// Type specifying the `Gsp` falcon engine. Cannot be instantiated. pub(crate) struct Gsp(()); -impl FalconEngine for Gsp { +impl RegisterBase for Gsp { const BASE: usize = 0x00110000; } +impl FalconEngine for Gsp { + const ID: Self = Gsp(()); +} + impl Falcon { /// Clears the SWGEN0 bit in the Falcon's IRQ status clear register to /// allow GSP to signal CPU for processing new messages in message queue. pub(crate) fn clear_swgen0_intr(&self, bar: &Bar0) { regs::NV_PFALCON_FALCON_IRQSCLR::default() .set_swgen0(true) - .write(bar, Gsp::BASE); + .write(bar, &Gsp::ID); } } diff --git a/drivers/gpu/nova-core/falcon/hal/ga102.rs b/drivers/gpu/nova-core/falcon/hal/ga102.rs index 52c33d3f22a8..3fdacd19322d 100644 --- a/drivers/gpu/nova-core/falcon/hal/ga102.rs +++ b/drivers/gpu/nova-core/falcon/hal/ga102.rs @@ -16,15 +16,15 @@ use super::FalconHal; fn select_core_ga102(bar: &Bar0) -> Result { - let bcr_ctrl = regs::NV_PRISCV_RISCV_BCR_CTRL::read(bar, E::BASE); + let bcr_ctrl = regs::NV_PRISCV_RISCV_BCR_CTRL::read(bar, &E::ID); if bcr_ctrl.core_select() != PeregrineCoreSelect::Falcon { regs::NV_PRISCV_RISCV_BCR_CTRL::default() .set_core_select(PeregrineCoreSelect::Falcon) - .write(bar, E::BASE); + .write(bar, &E::ID); // TIMEOUT: falcon core should take less than 10ms to report being enabled. util::wait_on(Delta::from_millis(10), || { - let r = regs::NV_PRISCV_RISCV_BCR_CTRL::read(bar, E::BASE); + let r = regs::NV_PRISCV_RISCV_BCR_CTRL::read(bar, &E::ID); if r.valid() { Some(()) } else { @@ -76,16 +76,16 @@ fn signature_reg_fuse_version_ga102( fn program_brom_ga102(bar: &Bar0, params: &FalconBromParams) -> Result { regs::NV_PFALCON2_FALCON_BROM_PARAADDR::default() .set_value(params.pkc_data_offset) - .write(bar, E::BASE); + .write(bar, &E::ID); regs::NV_PFALCON2_FALCON_BROM_ENGIDMASK::default() .set_value(u32::from(params.engine_id_mask)) - .write(bar, E::BASE); + .write(bar, &E::ID); regs::NV_PFALCON2_FALCON_BROM_CURR_UCODE_ID::default() .set_ucode_id(params.ucode_id) - .write(bar, E::BASE); + .write(bar, &E::ID); regs::NV_PFALCON2_FALCON_MOD_SEL::default() .set_algo(FalconModSelAlgo::Rsa3k) - .write(bar, E::BASE); + .write(bar, &E::ID); Ok(()) } diff --git a/drivers/gpu/nova-core/falcon/sec2.rs b/drivers/gpu/nova-core/falcon/sec2.rs index 5147d9e2a7fe..dbc486a712ff 100644 --- a/drivers/gpu/nova-core/falcon/sec2.rs +++ b/drivers/gpu/nova-core/falcon/sec2.rs @@ -1,10 +1,15 @@ // SPDX-License-Identifier: GPL-2.0 -use crate::falcon::FalconEngine; +use crate::falcon::{FalconEngine, PFalconBase}; +use crate::regs::macros::RegisterBase; /// Type specifying the `Sec2` falcon engine. Cannot be instantiated. pub(crate) struct Sec2(()); -impl FalconEngine for Sec2 { +impl RegisterBase for Sec2 { const BASE: usize = 0x00840000; } + +impl FalconEngine for Sec2 { + const ID: Self = Sec2(()); +} diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs index c8f8adb24f6e..7730c5a475d5 100644 --- a/drivers/gpu/nova-core/regs.rs +++ b/drivers/gpu/nova-core/regs.rs @@ -5,11 +5,11 @@ #![allow(non_camel_case_types)] #[macro_use] -mod macros; +pub(crate) mod macros; use crate::falcon::{ DmaTrfCmdSize, FalconCoreRev, FalconCoreRevSubversion, FalconFbifMemType, FalconFbifTarget, - FalconModSelAlgo, FalconSecurityModel, PeregrineCoreSelect, + FalconModSelAlgo, FalconSecurityModel, PFalconBase, PeregrineCoreSelect, }; use crate::gpu::{Architecture, Chipset}; use kernel::prelude::*; @@ -195,24 +195,24 @@ pub(crate) fn vga_workspace_addr(self) -> Option { // PFALCON -register!(NV_PFALCON_FALCON_IRQSCLR @ +0x00000004 { +register!(NV_PFALCON_FALCON_IRQSCLR @ PFalconBase[0x00000004] { 4:4 halt as bool; 6:6 swgen0 as bool; }); -register!(NV_PFALCON_FALCON_MAILBOX0 @ +0x00000040 { +register!(NV_PFALCON_FALCON_MAILBOX0 @ PFalconBase[0x00000040] { 31:0 value as u32; }); -register!(NV_PFALCON_FALCON_MAILBOX1 @ +0x00000044 { +register!(NV_PFALCON_FALCON_MAILBOX1 @ PFalconBase[0x00000044] { 31:0 value as u32; }); -register!(NV_PFALCON_FALCON_RM @ +0x00000084 { +register!(NV_PFALCON_FALCON_RM @ PFalconBase[0x00000084] { 31:0 value as u32; }); -register!(NV_PFALCON_FALCON_HWCFG2 @ +0x000000f4 { +register!(NV_PFALCON_FALCON_HWCFG2 @ PFalconBase[0x000000f4] { 10:10 riscv as bool; 12:12 mem_scrubbing as bool, "Set to 0 after memory scrubbing is completed"; 31:31 reset_ready as bool, "Signal indicating that reset is completed (GA102+)"; @@ -225,17 +225,17 @@ pub(crate) fn mem_scrubbing_done(self) -> bool { } } -register!(NV_PFALCON_FALCON_CPUCTL @ +0x00000100 { +register!(NV_PFALCON_FALCON_CPUCTL @ PFalconBase[0x00000100] { 1:1 startcpu as bool; 4:4 halted as bool; 6:6 alias_en as bool; }); -register!(NV_PFALCON_FALCON_BOOTVEC @ +0x00000104 { +register!(NV_PFALCON_FALCON_BOOTVEC @ PFalconBase[0x00000104] { 31:0 value as u32; }); -register!(NV_PFALCON_FALCON_DMACTL @ +0x0000010c { +register!(NV_PFALCON_FALCON_DMACTL @ PFalconBase[0x0000010c] { 0:0 require_ctx as bool; 1:1 dmem_scrubbing as bool; 2:2 imem_scrubbing as bool; @@ -243,15 +243,15 @@ pub(crate) fn mem_scrubbing_done(self) -> bool { 7:7 secure_stat as bool; }); -register!(NV_PFALCON_FALCON_DMATRFBASE @ +0x00000110 { +register!(NV_PFALCON_FALCON_DMATRFBASE @ PFalconBase[0x00000110] { 31:0 base as u32; }); -register!(NV_PFALCON_FALCON_DMATRFMOFFS @ +0x00000114 { +register!(NV_PFALCON_FALCON_DMATRFMOFFS @ PFalconBase[0x00000114] { 23:0 offs as u32; }); -register!(NV_PFALCON_FALCON_DMATRFCMD @ +0x00000118 { +register!(NV_PFALCON_FALCON_DMATRFCMD @ PFalconBase[0x00000118] { 0:0 full as bool; 1:1 idle as bool; 3:2 sec as u8; @@ -262,60 +262,60 @@ pub(crate) fn mem_scrubbing_done(self) -> bool { 16:16 set_dmtag as u8; }); -register!(NV_PFALCON_FALCON_DMATRFFBOFFS @ +0x0000011c { +register!(NV_PFALCON_FALCON_DMATRFFBOFFS @ PFalconBase[0x0000011c] { 31:0 offs as u32; }); -register!(NV_PFALCON_FALCON_DMATRFBASE1 @ +0x00000128 { +register!(NV_PFALCON_FALCON_DMATRFBASE1 @ PFalconBase[0x00000128] { 8:0 base as u16; }); -register!(NV_PFALCON_FALCON_HWCFG1 @ +0x0000012c { +register!(NV_PFALCON_FALCON_HWCFG1 @ PFalconBase[0x0000012c] { 3:0 core_rev as u8 ?=> FalconCoreRev, "Core revision"; 5:4 security_model as u8 ?=> FalconSecurityModel, "Security model"; 7:6 core_rev_subversion as u8 ?=> FalconCoreRevSubversion, "Core revision subversion"; }); -register!(NV_PFALCON_FALCON_CPUCTL_ALIAS @ +0x00000130 { +register!(NV_PFALCON_FALCON_CPUCTL_ALIAS @ PFalconBase[0x00000130] { 1:1 startcpu as bool; }); // Actually known as `NV_PSEC_FALCON_ENGINE` and `NV_PGSP_FALCON_ENGINE` depending on the falcon // instance. -register!(NV_PFALCON_FALCON_ENGINE @ +0x000003c0 { +register!(NV_PFALCON_FALCON_ENGINE @ PFalconBase[0x000003c0] { 0:0 reset as bool; }); // TODO[REGA]: this is an array of registers. -register!(NV_PFALCON_FBIF_TRANSCFG @ +0x00000600 { +register!(NV_PFALCON_FBIF_TRANSCFG @ PFalconBase[0x00000600] { 1:0 target as u8 ?=> FalconFbifTarget; 2:2 mem_type as bool => FalconFbifMemType; }); -register!(NV_PFALCON_FBIF_CTL @ +0x00000624 { +register!(NV_PFALCON_FBIF_CTL @ PFalconBase[0x00000624] { 7:7 allow_phys_no_ctx as bool; }); -register!(NV_PFALCON2_FALCON_MOD_SEL @ +0x00001180 { +register!(NV_PFALCON2_FALCON_MOD_SEL @ PFalconBase[0x00001180] { 7:0 algo as u8 ?=> FalconModSelAlgo; }); -register!(NV_PFALCON2_FALCON_BROM_CURR_UCODE_ID @ +0x00001198 { +register!(NV_PFALCON2_FALCON_BROM_CURR_UCODE_ID @ PFalconBase[0x00001198] { 7:0 ucode_id as u8; }); -register!(NV_PFALCON2_FALCON_BROM_ENGIDMASK @ +0x0000119c { +register!(NV_PFALCON2_FALCON_BROM_ENGIDMASK @ PFalconBase[0x0000119c] { 31:0 value as u32; }); // TODO[REGA]: this is an array of registers. -register!(NV_PFALCON2_FALCON_BROM_PARAADDR @ +0x00001210 { +register!(NV_PFALCON2_FALCON_BROM_PARAADDR @ PFalconBase[0x00001210] { 31:0 value as u32; }); // PRISCV -register!(NV_PRISCV_RISCV_BCR_CTRL @ +0x00001668 { +register!(NV_PRISCV_RISCV_BCR_CTRL @ PFalconBase[0x00001668] { 0:0 valid as bool; 4:4 core_select as bool => PeregrineCoreSelect; 8:8 br_fetch as bool; diff --git a/drivers/gpu/nova-core/regs/macros.rs b/drivers/gpu/nova-core/regs/macros.rs index 200fbe847571..005ee7afe279 100644 --- a/drivers/gpu/nova-core/regs/macros.rs +++ b/drivers/gpu/nova-core/regs/macros.rs @@ -10,6 +10,16 @@ //! dedicated type for each register. Each such type comes with its own field accessors that can //! return an error if a field's value is invalid. +/// Trait providing a base address to be added to the offset of a relative register to obtain +/// its actual offset. +/// +/// The `T` generic argument is used to distinguish which base to use, in case a type provides +/// several bases. It is given to the `register!` macro to restrict the use of the register to +/// implementors of this particular variant. +pub(crate) trait RegisterBase { + const BASE: usize; +} + /// Defines a dedicated type for a register with an absolute offset, including getter and setter /// methods for its fields and methods to read and write it from an `Io` region. /// @@ -56,20 +66,6 @@ /// The documentation strings are optional. If present, they will be added to the type's /// definition, or the field getter and setter methods they are attached to. /// -/// Putting a `+` before the address of the register makes it relative to a base: the `read` and -/// `write` methods take a `base` argument that is added to the specified address before access: -/// -/// ```no_run -/// register!(CPU_CTL @ +0x0000010, "CPU core control" { -/// 0:0 start as bool, "Start the CPU core"; -/// }); -/// -/// // Flip the `start` switch for the CPU core which base address is at `CPU_BASE`. -/// let cpuctl = CPU_CTL::read(&bar, CPU_BASE); -/// pr_info!("CPU CTL: {:#x}", cpuctl); -/// cpuctl.set_start(true).write(&bar, CPU_BASE); -/// ``` -/// /// It is also possible to create a alias register by using the `=> ALIAS` syntax. This is useful /// for cases where a register's interpretation depends on the context: /// @@ -85,6 +81,87 @@ /// /// In this example, `SCRATCH_0_BOOT_STATUS` uses the same I/O address as `SCRATCH`, while also /// providing its own `completed` field. +/// +/// ## Relative registers +/// +/// A register can be defined as being accessible from a fixed offset of a provided base. For +/// instance, imagine the following I/O space: +/// +/// ```text +/// +-----------------------------+ +/// | ... | +/// | | +/// 0x100--->+------------CPU0-------------+ +/// | | +/// 0x110--->+-----------------------------+ +/// | CPU_CTL | +/// +-----------------------------+ +/// | ... | +/// | | +/// | | +/// 0x200--->+------------CPU1-------------+ +/// | | +/// 0x210--->+-----------------------------+ +/// | CPU_CTL | +/// +-----------------------------+ +/// | ... | +/// +-----------------------------+ +/// ``` +/// +/// `CPU0` and `CPU1` both have a `CPU_CTL` register that starts at offset `0x10` of their I/O +/// space segment. Since both instances of `CPU_CTL` share the same layout, we don't want to define +/// them twice and would prefer a way to select which one to use from a single definition +/// +/// This can be done using the `Base[Offset]` syntax when specifying the register's address. +/// +/// `Base` is an arbitrary type (typically a ZST) to be used as a generic parameter of the +/// [`RegisterBase`] trait to provide the base as a constant, i.e. each type providing a base for +/// this register needs to implement `RegisterBase`. Here is the above example translated +/// into code: +/// +/// ```no_run +/// // Type used to identify the base. +/// pub(crate) struct CpuCtlBase; +/// +/// // ZST describing `CPU0`. +/// struct Cpu0; +/// impl RegisterBase for Cpu0 { +/// const BASE: usize = 0x100; +/// } +/// // Singleton of `CPU0` used to identify it. +/// const CPU0: Cpu0 = Cpu0; +/// +/// // ZST describing `CPU1`. +/// struct Cpu1; +/// impl RegisterBase for Cpu1 { +/// const BASE: usize = 0x200; +/// } +/// // Singleton of `CPU1` used to identify it. +/// const CPU1: Cpu1 = Cpu1; +/// +/// // This makes `CPU_CTL` accessible from all implementors of `RegisterBase`. +/// register!(CPU_CTL @ CpuCtlBase[0x10], "CPU core control" { +/// 0:0 start as bool, "Start the CPU core"; +/// }); +/// +/// // The `read`, `write` and `alter` methods of relative registers take an extra `base` argument +/// // that is used to resolve its final address by adding its `BASE` to the offset of the +/// // register. +/// +/// // Start `CPU0`. +/// CPU_CTL::alter(bar, &CPU0, |r| r.set_start(true)); +/// +/// // Start `CPU1`. +/// CPU_CTL::alter(bar, &CPU1, |r| r.set_start(true)); +/// +/// // Aliases can also be defined for relative register. +/// register!(CPU_CTL_ALIAS => CpuCtlBase[CPU_CTL], "Alias to CPU core control" { +/// 1:1 alias_start as bool, "Start the aliased CPU core"; +/// }); +/// +/// // Start the aliased `CPU0`. +/// CPU_CTL_ALIAS::alter(bar, &CPU0, |r| r.set_alias_start(true)); +/// ``` macro_rules! register { // Creates a register at a fixed offset of the MMIO space. ($name:ident @ $offset:literal $(, $comment:literal)? { $($fields:tt)* } ) => { @@ -98,16 +175,16 @@ macro_rules! register { register!(@io_fixed $name @ $alias::OFFSET); }; - // Creates a register at a relative offset from a base address. - ($name:ident @ + $offset:literal $(, $comment:literal)? { $($fields:tt)* } ) => { + // Creates a register at a relative offset from a base address provider. + ($name:ident @ $base:ty [ $offset:literal ] $(, $comment:literal)? { $($fields:tt)* } ) => { register!(@core $name $(, $comment)? { $($fields)* } ); - register!(@io_relative $name @ + $offset); + register!(@io_relative $name @ $base [ $offset ]); }; // Creates an alias register of relative offset register `alias` with its own fields. - ($name:ident => + $alias:ident $(, $comment:literal)? { $($fields:tt)* } ) => { + ($name:ident => $base:ty [ $alias:ident ] $(, $comment:literal)? { $($fields:tt)* }) => { register!(@core $name $(, $comment)? { $($fields)* } ); - register!(@io_relative $name @ + $alias::OFFSET); + register!(@io_relative $name @ $base [ $alias::OFFSET ]); }; // All rules below are helpers. @@ -380,39 +457,62 @@ pub(crate) fn alter( }; // Generates the IO accessors for a relative offset register. - (@io_relative $name:ident @ + $offset:literal) => { + (@io_relative $name:ident @ $base:ty [ $offset:expr ]) => { #[allow(dead_code)] impl $name { pub(crate) const OFFSET: usize = $offset; + /// Read the register from `io`, using the base address provided by `base` and adding + /// the register's offset to it. #[inline(always)] - pub(crate) fn read( + pub(crate) fn read( io: &T, - base: usize, + #[allow(unused_variables)] + base: &B, ) -> Self where T: ::core::ops::Deref>, + B: crate::regs::macros::RegisterBase<$base>, { - Self(io.read32(base + $offset)) + const OFFSET: usize = $name::OFFSET; + + let value = io.read32( + >::BASE + OFFSET + ); + + Self(value) } + /// Write the value contained in `self` to `io`, using the base address provided by + /// `base` and adding the register's offset to it. #[inline(always)] - pub(crate) fn write( + pub(crate) fn write( self, io: &T, - base: usize, + #[allow(unused_variables)] + base: &B, ) where T: ::core::ops::Deref>, + B: crate::regs::macros::RegisterBase<$base>, { - io.write32(self.0, base + $offset) + const OFFSET: usize = $name::OFFSET; + + io.write32( + self.0, + >::BASE + OFFSET + ); } + /// Read the register from `io`, using the base address provided by `base` and adding + /// the register's offset to it, then run `f` on its value to obtain a new value to + /// write back. #[inline(always)] - pub(crate) fn alter( + pub(crate) fn alter( io: &T, - base: usize, + base: &B, f: F, ) where T: ::core::ops::Deref>, + B: crate::regs::macros::RegisterBase<$base>, F: ::core::ops::FnOnce(Self) -> Self, { let reg = f(Self::read(io, base)); From e617f3a3702ca1ca2a498edbad0b12ceadc27321 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 18 Jul 2025 16:26:21 +0900 Subject: [PATCH 00917/11391] gpu: nova-core: falcon: add distinct base address for PFALCON2 Falcon engines have two distinct register bases: `PFALCON` and `PFALCON2`. So far we assumed that `PFALCON2` was located at `PFALCON + 0x1000` because that is the case of most engines, but there are exceptions (NVDEC uses `0x1c00`). Fix this shortcoming by leveraging the redesigned relative registers definitions to assign a distinct `PFalcon2Base` base address to each falcon engine. Reviewed-by: Lyude Paul Link: https://lore.kernel.org/r/20250718-nova-regs-v2-16-7b6a762aa1cd@nvidia.com Signed-off-by: Alexandre Courbot --- drivers/gpu/nova-core/falcon.rs | 7 ++++++- drivers/gpu/nova-core/falcon/gsp.rs | 6 +++++- drivers/gpu/nova-core/falcon/sec2.rs | 6 +++++- drivers/gpu/nova-core/regs.rs | 12 +++++++----- 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs index 67265a0b5d7b..2ecdcc6b9b9d 100644 --- a/drivers/gpu/nova-core/falcon.rs +++ b/drivers/gpu/nova-core/falcon.rs @@ -278,11 +278,16 @@ fn from(value: bool) -> Self { /// Type used to represent the `PFALCON` registers address base for a given falcon engine. pub(crate) struct PFalconBase(()); +/// Type used to represent the `PFALCON2` registers address base for a given falcon engine. +pub(crate) struct PFalcon2Base(()); + /// Trait defining the parameters of a given Falcon engine. /// /// Each engine provides one base for `PFALCON` and `PFALCON2` registers. The `ID` constant is used /// to identify a given Falcon instance with register I/O methods. -pub(crate) trait FalconEngine: Sync + RegisterBase + Sized { +pub(crate) trait FalconEngine: + Sync + RegisterBase + RegisterBase + Sized +{ /// Singleton of the engine, used to identify it with register I/O methods. const ID: Self; } diff --git a/drivers/gpu/nova-core/falcon/gsp.rs b/drivers/gpu/nova-core/falcon/gsp.rs index 0db9f94036a6..f17599cb49fa 100644 --- a/drivers/gpu/nova-core/falcon/gsp.rs +++ b/drivers/gpu/nova-core/falcon/gsp.rs @@ -2,7 +2,7 @@ use crate::{ driver::Bar0, - falcon::{Falcon, FalconEngine, PFalconBase}, + falcon::{Falcon, FalconEngine, PFalcon2Base, PFalconBase}, regs::{self, macros::RegisterBase}, }; @@ -13,6 +13,10 @@ impl RegisterBase for Gsp { const BASE: usize = 0x00110000; } +impl RegisterBase for Gsp { + const BASE: usize = 0x00111000; +} + impl FalconEngine for Gsp { const ID: Self = Gsp(()); } diff --git a/drivers/gpu/nova-core/falcon/sec2.rs b/drivers/gpu/nova-core/falcon/sec2.rs index dbc486a712ff..815786c8480d 100644 --- a/drivers/gpu/nova-core/falcon/sec2.rs +++ b/drivers/gpu/nova-core/falcon/sec2.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 -use crate::falcon::{FalconEngine, PFalconBase}; +use crate::falcon::{FalconEngine, PFalcon2Base, PFalconBase}; use crate::regs::macros::RegisterBase; /// Type specifying the `Sec2` falcon engine. Cannot be instantiated. @@ -10,6 +10,10 @@ impl RegisterBase for Sec2 { const BASE: usize = 0x00840000; } +impl RegisterBase for Sec2 { + const BASE: usize = 0x00841000; +} + impl FalconEngine for Sec2 { const ID: Self = Sec2(()); } diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs index 7730c5a475d5..e55525916bad 100644 --- a/drivers/gpu/nova-core/regs.rs +++ b/drivers/gpu/nova-core/regs.rs @@ -9,7 +9,7 @@ use crate::falcon::{ DmaTrfCmdSize, FalconCoreRev, FalconCoreRevSubversion, FalconFbifMemType, FalconFbifTarget, - FalconModSelAlgo, FalconSecurityModel, PFalconBase, PeregrineCoreSelect, + FalconModSelAlgo, FalconSecurityModel, PFalcon2Base, PFalconBase, PeregrineCoreSelect, }; use crate::gpu::{Architecture, Chipset}; use kernel::prelude::*; @@ -296,20 +296,22 @@ pub(crate) fn mem_scrubbing_done(self) -> bool { 7:7 allow_phys_no_ctx as bool; }); -register!(NV_PFALCON2_FALCON_MOD_SEL @ PFalconBase[0x00001180] { +/* PFALCON2 */ + +register!(NV_PFALCON2_FALCON_MOD_SEL @ PFalcon2Base[0x00000180] { 7:0 algo as u8 ?=> FalconModSelAlgo; }); -register!(NV_PFALCON2_FALCON_BROM_CURR_UCODE_ID @ PFalconBase[0x00001198] { +register!(NV_PFALCON2_FALCON_BROM_CURR_UCODE_ID @ PFalcon2Base[0x00000198] { 7:0 ucode_id as u8; }); -register!(NV_PFALCON2_FALCON_BROM_ENGIDMASK @ PFalconBase[0x0000119c] { +register!(NV_PFALCON2_FALCON_BROM_ENGIDMASK @ PFalcon2Base[0x0000019c] { 31:0 value as u32; }); // TODO[REGA]: this is an array of registers. -register!(NV_PFALCON2_FALCON_BROM_PARAADDR @ PFalconBase[0x00001210] { +register!(NV_PFALCON2_FALCON_BROM_PARAADDR @ PFalcon2Base[0x00000210] { 31:0 value as u32; }); From 20ed4a8695b277c296e3a30306ef8551903e1e04 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 18 Jul 2025 16:26:22 +0900 Subject: [PATCH 00918/11391] gpu: nova-core: register: add support for register arrays Having registers that can be interpreted identically in a contiguous I/O area (or at least, following a given stride) is a common way to organize registers, and is used by NVIDIA hardware. Thus, add a way to simply and safely declare such a layout using the register!() macro. Build-time bound-checking is effective for array accesses performed with a constant. For cases where the index cannot be known at compile time, `try_` variants of the accessors are also made available that return `EINVAL` if the access is out-of-bounds. Reviewed-by: Daniel Almeida Reviewed-by: Lyude Paul Link: https://lore.kernel.org/r/20250718-nova-regs-v2-17-7b6a762aa1cd@nvidia.com Signed-off-by: Alexandre Courbot --- drivers/gpu/nova-core/gpu.rs | 2 +- drivers/gpu/nova-core/regs.rs | 15 ++- drivers/gpu/nova-core/regs/macros.rs | 195 +++++++++++++++++++++++++++ 3 files changed, 204 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index b5c9786619a9..8caecaf7dfb4 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -221,7 +221,7 @@ fn run_fwsec_frts( fwsec_frts.run(dev, falcon, bar)?; // SCRATCH_E contains the error code for FWSEC-FRTS. - let frts_status = regs::NV_PBUS_SW_SCRATCH_0E::read(bar).frts_err_code(); + let frts_status = regs::NV_PBUS_SW_SCRATCH_0E_FRTS_ERR::read(bar).frts_err_code(); if frts_status != 0 { dev_err!( dev, diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs index e55525916bad..c45de208055d 100644 --- a/drivers/gpu/nova-core/regs.rs +++ b/drivers/gpu/nova-core/regs.rs @@ -45,8 +45,10 @@ pub(crate) fn chipset(self) -> Result { // PBUS -// TODO[REGA]: this is an array of registers. -register!(NV_PBUS_SW_SCRATCH_0E@0x00001438 { +register!(NV_PBUS_SW_SCRATCH @ 0x00001400[64] {}); + +register!(NV_PBUS_SW_SCRATCH_0E_FRTS_ERR => NV_PBUS_SW_SCRATCH[0xe], + "scratch register 0xe used as FRTS firmware error code" { 31:16 frts_err_code as u16; }); @@ -124,13 +126,12 @@ pub(crate) fn higher_bound(self) -> u64 { 0:0 read_protection_level0 as bool, "Set after FWSEC lowers its protection level"; }); -// TODO[REGA]: This is an array of registers. -register!(NV_PGC6_AON_SECURE_SCRATCH_GROUP_05 @ 0x00118234 { - 31:0 value as u32; -}); +// OpenRM defines this as a register array, but doesn't specify its size and only uses its first +// element. Be conservative until we know the actual size or need to use more registers. +register!(NV_PGC6_AON_SECURE_SCRATCH_GROUP_05 @ 0x00118234[1] {}); register!( - NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_0_GFW_BOOT => NV_PGC6_AON_SECURE_SCRATCH_GROUP_05, + NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_0_GFW_BOOT => NV_PGC6_AON_SECURE_SCRATCH_GROUP_05[0], "Scratch group 05 register 0 used as GFW boot progress indicator" { 7:0 progress as u8, "Progress of GFW boot (0xff means completed)"; } diff --git a/drivers/gpu/nova-core/regs/macros.rs b/drivers/gpu/nova-core/regs/macros.rs index 005ee7afe279..f38177065c25 100644 --- a/drivers/gpu/nova-core/regs/macros.rs +++ b/drivers/gpu/nova-core/regs/macros.rs @@ -162,6 +162,57 @@ pub(crate) trait RegisterBase { /// // Start the aliased `CPU0`. /// CPU_CTL_ALIAS::alter(bar, &CPU0, |r| r.set_alias_start(true)); /// ``` +/// +/// ## Arrays of registers +/// +/// Some I/O areas contain consecutive values that can be interpreted in the same way. These areas +/// can be defined as an array of identical registers, allowing them to be accessed by index with +/// compile-time or runtime bound checking. Simply define their address as `Address[Size]`, and add +/// an `idx` parameter to their `read`, `write` and `alter` methods: +/// +/// ```no_run +/// # fn no_run() -> Result<(), Error> { +/// # fn get_scratch_idx() -> usize { +/// # 0x15 +/// # } +/// // Array of 64 consecutive registers with the same layout starting at offset `0x80`. +/// register!(SCRATCH @ 0x00000080[64], "Scratch registers" { +/// 31:0 value as u32; +/// }); +/// +/// // Read scratch register 0, i.e. I/O address `0x80`. +/// let scratch_0 = SCRATCH::read(bar, 0).value(); +/// // Read scratch register 15, i.e. I/O address `0x80 + (15 * 4)`. +/// let scratch_15 = SCRATCH::read(bar, 15).value(); +/// +/// // This is out of bounds and won't build. +/// // let scratch_128 = SCRATCH::read(bar, 128).value(); +/// +/// // Runtime-obtained array index. +/// let scratch_idx = get_scratch_idx(); +/// // Access on a runtime index returns an error if it is out-of-bounds. +/// let some_scratch = SCRATCH::try_read(bar, scratch_idx)?.value(); +/// +/// // Alias to a particular register in an array. +/// // Here `SCRATCH[8]` is used to convey the firmware exit code. +/// register!(FIRMWARE_STATUS => SCRATCH[8], "Firmware exit status code" { +/// 7:0 status as u8; +/// }); +/// +/// let status = FIRMWARE_STATUS::read(bar).status(); +/// +/// // Non-contiguous register arrays can be defined by adding a stride parameter. +/// // Here, each of the 16 registers of the array are separated by 8 bytes, meaning that the +/// // registers of the two declarations below are interleaved. +/// register!(SCRATCH_INTERLEAVED_0 @ 0x000000c0[16 ; 8], "Scratch registers bank 0" { +/// 31:0 value as u32; +/// }); +/// register!(SCRATCH_INTERLEAVED_1 @ 0x000000c4[16 ; 8], "Scratch registers bank 1" { +/// 31:0 value as u32; +/// }); +/// # Ok(()) +/// # } +/// ``` macro_rules! register { // Creates a register at a fixed offset of the MMIO space. ($name:ident @ $offset:literal $(, $comment:literal)? { $($fields:tt)* } ) => { @@ -187,6 +238,35 @@ macro_rules! register { register!(@io_relative $name @ $base [ $alias::OFFSET ]); }; + // Creates an array of registers at a fixed offset of the MMIO space. + ( + $name:ident @ $offset:literal [ $size:expr ; $stride:expr ] $(, $comment:literal)? { + $($fields:tt)* + } + ) => { + static_assert!(::core::mem::size_of::() <= $stride); + register!(@core $name $(, $comment)? { $($fields)* } ); + register!(@io_array $name @ $offset [ $size ; $stride ]); + }; + + // Shortcut for contiguous array of registers (stride == size of element). + ( + $name:ident @ $offset:literal [ $size:expr ] $(, $comment:literal)? { + $($fields:tt)* + } + ) => { + register!($name @ $offset [ $size ; ::core::mem::size_of::() ] $(, $comment)? { + $($fields)* + } ); + }; + + // Creates an alias of register `idx` of array of registers `alias` with its own fields. + ($name:ident => $alias:ident [ $idx:expr ] $(, $comment:literal)? { $($fields:tt)* }) => { + static_assert!($idx < $alias::SIZE); + register!(@core $name $(, $comment)? { $($fields)* } ); + register!(@io_fixed $name @ $alias::OFFSET + $idx * $alias::STRIDE ); + }; + // All rules below are helpers. // Defines the wrapper `$name` type, as well as its relevant implementations (`Debug`, @@ -520,4 +600,119 @@ pub(crate) fn alter( } } }; + + // Generates the IO accessors for an array of registers. + (@io_array $name:ident @ $offset:literal [ $size:expr ; $stride:expr ]) => { + #[allow(dead_code)] + impl $name { + pub(crate) const OFFSET: usize = $offset; + pub(crate) const SIZE: usize = $size; + pub(crate) const STRIDE: usize = $stride; + + /// Read the array register at index `idx` from its address in `io`. + #[inline(always)] + pub(crate) fn read( + io: &T, + idx: usize, + ) -> Self where + T: ::core::ops::Deref>, + { + build_assert!(idx < Self::SIZE); + + let offset = Self::OFFSET + (idx * Self::STRIDE); + let value = io.read32(offset); + + Self(value) + } + + /// Write the value contained in `self` to the array register with index `idx` in `io`. + #[inline(always)] + pub(crate) fn write( + self, + io: &T, + idx: usize + ) where + T: ::core::ops::Deref>, + { + build_assert!(idx < Self::SIZE); + + let offset = Self::OFFSET + (idx * Self::STRIDE); + + io.write32(self.0, offset); + } + + /// Read the array register at index `idx` in `io` and run `f` on its value to obtain a + /// new value to write back. + #[inline(always)] + pub(crate) fn alter( + io: &T, + idx: usize, + f: F, + ) where + T: ::core::ops::Deref>, + F: ::core::ops::FnOnce(Self) -> Self, + { + let reg = f(Self::read(io, idx)); + reg.write(io, idx); + } + + /// Read the array register at index `idx` from its address in `io`. + /// + /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the + /// access was out-of-bounds. + #[inline(always)] + pub(crate) fn try_read( + io: &T, + idx: usize, + ) -> ::kernel::error::Result where + T: ::core::ops::Deref>, + { + if idx < Self::SIZE { + Ok(Self::read(io, idx)) + } else { + Err(EINVAL) + } + } + + /// Write the value contained in `self` to the array register with index `idx` in `io`. + /// + /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the + /// access was out-of-bounds. + #[inline(always)] + pub(crate) fn try_write( + self, + io: &T, + idx: usize, + ) -> ::kernel::error::Result where + T: ::core::ops::Deref>, + { + if idx < Self::SIZE { + Ok(self.write(io, idx)) + } else { + Err(EINVAL) + } + } + + /// Read the array register at index `idx` in `io` and run `f` on its value to obtain a + /// new value to write back. + /// + /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the + /// access was out-of-bounds. + #[inline(always)] + pub(crate) fn try_alter( + io: &T, + idx: usize, + f: F, + ) -> ::kernel::error::Result where + T: ::core::ops::Deref>, + F: ::core::ops::FnOnce(Self) -> Self, + { + if idx < Self::SIZE { + Ok(Self::alter(io, idx, f)) + } else { + Err(EINVAL) + } + } + } + }; } From ec2f6c81d2a16a93d882488062e8e09e2f1d6865 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 18 Jul 2025 16:26:23 +0900 Subject: [PATCH 00919/11391] gpu: nova-core: falcon: use register arrays for FUSE registers FUSE registers are an array of 16 consecutive registers. Use the newly available register array feature to define them properly and improve the code using them. Reviewed-by: Lyude Paul Link: https://lore.kernel.org/r/20250718-nova-regs-v2-18-7b6a762aa1cd@nvidia.com Signed-off-by: Alexandre Courbot --- drivers/gpu/nova-core/falcon/hal/ga102.rs | 33 +++++++++++------------ drivers/gpu/nova-core/regs.rs | 8 +++--- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/nova-core/falcon/hal/ga102.rs b/drivers/gpu/nova-core/falcon/hal/ga102.rs index 3fdacd19322d..13c945fd6d6b 100644 --- a/drivers/gpu/nova-core/falcon/hal/ga102.rs +++ b/drivers/gpu/nova-core/falcon/hal/ga102.rs @@ -42,35 +42,32 @@ fn signature_reg_fuse_version_ga102( engine_id_mask: u16, ucode_id: u8, ) -> Result { - // TODO[REGA]: The ucode fuse versions are contained in the - // FUSE_OPT_FPF__UCODE_VERSION registers, which are an array. Our register - // definition macros do not allow us to manage them properly, so we need to hardcode their - // addresses for now. Clean this up once we support register arrays. + const NV_FUSE_OPT_FPF_SIZE: u8 = regs::NV_FUSE_OPT_FPF_SIZE as u8; // Each engine has 16 ucode version registers numbered from 1 to 16. - if ucode_id == 0 || ucode_id > 16 { - dev_err!(dev, "invalid ucode id {:#x}", ucode_id); - return Err(EINVAL); - } + let ucode_idx = match ucode_id { + 1..=NV_FUSE_OPT_FPF_SIZE => (ucode_id - 1) as usize, + _ => { + dev_err!(dev, "invalid ucode id {:#x}", ucode_id); + return Err(EINVAL); + } + }; - // Base address of the FUSE registers array corresponding to the engine. - let reg_fuse_base = if engine_id_mask & 0x0001 != 0 { - regs::NV_FUSE_OPT_FPF_SEC2_UCODE1_VERSION::OFFSET + // `ucode_idx` is guaranteed to be in the range [0..15], making the `read` calls provable valid + // at build-time. + let reg_fuse_version = if engine_id_mask & 0x0001 != 0 { + regs::NV_FUSE_OPT_FPF_SEC2_UCODE1_VERSION::read(bar, ucode_idx).data() } else if engine_id_mask & 0x0004 != 0 { - regs::NV_FUSE_OPT_FPF_NVDEC_UCODE1_VERSION::OFFSET + regs::NV_FUSE_OPT_FPF_NVDEC_UCODE1_VERSION::read(bar, ucode_idx).data() } else if engine_id_mask & 0x0400 != 0 { - regs::NV_FUSE_OPT_FPF_GSP_UCODE1_VERSION::OFFSET + regs::NV_FUSE_OPT_FPF_GSP_UCODE1_VERSION::read(bar, ucode_idx).data() } else { dev_err!(dev, "unexpected engine_id_mask {:#x}", engine_id_mask); return Err(EINVAL); }; - // Read `reg_fuse_base[ucode_id - 1]`. - let reg_fuse_version = - bar.read32(reg_fuse_base + ((ucode_id - 1) as usize * core::mem::size_of::())); - // TODO[NUMM]: replace with `last_set_bit` once it lands. - Ok(u32::BITS - reg_fuse_version.leading_zeros()) + Ok(u16::BITS - reg_fuse_version.leading_zeros()) } fn program_brom_ga102(bar: &Bar0, params: &FalconBromParams) -> Result { diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs index c45de208055d..4ae2a91bcce8 100644 --- a/drivers/gpu/nova-core/regs.rs +++ b/drivers/gpu/nova-core/regs.rs @@ -182,15 +182,17 @@ pub(crate) fn vga_workspace_addr(self) -> Option { // FUSE -register!(NV_FUSE_OPT_FPF_NVDEC_UCODE1_VERSION @ 0x00824100 { +pub(crate) const NV_FUSE_OPT_FPF_SIZE: usize = 16; + +register!(NV_FUSE_OPT_FPF_NVDEC_UCODE1_VERSION @ 0x00824100[NV_FUSE_OPT_FPF_SIZE] { 15:0 data as u16; }); -register!(NV_FUSE_OPT_FPF_SEC2_UCODE1_VERSION @ 0x00824140 { +register!(NV_FUSE_OPT_FPF_SEC2_UCODE1_VERSION @ 0x00824140[NV_FUSE_OPT_FPF_SIZE] { 15:0 data as u16; }); -register!(NV_FUSE_OPT_FPF_GSP_UCODE1_VERSION @ 0x008241c0 { +register!(NV_FUSE_OPT_FPF_GSP_UCODE1_VERSION @ 0x008241c0[NV_FUSE_OPT_FPF_SIZE] { 15:0 data as u16; }); From 0988099646cfc6c72a4448cad39d4ee22ad457a7 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 18 Jul 2025 16:26:24 +0900 Subject: [PATCH 00920/11391] gpu: nova-core: register: add support for relative array registers Add support for declaring arrays of registers available from a variable base. This is effectively a combination of the relative and array registers features. nova-core does not make much use of this yet, but it will become helpful to have for GSP boot. Reviewed-by: Lyude Paul Link: https://lore.kernel.org/r/20250718-nova-regs-v2-19-7b6a762aa1cd@nvidia.com Signed-off-by: Alexandre Courbot --- Documentation/gpu/nova/core/todo.rst | 1 - drivers/gpu/nova-core/falcon.rs | 2 +- drivers/gpu/nova-core/falcon/hal/ga102.rs | 2 +- drivers/gpu/nova-core/regs.rs | 8 +- drivers/gpu/nova-core/regs/macros.rs | 242 ++++++++++++++++++++++ 5 files changed, 248 insertions(+), 7 deletions(-) diff --git a/Documentation/gpu/nova/core/todo.rst b/Documentation/gpu/nova/core/todo.rst index a1d12c1b289d..48b20656dcb1 100644 --- a/Documentation/gpu/nova/core/todo.rst +++ b/Documentation/gpu/nova/core/todo.rst @@ -131,7 +131,6 @@ crate so it can be used by other components as well. Features desired before this happens: -* Arrays of registers with build-time index validation, * Make I/O optional I/O (for field values that are not registers), * Support other sizes than `u32`, * Allow visibility control for registers and individual fields, diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs index 2ecdcc6b9b9d..d235a6f9efca 100644 --- a/drivers/gpu/nova-core/falcon.rs +++ b/drivers/gpu/nova-core/falcon.rs @@ -516,7 +516,7 @@ fn dma_wr>( pub(crate) fn dma_load>(&self, bar: &Bar0, fw: &F) -> Result { regs::NV_PFALCON_FBIF_CTL::alter(bar, &E::ID, |v| v.set_allow_phys_no_ctx(true)); regs::NV_PFALCON_FALCON_DMACTL::default().write(bar, &E::ID); - regs::NV_PFALCON_FBIF_TRANSCFG::alter(bar, &E::ID, |v| { + regs::NV_PFALCON_FBIF_TRANSCFG::alter(bar, &E::ID, 0, |v| { v.set_target(FalconFbifTarget::CoherentSysmem) .set_mem_type(FalconFbifMemType::Physical) }); diff --git a/drivers/gpu/nova-core/falcon/hal/ga102.rs b/drivers/gpu/nova-core/falcon/hal/ga102.rs index 13c945fd6d6b..0b1cbe7853b3 100644 --- a/drivers/gpu/nova-core/falcon/hal/ga102.rs +++ b/drivers/gpu/nova-core/falcon/hal/ga102.rs @@ -73,7 +73,7 @@ fn signature_reg_fuse_version_ga102( fn program_brom_ga102(bar: &Bar0, params: &FalconBromParams) -> Result { regs::NV_PFALCON2_FALCON_BROM_PARAADDR::default() .set_value(params.pkc_data_offset) - .write(bar, &E::ID); + .write(bar, &E::ID, 0); regs::NV_PFALCON2_FALCON_BROM_ENGIDMASK::default() .set_value(u32::from(params.engine_id_mask)) .write(bar, &E::ID); diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs index 4ae2a91bcce8..206dab2e1335 100644 --- a/drivers/gpu/nova-core/regs.rs +++ b/drivers/gpu/nova-core/regs.rs @@ -289,8 +289,7 @@ pub(crate) fn mem_scrubbing_done(self) -> bool { 0:0 reset as bool; }); -// TODO[REGA]: this is an array of registers. -register!(NV_PFALCON_FBIF_TRANSCFG @ PFalconBase[0x00000600] { +register!(NV_PFALCON_FBIF_TRANSCFG @ PFalconBase[0x00000600[8]] { 1:0 target as u8 ?=> FalconFbifTarget; 2:2 mem_type as bool => FalconFbifMemType; }); @@ -313,8 +312,9 @@ pub(crate) fn mem_scrubbing_done(self) -> bool { 31:0 value as u32; }); -// TODO[REGA]: this is an array of registers. -register!(NV_PFALCON2_FALCON_BROM_PARAADDR @ PFalcon2Base[0x00000210] { +// OpenRM defines this as a register array, but doesn't specify its size and only uses its first +// element. Be conservative until we know the actual size or need to use more registers. +register!(NV_PFALCON2_FALCON_BROM_PARAADDR @ PFalcon2Base[0x00000210[1]] { 31:0 value as u32; }); diff --git a/drivers/gpu/nova-core/regs/macros.rs b/drivers/gpu/nova-core/regs/macros.rs index f38177065c25..754c14ee7f40 100644 --- a/drivers/gpu/nova-core/regs/macros.rs +++ b/drivers/gpu/nova-core/regs/macros.rs @@ -213,6 +213,74 @@ pub(crate) trait RegisterBase { /// # Ok(()) /// # } /// ``` +/// +/// ## Relative arrays of registers +/// +/// Combining the two features described in the sections above, arrays of registers accessible from +/// a base can also be defined: +/// +/// ```no_run +/// # fn no_run() -> Result<(), Error> { +/// # fn get_scratch_idx() -> usize { +/// # 0x15 +/// # } +/// // Type used as parameter of `RegisterBase` to specify the base. +/// pub(crate) struct CpuCtlBase; +/// +/// // ZST describing `CPU0`. +/// struct Cpu0; +/// impl RegisterBase for Cpu0 { +/// const BASE: usize = 0x100; +/// } +/// // Singleton of `CPU0` used to identify it. +/// const CPU0: Cpu0 = Cpu0; +/// +/// // ZST describing `CPU1`. +/// struct Cpu1; +/// impl RegisterBase for Cpu1 { +/// const BASE: usize = 0x200; +/// } +/// // Singleton of `CPU1` used to identify it. +/// const CPU1: Cpu1 = Cpu1; +/// +/// // 64 per-cpu scratch registers, arranged as an contiguous array. +/// register!(CPU_SCRATCH @ CpuCtlBase[0x00000080[64]], "Per-CPU scratch registers" { +/// 31:0 value as u32; +/// }); +/// +/// let cpu0_scratch_0 = CPU_SCRATCH::read(bar, &Cpu0, 0).value(); +/// let cpu1_scratch_15 = CPU_SCRATCH::read(bar, &Cpu1, 15).value(); +/// +/// // This won't build. +/// // let cpu0_scratch_128 = CPU_SCRATCH::read(bar, &Cpu0, 128).value(); +/// +/// // Runtime-obtained array index. +/// let scratch_idx = get_scratch_idx(); +/// // Access on a runtime value returns an error if it is out-of-bounds. +/// let cpu0_some_scratch = CPU_SCRATCH::try_read(bar, &Cpu0, scratch_idx)?.value(); +/// +/// // `SCRATCH[8]` is used to convey the firmware exit code. +/// register!(CPU_FIRMWARE_STATUS => CpuCtlBase[CPU_SCRATCH[8]], +/// "Per-CPU firmware exit status code" { +/// 7:0 status as u8; +/// }); +/// +/// let cpu0_status = CPU_FIRMWARE_STATUS::read(bar, &Cpu0).status(); +/// +/// // Non-contiguous register arrays can be defined by adding a stride parameter. +/// // Here, each of the 16 registers of the array are separated by 8 bytes, meaning that the +/// // registers of the two declarations below are interleaved. +/// register!(CPU_SCRATCH_INTERLEAVED_0 @ CpuCtlBase[0x00000d00[16 ; 8]], +/// "Scratch registers bank 0" { +/// 31:0 value as u32; +/// }); +/// register!(CPU_SCRATCH_INTERLEAVED_1 @ CpuCtlBase[0x00000d04[16 ; 8]], +/// "Scratch registers bank 1" { +/// 31:0 value as u32; +/// }); +/// # Ok(()) +/// # } +/// ``` macro_rules! register { // Creates a register at a fixed offset of the MMIO space. ($name:ident @ $offset:literal $(, $comment:literal)? { $($fields:tt)* } ) => { @@ -260,7 +328,41 @@ macro_rules! register { } ); }; + // Creates an array of registers at a relative offset from a base address provider. + ( + $name:ident @ $base:ty [ $offset:literal [ $size:expr ; $stride:expr ] ] + $(, $comment:literal)? { $($fields:tt)* } + ) => { + static_assert!(::core::mem::size_of::() <= $stride); + register!(@core $name $(, $comment)? { $($fields)* } ); + register!(@io_relative_array $name @ $base [ $offset [ $size ; $stride ] ]); + }; + + // Shortcut for contiguous array of relative registers (stride == size of element). + ( + $name:ident @ $base:ty [ $offset:literal [ $size:expr ] ] $(, $comment:literal)? { + $($fields:tt)* + } + ) => { + register!($name @ $base [ $offset [ $size ; ::core::mem::size_of::() ] ] + $(, $comment)? { $($fields)* } ); + }; + + // Creates an alias of register `idx` of relative array of registers `alias` with its own + // fields. + ( + $name:ident => $base:ty [ $alias:ident [ $idx:expr ] ] $(, $comment:literal)? { + $($fields:tt)* + } + ) => { + static_assert!($idx < $alias::SIZE); + register!(@core $name $(, $comment)? { $($fields)* } ); + register!(@io_relative $name @ $base [ $alias::OFFSET + $idx * $alias::STRIDE ] ); + }; + // Creates an alias of register `idx` of array of registers `alias` with its own fields. + // This rule belongs to the (non-relative) register arrays set, but needs to be put last + // to avoid it being interpreted in place of the relative register array alias rule. ($name:ident => $alias:ident [ $idx:expr ] $(, $comment:literal)? { $($fields:tt)* }) => { static_assert!($idx < $alias::SIZE); register!(@core $name $(, $comment)? { $($fields)* } ); @@ -715,4 +817,144 @@ pub(crate) fn try_alter( } } }; + + // Generates the IO accessors for an array of relative registers. + ( + @io_relative_array $name:ident @ $base:ty + [ $offset:literal [ $size:expr ; $stride:expr ] ] + ) => { + #[allow(dead_code)] + impl $name { + pub(crate) const OFFSET: usize = $offset; + pub(crate) const SIZE: usize = $size; + pub(crate) const STRIDE: usize = $stride; + + /// Read the array register at index `idx` from `io`, using the base address provided + /// by `base` and adding the register's offset to it. + #[inline(always)] + pub(crate) fn read( + io: &T, + #[allow(unused_variables)] + base: &B, + idx: usize, + ) -> Self where + T: ::core::ops::Deref>, + B: crate::regs::macros::RegisterBase<$base>, + { + build_assert!(idx < Self::SIZE); + + let offset = >::BASE + + Self::OFFSET + (idx * Self::STRIDE); + let value = io.read32(offset); + + Self(value) + } + + /// Write the value contained in `self` to `io`, using the base address provided by + /// `base` and adding the offset of array register `idx` to it. + #[inline(always)] + pub(crate) fn write( + self, + io: &T, + #[allow(unused_variables)] + base: &B, + idx: usize + ) where + T: ::core::ops::Deref>, + B: crate::regs::macros::RegisterBase<$base>, + { + build_assert!(idx < Self::SIZE); + + let offset = >::BASE + + Self::OFFSET + (idx * Self::STRIDE); + + io.write32(self.0, offset); + } + + /// Read the array register at index `idx` from `io`, using the base address provided + /// by `base` and adding the register's offset to it, then run `f` on its value to + /// obtain a new value to write back. + #[inline(always)] + pub(crate) fn alter( + io: &T, + base: &B, + idx: usize, + f: F, + ) where + T: ::core::ops::Deref>, + B: crate::regs::macros::RegisterBase<$base>, + F: ::core::ops::FnOnce(Self) -> Self, + { + let reg = f(Self::read(io, base, idx)); + reg.write(io, base, idx); + } + + /// Read the array register at index `idx` from `io`, using the base address provided + /// by `base` and adding the register's offset to it. + /// + /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the + /// access was out-of-bounds. + #[inline(always)] + pub(crate) fn try_read( + io: &T, + base: &B, + idx: usize, + ) -> ::kernel::error::Result where + T: ::core::ops::Deref>, + B: crate::regs::macros::RegisterBase<$base>, + { + if idx < Self::SIZE { + Ok(Self::read(io, base, idx)) + } else { + Err(EINVAL) + } + } + + /// Write the value contained in `self` to `io`, using the base address provided by + /// `base` and adding the offset of array register `idx` to it. + /// + /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the + /// access was out-of-bounds. + #[inline(always)] + pub(crate) fn try_write( + self, + io: &T, + base: &B, + idx: usize, + ) -> ::kernel::error::Result where + T: ::core::ops::Deref>, + B: crate::regs::macros::RegisterBase<$base>, + { + if idx < Self::SIZE { + Ok(self.write(io, base, idx)) + } else { + Err(EINVAL) + } + } + + /// Read the array register at index `idx` from `io`, using the base address provided + /// by `base` and adding the register's offset to it, then run `f` on its value to + /// obtain a new value to write back. + /// + /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the + /// access was out-of-bounds. + #[inline(always)] + pub(crate) fn try_alter( + io: &T, + base: &B, + idx: usize, + f: F, + ) -> ::kernel::error::Result where + T: ::core::ops::Deref>, + B: crate::regs::macros::RegisterBase<$base>, + F: ::core::ops::FnOnce(Self) -> Self, + { + if idx < Self::SIZE { + Ok(Self::alter(io, base, idx, f)) + } else { + Err(EINVAL) + } + } + } + }; } From 2327a3d6f65ce2fe2634546dde4a25ef52296fec Mon Sep 17 00:00:00 2001 From: Charalampos Mitrodimas Date: Tue, 12 Aug 2025 15:51:25 +0000 Subject: [PATCH 00921/11391] net: ipv6: fix field-spanning memcpy warning in AH output Fix field-spanning memcpy warnings in ah6_output() and ah6_output_done() where extension headers are copied to/from IPv6 address fields, triggering fortify-string warnings about writes beyond the 16-byte address fields. memcpy: detected field-spanning write (size 40) of single field "&top_iph->saddr" at net/ipv6/ah6.c:439 (size 16) WARNING: CPU: 0 PID: 8838 at net/ipv6/ah6.c:439 ah6_output+0xe7e/0x14e0 net/ipv6/ah6.c:439 The warnings are false positives as the extension headers are intentionally placed after the IPv6 header in memory. Fix by properly copying addresses and extension headers separately, and introduce helper functions to avoid code duplication. Reported-by: syzbot+01b0667934cdceb4451c@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=01b0667934cdceb4451c Signed-off-by: Charalampos Mitrodimas Signed-off-by: Steffen Klassert --- net/ipv6/ah6.c | 50 +++++++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index eb474f0987ae..95372e0f1d21 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -46,6 +46,34 @@ struct ah_skb_cb { #define AH_SKB_CB(__skb) ((struct ah_skb_cb *)&((__skb)->cb[0])) +/* Helper to save IPv6 addresses and extension headers to temporary storage */ +static inline void ah6_save_hdrs(struct tmp_ext *iph_ext, + struct ipv6hdr *top_iph, int extlen) +{ + if (!extlen) + return; + +#if IS_ENABLED(CONFIG_IPV6_MIP6) + iph_ext->saddr = top_iph->saddr; +#endif + iph_ext->daddr = top_iph->daddr; + memcpy(&iph_ext->hdrs, top_iph + 1, extlen - sizeof(*iph_ext)); +} + +/* Helper to restore IPv6 addresses and extension headers from temporary storage */ +static inline void ah6_restore_hdrs(struct ipv6hdr *top_iph, + struct tmp_ext *iph_ext, int extlen) +{ + if (!extlen) + return; + +#if IS_ENABLED(CONFIG_IPV6_MIP6) + top_iph->saddr = iph_ext->saddr; +#endif + top_iph->daddr = iph_ext->daddr; + memcpy(top_iph + 1, &iph_ext->hdrs, extlen - sizeof(*iph_ext)); +} + static void *ah_alloc_tmp(struct crypto_ahash *ahash, int nfrags, unsigned int size) { @@ -301,13 +329,7 @@ static void ah6_output_done(void *data, int err) memcpy(ah->auth_data, icv, ahp->icv_trunc_len); memcpy(top_iph, iph_base, IPV6HDR_BASELEN); - if (extlen) { -#if IS_ENABLED(CONFIG_IPV6_MIP6) - memcpy(&top_iph->saddr, iph_ext, extlen); -#else - memcpy(&top_iph->daddr, iph_ext, extlen); -#endif - } + ah6_restore_hdrs(top_iph, iph_ext, extlen); kfree(AH_SKB_CB(skb)->tmp); xfrm_output_resume(skb->sk, skb, err); @@ -378,12 +400,8 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) */ memcpy(iph_base, top_iph, IPV6HDR_BASELEN); + ah6_save_hdrs(iph_ext, top_iph, extlen); if (extlen) { -#if IS_ENABLED(CONFIG_IPV6_MIP6) - memcpy(iph_ext, &top_iph->saddr, extlen); -#else - memcpy(iph_ext, &top_iph->daddr, extlen); -#endif err = ipv6_clear_mutable_options(top_iph, extlen - sizeof(*iph_ext) + sizeof(*top_iph), @@ -434,13 +452,7 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) memcpy(ah->auth_data, icv, ahp->icv_trunc_len); memcpy(top_iph, iph_base, IPV6HDR_BASELEN); - if (extlen) { -#if IS_ENABLED(CONFIG_IPV6_MIP6) - memcpy(&top_iph->saddr, iph_ext, extlen); -#else - memcpy(&top_iph->daddr, iph_ext, extlen); -#endif - } + ah6_restore_hdrs(top_iph, iph_ext, extlen); out_free: kfree(iph_base); From 9f4f591cd5a410f4203a9c104f92d467945b7d7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Garc=C3=ADa?= Date: Thu, 14 Aug 2025 21:32:17 +0200 Subject: [PATCH 00922/11391] xfrm: xfrm_user: use strscpy() for alg_name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the strcpy() calls that copy the canonical algorithm name into alg_name with strscpy() to avoid potential overflows and guarantee NULL termination. Destination is alg_name in xfrm_algo/xfrm_algo_auth/xfrm_algo_aead (size CRYPTO_MAX_ALG_NAME). Tested in QEMU (BusyBox/Alpine rootfs): - Added ESP AEAD (rfc4106(gcm(aes))) and classic ESP (sha256 + cbc(aes)) - Verified canonical names via ip -d xfrm state - Checked IPComp negative (unknown algo) and deflate path Signed-off-by: Miguel García Signed-off-by: Steffen Klassert --- net/xfrm/xfrm_user.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 684239018bec..010c9e6638c0 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -593,7 +593,7 @@ static int attach_one_algo(struct xfrm_algo **algpp, u8 *props, if (!p) return -ENOMEM; - strcpy(p->alg_name, algo->name); + strscpy(p->alg_name, algo->name); *algpp = p; return 0; } @@ -620,7 +620,7 @@ static int attach_crypt(struct xfrm_state *x, struct nlattr *rta, if (!p) return -ENOMEM; - strcpy(p->alg_name, algo->name); + strscpy(p->alg_name, algo->name); x->ealg = p; x->geniv = algo->uinfo.encr.geniv; return 0; @@ -649,7 +649,7 @@ static int attach_auth(struct xfrm_algo_auth **algpp, u8 *props, if (!p) return -ENOMEM; - strcpy(p->alg_name, algo->name); + strscpy(p->alg_name, algo->name); p->alg_key_len = ualg->alg_key_len; p->alg_trunc_len = algo->uinfo.auth.icv_truncbits; memcpy(p->alg_key, ualg->alg_key, (ualg->alg_key_len + 7) / 8); @@ -684,7 +684,7 @@ static int attach_auth_trunc(struct xfrm_algo_auth **algpp, u8 *props, if (!p) return -ENOMEM; - strcpy(p->alg_name, algo->name); + strscpy(p->alg_name, algo->name); if (!p->alg_trunc_len) p->alg_trunc_len = algo->uinfo.auth.icv_truncbits; @@ -714,7 +714,7 @@ static int attach_aead(struct xfrm_state *x, struct nlattr *rta, if (!p) return -ENOMEM; - strcpy(p->alg_name, algo->name); + strscpy(p->alg_name, algo->name); x->aead = p; x->geniv = algo->uinfo.aead.geniv; return 0; From 4f4098c57e139ad972154077fb45c3e3141555dd Mon Sep 17 00:00:00 2001 From: Ma Ke Date: Fri, 18 Jul 2025 17:50:54 +0800 Subject: [PATCH 00923/11391] media: lirc: Fix error handling in lirc_register() When cdev_device_add() failed, calling put_device() to explicitly release dev->lirc_dev. Otherwise, it could cause the fault of the reference count. Found by code review. Cc: stable@vger.kernel.org Fixes: a6ddd4fecbb0 ("media: lirc: remove last remnants of lirc kapi") Signed-off-by: Ma Ke Signed-off-by: Sean Young Signed-off-by: Hans Verkuil --- drivers/media/rc/lirc_dev.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index a2257dc2f25d..7d4942925993 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -736,11 +736,11 @@ int lirc_register(struct rc_dev *dev) cdev_init(&dev->lirc_cdev, &lirc_fops); + get_device(&dev->dev); + err = cdev_device_add(&dev->lirc_cdev, &dev->lirc_dev); if (err) - goto out_ida; - - get_device(&dev->dev); + goto out_put_device; switch (dev->driver_type) { case RC_DRIVER_SCANCODE: @@ -764,7 +764,8 @@ int lirc_register(struct rc_dev *dev) return 0; -out_ida: +out_put_device: + put_device(&dev->lirc_dev); ida_free(&lirc_ida, minor); return err; } From eecd203ada43a4693ce6fdd3a58ae10c7819252c Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Thu, 17 Jul 2025 23:21:55 +0900 Subject: [PATCH 00924/11391] media: imon: make send_packet() more robust syzbot is reporting that imon has three problems which result in hung tasks due to forever holding device lock [1]. First problem is that when usb_rx_callback_intf0() once got -EPROTO error after ictx->dev_present_intf0 became true, usb_rx_callback_intf0() resubmits urb after printk(), and resubmitted urb causes usb_rx_callback_intf0() to again get -EPROTO error. This results in printk() flooding (RCU stalls). Alan Stern commented [2] that In theory it's okay to resubmit _if_ the driver has a robust error-recovery scheme (such as giving up after some fixed limit on the number of errors or after some fixed time has elapsed, perhaps with a time delay to prevent a flood of errors). Most drivers don't bother to do this; they simply give up right away. This makes them more vulnerable to short-term noise interference during USB transfers, but in reality such interference is quite rare. There's nothing really wrong with giving up right away. but imon has a poor error-recovery scheme which just retries forever; this behavior should be fixed. Since I'm not sure whether it is safe for imon users to give up upon any error code, this patch takes care of only union of error codes chosen from modules in drivers/media/rc/ directory which handle -EPROTO error (i.e. ir_toy, mceusb and igorplugusb). Second problem is that when usb_rx_callback_intf0() once got -EPROTO error before ictx->dev_present_intf0 becomes true, usb_rx_callback_intf0() always resubmits urb due to commit 8791d63af0cf ("[media] imon: don't wedge hardware after early callbacks"). Move the ictx->dev_present_intf0 test introduced by commit 6f6b90c9231a ("[media] imon: don't parse scancodes until intf configured") to immediately before imon_incoming_packet(), or the first problem explained above happens without printk() flooding (i.e. hung task). Third problem is that when usb_rx_callback_intf0() is not called for some reason (e.g. flaky hardware; the reproducer for this problem sometimes prevents usb_rx_callback_intf0() from being called), wait_for_completion_interruptible() in send_packet() never returns (i.e. hung task). As a workaround for such situation, change send_packet() to wait for completion with timeout of 10 seconds. Link: https://syzkaller.appspot.com/bug?extid=592e2ab8775dbe0bf09a [1] Link: https://lkml.kernel.org/r/d6da6709-d799-4be3-a695-850bddd6eb24@rowland.harvard.edu [2] Signed-off-by: Tetsuo Handa Signed-off-by: Sean Young Signed-off-by: Hans Verkuil --- drivers/media/rc/imon.c | 61 +++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index f5221b018808..b914dd39c21c 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -645,12 +645,15 @@ static int send_packet(struct imon_context *ictx) smp_rmb(); /* ensure later readers know we're not busy */ pr_err_ratelimited("error submitting urb(%d)\n", retval); } else { - /* Wait for transmission to complete (or abort) */ - retval = wait_for_completion_interruptible( - &ictx->tx.finished); - if (retval) { + /* Wait for transmission to complete (or abort or timeout) */ + retval = wait_for_completion_interruptible_timeout(&ictx->tx.finished, 10 * HZ); + if (retval <= 0) { usb_kill_urb(ictx->tx_urb); pr_err_ratelimited("task interrupted\n"); + if (retval < 0) + ictx->tx.status = retval; + else + ictx->tx.status = -ETIMEDOUT; } ictx->tx.busy = false; @@ -1745,14 +1748,6 @@ static void usb_rx_callback_intf0(struct urb *urb) if (!ictx) return; - /* - * if we get a callback before we're done configuring the hardware, we - * can't yet process the data, as there's nowhere to send it, but we - * still need to submit a new rx URB to avoid wedging the hardware - */ - if (!ictx->dev_present_intf0) - goto out; - switch (urb->status) { case -ENOENT: /* usbcore unlink successful! */ return; @@ -1761,16 +1756,29 @@ static void usb_rx_callback_intf0(struct urb *urb) break; case 0: - imon_incoming_packet(ictx, urb, intfnum); + /* + * if we get a callback before we're done configuring the hardware, we + * can't yet process the data, as there's nowhere to send it, but we + * still need to submit a new rx URB to avoid wedging the hardware + */ + if (ictx->dev_present_intf0) + imon_incoming_packet(ictx, urb, intfnum); break; + case -ECONNRESET: + case -EILSEQ: + case -EPROTO: + case -EPIPE: + dev_warn(ictx->dev, "imon %s: status(%d)\n", + __func__, urb->status); + return; + default: dev_warn(ictx->dev, "imon %s: status(%d): ignored\n", __func__, urb->status); break; } -out: usb_submit_urb(ictx->rx_urb_intf0, GFP_ATOMIC); } @@ -1786,14 +1794,6 @@ static void usb_rx_callback_intf1(struct urb *urb) if (!ictx) return; - /* - * if we get a callback before we're done configuring the hardware, we - * can't yet process the data, as there's nowhere to send it, but we - * still need to submit a new rx URB to avoid wedging the hardware - */ - if (!ictx->dev_present_intf1) - goto out; - switch (urb->status) { case -ENOENT: /* usbcore unlink successful! */ return; @@ -1802,16 +1802,29 @@ static void usb_rx_callback_intf1(struct urb *urb) break; case 0: - imon_incoming_packet(ictx, urb, intfnum); + /* + * if we get a callback before we're done configuring the hardware, we + * can't yet process the data, as there's nowhere to send it, but we + * still need to submit a new rx URB to avoid wedging the hardware + */ + if (ictx->dev_present_intf1) + imon_incoming_packet(ictx, urb, intfnum); break; + case -ECONNRESET: + case -EILSEQ: + case -EPROTO: + case -EPIPE: + dev_warn(ictx->dev, "imon %s: status(%d)\n", + __func__, urb->status); + return; + default: dev_warn(ictx->dev, "imon %s: status(%d): ignored\n", __func__, urb->status); break; } -out: usb_submit_urb(ictx->rx_urb_intf1, GFP_ATOMIC); } From 7019553ab850ce1d3f0e512e16d14ab153f91c04 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Fri, 18 Jul 2025 01:04:00 +0900 Subject: [PATCH 00925/11391] media: imon: grab lock earlier in imon_ir_change_protocol() Move mutex_trylock() in imon_ir_change_protocol() to the beginning, for memcpy() which modifies ictx->usb_tx_buf should be protected by ictx->lock. Also, verify at the beginning of send_packet() that ictx->lock is held in case send_packet() is by error called from imon_ir_change_protocol() when mutex_trylock() failed due to concurrent requests. Signed-off-by: Tetsuo Handa Signed-off-by: Sean Young Signed-off-by: Hans Verkuil --- drivers/media/rc/imon.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index b914dd39c21c..8275ca5e9b6f 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -598,6 +598,8 @@ static int send_packet(struct imon_context *ictx) int retval = 0; struct usb_ctrlrequest *control_req = NULL; + lockdep_assert_held(&ictx->lock); + /* Check if we need to use control or interrupt urb */ if (!ictx->tx_control) { pipe = usb_sndintpipe(ictx->usbdev_intf0, @@ -1124,7 +1126,7 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 *rc_proto) int retval; struct imon_context *ictx = rc->priv; struct device *dev = ictx->dev; - bool unlock = false; + const bool unlock = mutex_trylock(&ictx->lock); unsigned char ir_proto_packet[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 }; @@ -1151,8 +1153,6 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 *rc_proto) memcpy(ictx->usb_tx_buf, &ir_proto_packet, sizeof(ir_proto_packet)); - unlock = mutex_trylock(&ictx->lock); - retval = send_packet(ictx); if (retval) goto out; From a75b8d198c55e9eb5feb6f6e155496305caba2dc Mon Sep 17 00:00:00 2001 From: Sean Young Date: Wed, 16 Jul 2025 15:24:54 +0100 Subject: [PATCH 00926/11391] media: imon: Remove unused defines These defines were used for devices now supported by the imon_raw driver. Signed-off-by: Sean Young Signed-off-by: Hans Verkuil --- drivers/media/rc/imon.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 8275ca5e9b6f..91d05aadced3 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -39,11 +39,6 @@ #define DISPLAY_MINOR_BASE 144 #define DEVICE_NAME "lcd%d" -#define BUF_CHUNK_SIZE 8 -#define BUF_SIZE 128 - -#define BIT_DURATION 250 /* each bit received is 250us */ - #define IMON_CLOCK_ENABLE_PACKETS 2 /*** P R O T O T Y P E S ***/ From 02fc01adec1c4b107fed08c30ac979b62136998f Mon Sep 17 00:00:00 2001 From: Pu Lehui Date: Sat, 19 Jul 2025 09:17:21 +0000 Subject: [PATCH 00927/11391] riscv, bpf: Extract emit_stx() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's a lot of redundant code related to store from register operations, let's extract emit_stx() to make code more compact. Signed-off-by: Pu Lehui Signed-off-by: Daniel Borkmann Tested-by: Björn Töpel Reviewed-by: Björn Töpel Acked-by: Björn Töpel Link: https://lore.kernel.org/bpf/20250719091730.2660197-2-pulehui@huaweicloud.com --- arch/riscv/net/bpf_jit_comp64.c | 172 ++++++++------------------------ 1 file changed, 41 insertions(+), 131 deletions(-) diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c index 10e01ff06312..ba75ba179b26 100644 --- a/arch/riscv/net/bpf_jit_comp64.c +++ b/arch/riscv/net/bpf_jit_comp64.c @@ -559,52 +559,39 @@ static int emit_load_64(bool sign_ext, u8 rd, s32 off, u8 rs, struct rv_jit_cont return ctx->ninsns - insns_start; } -static void emit_store_8(u8 rd, s32 off, u8 rs, struct rv_jit_context *ctx) +static void emit_stx_insn(u8 rd, s16 off, u8 rs, u8 size, struct rv_jit_context *ctx) { - if (is_12b_int(off)) { + switch (size) { + case BPF_B: emit(rv_sb(rd, off, rs), ctx); - return; - } - - emit_imm(RV_REG_T1, off, ctx); - emit_add(RV_REG_T1, RV_REG_T1, rd, ctx); - emit(rv_sb(RV_REG_T1, 0, rs), ctx); -} - -static void emit_store_16(u8 rd, s32 off, u8 rs, struct rv_jit_context *ctx) -{ - if (is_12b_int(off)) { + break; + case BPF_H: emit(rv_sh(rd, off, rs), ctx); - return; - } - - emit_imm(RV_REG_T1, off, ctx); - emit_add(RV_REG_T1, RV_REG_T1, rd, ctx); - emit(rv_sh(RV_REG_T1, 0, rs), ctx); -} - -static void emit_store_32(u8 rd, s32 off, u8 rs, struct rv_jit_context *ctx) -{ - if (is_12b_int(off)) { + break; + case BPF_W: emit_sw(rd, off, rs, ctx); - return; + break; + case BPF_DW: + emit_sd(rd, off, rs, ctx); + break; } - - emit_imm(RV_REG_T1, off, ctx); - emit_add(RV_REG_T1, RV_REG_T1, rd, ctx); - emit_sw(RV_REG_T1, 0, rs, ctx); } -static void emit_store_64(u8 rd, s32 off, u8 rs, struct rv_jit_context *ctx) +static int emit_stx(u8 rd, s16 off, u8 rs, u8 size, struct rv_jit_context *ctx) { + int insns_start; + if (is_12b_int(off)) { - emit_sd(rd, off, rs, ctx); - return; + insns_start = ctx->ninsns; + emit_stx_insn(rd, off, rs, size, ctx); + return ctx->ninsns - insns_start; } emit_imm(RV_REG_T1, off, ctx); emit_add(RV_REG_T1, RV_REG_T1, rd, ctx); - emit_sd(RV_REG_T1, 0, rs, ctx); + insns_start = ctx->ninsns; + emit_stx_insn(RV_REG_T1, 0, rs, size, ctx); + return ctx->ninsns - insns_start; } static int emit_atomic_ld_st(u8 rd, u8 rs, const struct bpf_insn *insn, @@ -642,20 +629,7 @@ static int emit_atomic_ld_st(u8 rd, u8 rs, const struct bpf_insn *insn, /* store_release(dst_reg + off16, src_reg) */ case BPF_STORE_REL: emit_fence_rw_w(ctx); - switch (BPF_SIZE(code)) { - case BPF_B: - emit_store_8(rd, off, rs, ctx); - break; - case BPF_H: - emit_store_16(rd, off, rs, ctx); - break; - case BPF_W: - emit_store_32(rd, off, rs, ctx); - break; - case BPF_DW: - emit_store_64(rd, off, rs, ctx); - break; - } + emit_stx(rd, off, rs, BPF_SIZE(code), ctx); break; default: pr_err_once("bpf-jit: invalid atomic load/store opcode %02x\n", imm); @@ -2023,17 +1997,30 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, /* STX: *(size *)(dst + off) = src */ case BPF_STX | BPF_MEM | BPF_B: - emit_store_8(rd, off, rs, ctx); - break; case BPF_STX | BPF_MEM | BPF_H: - emit_store_16(rd, off, rs, ctx); - break; case BPF_STX | BPF_MEM | BPF_W: - emit_store_32(rd, off, rs, ctx); - break; case BPF_STX | BPF_MEM | BPF_DW: - emit_store_64(rd, off, rs, ctx); + /* STX | PROBE_MEM32: *(size *)(dst + RV_REG_ARENA + off) = src */ + case BPF_STX | BPF_PROBE_MEM32 | BPF_B: + case BPF_STX | BPF_PROBE_MEM32 | BPF_H: + case BPF_STX | BPF_PROBE_MEM32 | BPF_W: + case BPF_STX | BPF_PROBE_MEM32 | BPF_DW: + { + int insn_len; + + if (BPF_MODE(insn->code) == BPF_PROBE_MEM32) { + emit_add(RV_REG_T2, rd, RV_REG_ARENA, ctx); + rd = RV_REG_T2; + } + + insn_len = emit_stx(rd, off, rs, BPF_SIZE(code), ctx); + + ret = add_exception_handler(insn, ctx, REG_DONT_CLEAR_MARKER, insn_len); + if (ret) + return ret; break; + } + case BPF_STX | BPF_ATOMIC | BPF_B: case BPF_STX | BPF_ATOMIC | BPF_H: case BPF_STX | BPF_ATOMIC | BPF_W: @@ -2046,83 +2033,6 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, return ret; break; - case BPF_STX | BPF_PROBE_MEM32 | BPF_B: - case BPF_STX | BPF_PROBE_MEM32 | BPF_H: - case BPF_STX | BPF_PROBE_MEM32 | BPF_W: - case BPF_STX | BPF_PROBE_MEM32 | BPF_DW: - { - int insn_len, insns_start; - - emit_add(RV_REG_T2, rd, RV_REG_ARENA, ctx); - rd = RV_REG_T2; - - switch (BPF_SIZE(code)) { - case BPF_B: - if (is_12b_int(off)) { - insns_start = ctx->ninsns; - emit(rv_sb(rd, off, rs), ctx); - insn_len = ctx->ninsns - insns_start; - break; - } - - emit_imm(RV_REG_T1, off, ctx); - emit_add(RV_REG_T1, RV_REG_T1, rd, ctx); - insns_start = ctx->ninsns; - emit(rv_sb(RV_REG_T1, 0, rs), ctx); - insn_len = ctx->ninsns - insns_start; - break; - case BPF_H: - if (is_12b_int(off)) { - insns_start = ctx->ninsns; - emit(rv_sh(rd, off, rs), ctx); - insn_len = ctx->ninsns - insns_start; - break; - } - - emit_imm(RV_REG_T1, off, ctx); - emit_add(RV_REG_T1, RV_REG_T1, rd, ctx); - insns_start = ctx->ninsns; - emit(rv_sh(RV_REG_T1, 0, rs), ctx); - insn_len = ctx->ninsns - insns_start; - break; - case BPF_W: - if (is_12b_int(off)) { - insns_start = ctx->ninsns; - emit_sw(rd, off, rs, ctx); - insn_len = ctx->ninsns - insns_start; - break; - } - - emit_imm(RV_REG_T1, off, ctx); - emit_add(RV_REG_T1, RV_REG_T1, rd, ctx); - insns_start = ctx->ninsns; - emit_sw(RV_REG_T1, 0, rs, ctx); - insn_len = ctx->ninsns - insns_start; - break; - case BPF_DW: - if (is_12b_int(off)) { - insns_start = ctx->ninsns; - emit_sd(rd, off, rs, ctx); - insn_len = ctx->ninsns - insns_start; - break; - } - - emit_imm(RV_REG_T1, off, ctx); - emit_add(RV_REG_T1, RV_REG_T1, rd, ctx); - insns_start = ctx->ninsns; - emit_sd(RV_REG_T1, 0, rs, ctx); - insn_len = ctx->ninsns - insns_start; - break; - } - - ret = add_exception_handler(insn, ctx, REG_DONT_CLEAR_MARKER, - insn_len); - if (ret) - return ret; - - break; - } - default: pr_err("bpf-jit: unknown opcode %02x\n", code); return -EINVAL; From d92c11a6b55b16a679c8533119ee77baf098cb4e Mon Sep 17 00:00:00 2001 From: Pu Lehui Date: Sat, 19 Jul 2025 09:17:22 +0000 Subject: [PATCH 00928/11391] riscv, bpf: Extract emit_st() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's a lot of redundant code related to store from immediate operations, let's extract emit_st() to make code more compact. Signed-off-by: Pu Lehui Signed-off-by: Daniel Borkmann Tested-by: Björn Töpel Reviewed-by: Björn Töpel Acked-by: Björn Töpel Link: https://lore.kernel.org/bpf/20250719091730.2660197-3-pulehui@huaweicloud.com --- arch/riscv/net/bpf_jit_comp64.c | 135 ++++++-------------------------- 1 file changed, 26 insertions(+), 109 deletions(-) diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c index ba75ba179b26..5e354f686ea3 100644 --- a/arch/riscv/net/bpf_jit_comp64.c +++ b/arch/riscv/net/bpf_jit_comp64.c @@ -577,6 +577,24 @@ static void emit_stx_insn(u8 rd, s16 off, u8 rs, u8 size, struct rv_jit_context } } +static int emit_st(u8 rd, s16 off, s32 imm, u8 size, struct rv_jit_context *ctx) +{ + int insns_start; + + emit_imm(RV_REG_T1, imm, ctx); + if (is_12b_int(off)) { + insns_start = ctx->ninsns; + emit_stx_insn(rd, off, RV_REG_T1, size, ctx); + return ctx->ninsns - insns_start; + } + + emit_imm(RV_REG_T2, off, ctx); + emit_add(RV_REG_T2, RV_REG_T2, rd, ctx); + insns_start = ctx->ninsns; + emit_stx_insn(RV_REG_T2, 0, RV_REG_T1, size, ctx); + return ctx->ninsns - insns_start; +} + static int emit_stx(u8 rd, s16 off, u8 rs, u8 size, struct rv_jit_context *ctx) { int insns_start; @@ -1870,128 +1888,27 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, /* ST: *(size *)(dst + off) = imm */ case BPF_ST | BPF_MEM | BPF_B: - emit_imm(RV_REG_T1, imm, ctx); - if (is_12b_int(off)) { - emit(rv_sb(rd, off, RV_REG_T1), ctx); - break; - } - - emit_imm(RV_REG_T2, off, ctx); - emit_add(RV_REG_T2, RV_REG_T2, rd, ctx); - emit(rv_sb(RV_REG_T2, 0, RV_REG_T1), ctx); - break; - case BPF_ST | BPF_MEM | BPF_H: - emit_imm(RV_REG_T1, imm, ctx); - if (is_12b_int(off)) { - emit(rv_sh(rd, off, RV_REG_T1), ctx); - break; - } - - emit_imm(RV_REG_T2, off, ctx); - emit_add(RV_REG_T2, RV_REG_T2, rd, ctx); - emit(rv_sh(RV_REG_T2, 0, RV_REG_T1), ctx); - break; case BPF_ST | BPF_MEM | BPF_W: - emit_imm(RV_REG_T1, imm, ctx); - if (is_12b_int(off)) { - emit_sw(rd, off, RV_REG_T1, ctx); - break; - } - - emit_imm(RV_REG_T2, off, ctx); - emit_add(RV_REG_T2, RV_REG_T2, rd, ctx); - emit_sw(RV_REG_T2, 0, RV_REG_T1, ctx); - break; case BPF_ST | BPF_MEM | BPF_DW: - emit_imm(RV_REG_T1, imm, ctx); - if (is_12b_int(off)) { - emit_sd(rd, off, RV_REG_T1, ctx); - break; - } - - emit_imm(RV_REG_T2, off, ctx); - emit_add(RV_REG_T2, RV_REG_T2, rd, ctx); - emit_sd(RV_REG_T2, 0, RV_REG_T1, ctx); - break; - + /* ST | PROBE_MEM32: *(size *)(dst + RV_REG_ARENA + off) = imm */ case BPF_ST | BPF_PROBE_MEM32 | BPF_B: case BPF_ST | BPF_PROBE_MEM32 | BPF_H: case BPF_ST | BPF_PROBE_MEM32 | BPF_W: case BPF_ST | BPF_PROBE_MEM32 | BPF_DW: { - int insn_len, insns_start; + int insn_len; - emit_add(RV_REG_T3, rd, RV_REG_ARENA, ctx); - rd = RV_REG_T3; - - /* Load imm to a register then store it */ - emit_imm(RV_REG_T1, imm, ctx); - - switch (BPF_SIZE(code)) { - case BPF_B: - if (is_12b_int(off)) { - insns_start = ctx->ninsns; - emit(rv_sb(rd, off, RV_REG_T1), ctx); - insn_len = ctx->ninsns - insns_start; - break; - } - - emit_imm(RV_REG_T2, off, ctx); - emit_add(RV_REG_T2, RV_REG_T2, rd, ctx); - insns_start = ctx->ninsns; - emit(rv_sb(RV_REG_T2, 0, RV_REG_T1), ctx); - insn_len = ctx->ninsns - insns_start; - break; - case BPF_H: - if (is_12b_int(off)) { - insns_start = ctx->ninsns; - emit(rv_sh(rd, off, RV_REG_T1), ctx); - insn_len = ctx->ninsns - insns_start; - break; - } - - emit_imm(RV_REG_T2, off, ctx); - emit_add(RV_REG_T2, RV_REG_T2, rd, ctx); - insns_start = ctx->ninsns; - emit(rv_sh(RV_REG_T2, 0, RV_REG_T1), ctx); - insn_len = ctx->ninsns - insns_start; - break; - case BPF_W: - if (is_12b_int(off)) { - insns_start = ctx->ninsns; - emit_sw(rd, off, RV_REG_T1, ctx); - insn_len = ctx->ninsns - insns_start; - break; - } - - emit_imm(RV_REG_T2, off, ctx); - emit_add(RV_REG_T2, RV_REG_T2, rd, ctx); - insns_start = ctx->ninsns; - emit_sw(RV_REG_T2, 0, RV_REG_T1, ctx); - insn_len = ctx->ninsns - insns_start; - break; - case BPF_DW: - if (is_12b_int(off)) { - insns_start = ctx->ninsns; - emit_sd(rd, off, RV_REG_T1, ctx); - insn_len = ctx->ninsns - insns_start; - break; - } - - emit_imm(RV_REG_T2, off, ctx); - emit_add(RV_REG_T2, RV_REG_T2, rd, ctx); - insns_start = ctx->ninsns; - emit_sd(RV_REG_T2, 0, RV_REG_T1, ctx); - insn_len = ctx->ninsns - insns_start; - break; + if (BPF_MODE(insn->code) == BPF_PROBE_MEM32) { + emit_add(RV_REG_T3, rd, RV_REG_ARENA, ctx); + rd = RV_REG_T3; } - ret = add_exception_handler(insn, ctx, REG_DONT_CLEAR_MARKER, - insn_len); + insn_len = emit_st(rd, off, imm, BPF_SIZE(code), ctx); + + ret = add_exception_handler(insn, ctx, REG_DONT_CLEAR_MARKER, insn_len); if (ret) return ret; - break; } From 01422a4f2c78c69febeafb9110d013f2bb46c58f Mon Sep 17 00:00:00 2001 From: Pu Lehui Date: Sat, 19 Jul 2025 09:17:23 +0000 Subject: [PATCH 00929/11391] riscv, bpf: Extract emit_ldx() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's a lot of redundant code related to load into register operations, let's extract emit_ldx() to make code more compact. Signed-off-by: Pu Lehui Signed-off-by: Daniel Borkmann Tested-by: Björn Töpel Reviewed-by: Björn Töpel Acked-by: Björn Töpel Link: https://lore.kernel.org/bpf/20250719091730.2660197-4-pulehui@huaweicloud.com --- arch/riscv/net/bpf_jit_comp64.c | 143 ++++++++------------------------ 1 file changed, 35 insertions(+), 108 deletions(-) diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c index 5e354f686ea3..a6a9fd9193e5 100644 --- a/arch/riscv/net/bpf_jit_comp64.c +++ b/arch/riscv/net/bpf_jit_comp64.c @@ -473,90 +473,24 @@ static inline void emit_kcfi(u32 hash, struct rv_jit_context *ctx) emit(hash, ctx); } -static int emit_load_8(bool sign_ext, u8 rd, s32 off, u8 rs, struct rv_jit_context *ctx) +static void emit_ldx_insn(u8 rd, s16 off, u8 rs, u8 size, bool sign_ext, + struct rv_jit_context *ctx) { - int insns_start; - - if (is_12b_int(off)) { - insns_start = ctx->ninsns; - if (sign_ext) - emit(rv_lb(rd, off, rs), ctx); - else - emit(rv_lbu(rd, off, rs), ctx); - return ctx->ninsns - insns_start; - } - - emit_imm(RV_REG_T1, off, ctx); - emit_add(RV_REG_T1, RV_REG_T1, rs, ctx); - insns_start = ctx->ninsns; - if (sign_ext) - emit(rv_lb(rd, 0, RV_REG_T1), ctx); - else - emit(rv_lbu(rd, 0, RV_REG_T1), ctx); - return ctx->ninsns - insns_start; -} - -static int emit_load_16(bool sign_ext, u8 rd, s32 off, u8 rs, struct rv_jit_context *ctx) -{ - int insns_start; - - if (is_12b_int(off)) { - insns_start = ctx->ninsns; - if (sign_ext) - emit(rv_lh(rd, off, rs), ctx); - else - emit(rv_lhu(rd, off, rs), ctx); - return ctx->ninsns - insns_start; - } - - emit_imm(RV_REG_T1, off, ctx); - emit_add(RV_REG_T1, RV_REG_T1, rs, ctx); - insns_start = ctx->ninsns; - if (sign_ext) - emit(rv_lh(rd, 0, RV_REG_T1), ctx); - else - emit(rv_lhu(rd, 0, RV_REG_T1), ctx); - return ctx->ninsns - insns_start; -} - -static int emit_load_32(bool sign_ext, u8 rd, s32 off, u8 rs, struct rv_jit_context *ctx) -{ - int insns_start; - - if (is_12b_int(off)) { - insns_start = ctx->ninsns; - if (sign_ext) - emit(rv_lw(rd, off, rs), ctx); - else - emit(rv_lwu(rd, off, rs), ctx); - return ctx->ninsns - insns_start; - } - - emit_imm(RV_REG_T1, off, ctx); - emit_add(RV_REG_T1, RV_REG_T1, rs, ctx); - insns_start = ctx->ninsns; - if (sign_ext) - emit(rv_lw(rd, 0, RV_REG_T1), ctx); - else - emit(rv_lwu(rd, 0, RV_REG_T1), ctx); - return ctx->ninsns - insns_start; -} - -static int emit_load_64(bool sign_ext, u8 rd, s32 off, u8 rs, struct rv_jit_context *ctx) -{ - int insns_start; - - if (is_12b_int(off)) { - insns_start = ctx->ninsns; + switch (size) { + case BPF_B: + emit(sign_ext ? rv_lb(rd, off, rs) : rv_lbu(rd, off, rs), ctx); + break; + case BPF_H: + emit(sign_ext ? rv_lh(rd, off, rs) : rv_lhu(rd, off, rs), ctx); + break; + case BPF_W: + emit(sign_ext ? rv_lw(rd, off, rs) : rv_lwu(rd, off, rs), ctx); + break; + case BPF_DW: emit_ld(rd, off, rs, ctx); - return ctx->ninsns - insns_start; + break; } - emit_imm(RV_REG_T1, off, ctx); - emit_add(RV_REG_T1, RV_REG_T1, rs, ctx); - insns_start = ctx->ninsns; - emit_ld(rd, 0, RV_REG_T1, ctx); - return ctx->ninsns - insns_start; } static void emit_stx_insn(u8 rd, s16 off, u8 rs, u8 size, struct rv_jit_context *ctx) @@ -577,6 +511,24 @@ static void emit_stx_insn(u8 rd, s16 off, u8 rs, u8 size, struct rv_jit_context } } +static int emit_ldx(u8 rd, s16 off, u8 rs, u8 size, bool sign_ext, + struct rv_jit_context *ctx) +{ + int insns_start; + + if (is_12b_int(off)) { + insns_start = ctx->ninsns; + emit_ldx_insn(rd, off, rs, size, sign_ext, ctx); + return ctx->ninsns - insns_start; + } + + emit_imm(RV_REG_T1, off, ctx); + emit_add(RV_REG_T1, RV_REG_T1, rs, ctx); + insns_start = ctx->ninsns; + emit_ldx_insn(rd, 0, RV_REG_T1, size, sign_ext, ctx); + return ctx->ninsns - insns_start; +} + static int emit_st(u8 rd, s16 off, s32 imm, u8 size, struct rv_jit_context *ctx) { int insns_start; @@ -622,20 +574,7 @@ static int emit_atomic_ld_st(u8 rd, u8 rs, const struct bpf_insn *insn, switch (imm) { /* dst_reg = load_acquire(src_reg + off16) */ case BPF_LOAD_ACQ: - switch (BPF_SIZE(code)) { - case BPF_B: - emit_load_8(false, rd, off, rs, ctx); - break; - case BPF_H: - emit_load_16(false, rd, off, rs, ctx); - break; - case BPF_W: - emit_load_32(false, rd, off, rs, ctx); - break; - case BPF_DW: - emit_load_64(false, rd, off, rs, ctx); - break; - } + emit_ldx(rd, off, rs, BPF_SIZE(code), false, ctx); emit_fence_r_rw(ctx); /* If our next insn is a redundant zext, return 1 to tell @@ -1859,20 +1798,7 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, rs = RV_REG_T2; } - switch (BPF_SIZE(code)) { - case BPF_B: - insn_len = emit_load_8(sign_ext, rd, off, rs, ctx); - break; - case BPF_H: - insn_len = emit_load_16(sign_ext, rd, off, rs, ctx); - break; - case BPF_W: - insn_len = emit_load_32(sign_ext, rd, off, rs, ctx); - break; - case BPF_DW: - insn_len = emit_load_64(sign_ext, rd, off, rs, ctx); - break; - } + insn_len = emit_ldx(rd, off, rs, BPF_SIZE(code), sign_ext, ctx); ret = add_exception_handler(insn, ctx, rd, insn_len); if (ret) @@ -1882,6 +1808,7 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, return 1; break; } + /* speculation barrier */ case BPF_ST | BPF_NOSPEC: break; From ec74ae56626bad5707d677d3bf05a1e3350a971e Mon Sep 17 00:00:00 2001 From: Pu Lehui Date: Sat, 19 Jul 2025 09:17:24 +0000 Subject: [PATCH 00930/11391] riscv: Separate toolchain support dependency from RISCV_ISA_ZACAS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RV64 bpf is going to support ZACAS instructions. Let's separate toolchain support dependency from RISCV_ISA_ZACAS. Signed-off-by: Pu Lehui Signed-off-by: Daniel Borkmann Tested-by: Björn Töpel Reviewed-by: Björn Töpel Acked-by: Björn Töpel Link: https://lore.kernel.org/bpf/20250719091730.2660197-5-pulehui@huaweicloud.com --- arch/riscv/Kconfig | 1 - arch/riscv/include/asm/cmpxchg.h | 6 ++++-- arch/riscv/kernel/setup.c | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index a4b233a0659e..451eb23d86c9 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -714,7 +714,6 @@ config TOOLCHAIN_HAS_ZACAS config RISCV_ISA_ZACAS bool "Zacas extension support for atomic CAS" - depends on TOOLCHAIN_HAS_ZACAS depends on RISCV_ALTERNATIVE default y help diff --git a/arch/riscv/include/asm/cmpxchg.h b/arch/riscv/include/asm/cmpxchg.h index 0b749e710216..4f4f389282b8 100644 --- a/arch/riscv/include/asm/cmpxchg.h +++ b/arch/riscv/include/asm/cmpxchg.h @@ -133,6 +133,7 @@ ({ \ if (IS_ENABLED(CONFIG_RISCV_ISA_ZABHA) && \ IS_ENABLED(CONFIG_RISCV_ISA_ZACAS) && \ + IS_ENABLED(CONFIG_TOOLCHAIN_HAS_ZACAS) && \ riscv_has_extension_unlikely(RISCV_ISA_EXT_ZABHA) && \ riscv_has_extension_unlikely(RISCV_ISA_EXT_ZACAS)) { \ r = o; \ @@ -180,6 +181,7 @@ r, p, co, o, n) \ ({ \ if (IS_ENABLED(CONFIG_RISCV_ISA_ZACAS) && \ + IS_ENABLED(CONFIG_TOOLCHAIN_HAS_ZACAS) && \ riscv_has_extension_unlikely(RISCV_ISA_EXT_ZACAS)) { \ r = o; \ \ @@ -315,7 +317,7 @@ arch_cmpxchg_release((ptr), (o), (n)); \ }) -#if defined(CONFIG_64BIT) && defined(CONFIG_RISCV_ISA_ZACAS) +#if defined(CONFIG_64BIT) && defined(CONFIG_RISCV_ISA_ZACAS) && defined(CONFIG_TOOLCHAIN_HAS_ZACAS) #define system_has_cmpxchg128() riscv_has_extension_unlikely(RISCV_ISA_EXT_ZACAS) @@ -351,7 +353,7 @@ union __u128_halves { #define arch_cmpxchg128_local(ptr, o, n) \ __arch_cmpxchg128((ptr), (o), (n), "") -#endif /* CONFIG_64BIT && CONFIG_RISCV_ISA_ZACAS */ +#endif /* CONFIG_64BIT && CONFIG_RISCV_ISA_ZACAS && CONFIG_TOOLCHAIN_HAS_ZACAS */ #ifdef CONFIG_RISCV_ISA_ZAWRS /* diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c index f90cce7a3ace..14235e58c539 100644 --- a/arch/riscv/kernel/setup.c +++ b/arch/riscv/kernel/setup.c @@ -290,6 +290,7 @@ static void __init riscv_spinlock_init(void) if (IS_ENABLED(CONFIG_RISCV_ISA_ZABHA) && IS_ENABLED(CONFIG_RISCV_ISA_ZACAS) && + IS_ENABLED(CONFIG_TOOLCHAIN_HAS_ZACAS) && riscv_isa_extension_available(NULL, ZABHA) && riscv_isa_extension_available(NULL, ZACAS)) { using_ext = "using Zabha"; From 5090b339eeb3417baa940d690923e630e077d8f8 Mon Sep 17 00:00:00 2001 From: Pu Lehui Date: Sat, 19 Jul 2025 09:17:25 +0000 Subject: [PATCH 00931/11391] riscv, bpf: Add rv_ext_enabled macro for runtime detection extentsion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add rv_ext_enabled macro to check whether the runtime detection extension is enabled. Signed-off-by: Pu Lehui Signed-off-by: Daniel Borkmann Tested-by: Björn Töpel Reviewed-by: Björn Töpel Acked-by: Björn Töpel Link: https://lore.kernel.org/bpf/20250719091730.2660197-6-pulehui@huaweicloud.com --- arch/riscv/net/bpf_jit.h | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/arch/riscv/net/bpf_jit.h b/arch/riscv/net/bpf_jit.h index e7b032dfd17f..0964df48c25e 100644 --- a/arch/riscv/net/bpf_jit.h +++ b/arch/riscv/net/bpf_jit.h @@ -13,21 +13,15 @@ #include #include +/* verify runtime detection extension status */ +#define rv_ext_enabled(ext) \ + (IS_ENABLED(CONFIG_RISCV_ISA_##ext) && riscv_has_extension_likely(RISCV_ISA_EXT_##ext)) + static inline bool rvc_enabled(void) { return IS_ENABLED(CONFIG_RISCV_ISA_C); } -static inline bool rvzba_enabled(void) -{ - return IS_ENABLED(CONFIG_RISCV_ISA_ZBA) && riscv_has_extension_likely(RISCV_ISA_EXT_ZBA); -} - -static inline bool rvzbb_enabled(void) -{ - return IS_ENABLED(CONFIG_RISCV_ISA_ZBB) && riscv_has_extension_likely(RISCV_ISA_EXT_ZBB); -} - enum { RV_REG_ZERO = 0, /* The constant value 0 */ RV_REG_RA = 1, /* Return address */ @@ -1123,7 +1117,7 @@ static inline void emit_sw(u8 rs1, s32 off, u8 rs2, struct rv_jit_context *ctx) static inline void emit_sh2add(u8 rd, u8 rs1, u8 rs2, struct rv_jit_context *ctx) { - if (rvzba_enabled()) { + if (rv_ext_enabled(ZBA)) { emit(rvzba_sh2add(rd, rs1, rs2), ctx); return; } @@ -1134,7 +1128,7 @@ static inline void emit_sh2add(u8 rd, u8 rs1, u8 rs2, struct rv_jit_context *ctx static inline void emit_sh3add(u8 rd, u8 rs1, u8 rs2, struct rv_jit_context *ctx) { - if (rvzba_enabled()) { + if (rv_ext_enabled(ZBA)) { emit(rvzba_sh3add(rd, rs1, rs2), ctx); return; } @@ -1184,7 +1178,7 @@ static inline void emit_subw(u8 rd, u8 rs1, u8 rs2, struct rv_jit_context *ctx) static inline void emit_sextb(u8 rd, u8 rs, struct rv_jit_context *ctx) { - if (rvzbb_enabled()) { + if (rv_ext_enabled(ZBB)) { emit(rvzbb_sextb(rd, rs), ctx); return; } @@ -1195,7 +1189,7 @@ static inline void emit_sextb(u8 rd, u8 rs, struct rv_jit_context *ctx) static inline void emit_sexth(u8 rd, u8 rs, struct rv_jit_context *ctx) { - if (rvzbb_enabled()) { + if (rv_ext_enabled(ZBB)) { emit(rvzbb_sexth(rd, rs), ctx); return; } @@ -1211,7 +1205,7 @@ static inline void emit_sextw(u8 rd, u8 rs, struct rv_jit_context *ctx) static inline void emit_zexth(u8 rd, u8 rs, struct rv_jit_context *ctx) { - if (rvzbb_enabled()) { + if (rv_ext_enabled(ZBB)) { emit(rvzbb_zexth(rd, rs), ctx); return; } @@ -1222,7 +1216,7 @@ static inline void emit_zexth(u8 rd, u8 rs, struct rv_jit_context *ctx) static inline void emit_zextw(u8 rd, u8 rs, struct rv_jit_context *ctx) { - if (rvzba_enabled()) { + if (rv_ext_enabled(ZBA)) { emit(rvzba_zextw(rd, rs), ctx); return; } @@ -1233,7 +1227,7 @@ static inline void emit_zextw(u8 rd, u8 rs, struct rv_jit_context *ctx) static inline void emit_bswap(u8 rd, s32 imm, struct rv_jit_context *ctx) { - if (rvzbb_enabled()) { + if (rv_ext_enabled(ZBB)) { int bits = 64 - imm; emit(rvzbb_rev8(rd, rd), ctx); From de39d2c4cdb68ece47ff9609dd5c9e87b918d1bd Mon Sep 17 00:00:00 2001 From: Pu Lehui Date: Sat, 19 Jul 2025 09:17:26 +0000 Subject: [PATCH 00932/11391] riscv, bpf: Add Zacas instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add Zacas instructions introduced by [0] to reduce code size and improve performance of RV64 JIT. Signed-off-by: Pu Lehui Signed-off-by: Daniel Borkmann Tested-by: Björn Töpel Reviewed-by: Björn Töpel Acked-by: Björn Töpel Link: https://github.com/riscvarchive/riscv-zacas/releases/download/v1.0/riscv-zacas.pdf [0] Link: https://lore.kernel.org/bpf/20250719091730.2660197-7-pulehui@huaweicloud.com --- arch/riscv/net/bpf_jit.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/riscv/net/bpf_jit.h b/arch/riscv/net/bpf_jit.h index 0964df48c25e..2351fba5d3e7 100644 --- a/arch/riscv/net/bpf_jit.h +++ b/arch/riscv/net/bpf_jit.h @@ -751,6 +751,17 @@ static inline u16 rvc_swsp(u32 imm8, u8 rs2) return rv_css_insn(0x6, imm, rs2, 0x2); } +/* RVZACAS instructions. */ +static inline u32 rvzacas_amocas_w(u8 rd, u8 rs2, u8 rs1, u8 aq, u8 rl) +{ + return rv_amo_insn(0x5, aq, rl, rs2, rs1, 2, rd, 0x2f); +} + +static inline u32 rvzacas_amocas_d(u8 rd, u8 rs2, u8 rs1, u8 aq, u8 rl) +{ + return rv_amo_insn(0x5, aq, rl, rs2, rs1, 3, rd, 0x2f); +} + /* RVZBA instructions. */ static inline u32 rvzba_sh2add(u8 rd, u8 rs1, u8 rs2) { From 1c0196b878a69927449d649163388ad63cafcacb Mon Sep 17 00:00:00 2001 From: Pu Lehui Date: Sat, 19 Jul 2025 09:17:27 +0000 Subject: [PATCH 00933/11391] riscv, bpf: Optimize cmpxchg insn with Zacas support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Optimize cmpxchg instruction with amocas.w and amocas.d Zacas instructions. Signed-off-by: Pu Lehui Signed-off-by: Daniel Borkmann Tested-by: Björn Töpel Reviewed-by: Björn Töpel Acked-by: Björn Töpel Link: https://lore.kernel.org/bpf/20250719091730.2660197-8-pulehui@huaweicloud.com --- arch/riscv/net/bpf_jit.h | 27 +++++++++++++++++++++++++++ arch/riscv/net/bpf_jit_comp64.c | 18 ++---------------- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/arch/riscv/net/bpf_jit.h b/arch/riscv/net/bpf_jit.h index 2351fba5d3e7..0790f40b7e9d 100644 --- a/arch/riscv/net/bpf_jit.h +++ b/arch/riscv/net/bpf_jit.h @@ -1294,6 +1294,33 @@ static inline void emit_bswap(u8 rd, s32 imm, struct rv_jit_context *ctx) emit_mv(rd, RV_REG_T2, ctx); } +static inline void emit_cmpxchg(u8 rd, u8 rs, u8 r0, bool is64, struct rv_jit_context *ctx) +{ + int jmp_offset; + + if (rv_ext_enabled(ZACAS)) { + emit(is64 ? rvzacas_amocas_d(r0, rs, rd, 1, 1) : + rvzacas_amocas_w(r0, rs, rd, 1, 1), ctx); + if (!is64) + emit_zextw(r0, r0, ctx); + return; + } + + if (is64) + emit_mv(RV_REG_T2, r0, ctx); + else + emit_addiw(RV_REG_T2, r0, 0, ctx); + emit(is64 ? rv_lr_d(r0, 0, rd, 0, 0) : + rv_lr_w(r0, 0, rd, 0, 0), ctx); + jmp_offset = ninsns_rvoff(8); + emit(rv_bne(RV_REG_T2, r0, jmp_offset >> 1), ctx); + emit(is64 ? rv_sc_d(RV_REG_T3, rs, rd, 0, 1) : + rv_sc_w(RV_REG_T3, rs, rd, 0, 1), ctx); + jmp_offset = ninsns_rvoff(-6); + emit(rv_bne(RV_REG_T3, 0, jmp_offset >> 1), ctx); + emit_fence_rw_rw(ctx); +} + #endif /* __riscv_xlen == 64 */ void bpf_jit_build_prologue(struct rv_jit_context *ctx, bool is_subprog); diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c index a6a9fd9193e5..8e813809d305 100644 --- a/arch/riscv/net/bpf_jit_comp64.c +++ b/arch/riscv/net/bpf_jit_comp64.c @@ -599,10 +599,9 @@ static int emit_atomic_ld_st(u8 rd, u8 rs, const struct bpf_insn *insn, static int emit_atomic_rmw(u8 rd, u8 rs, const struct bpf_insn *insn, struct rv_jit_context *ctx) { - u8 r0, code = insn->code; + u8 code = insn->code; s16 off = insn->off; s32 imm = insn->imm; - int jmp_offset; bool is64; if (BPF_SIZE(code) != BPF_W && BPF_SIZE(code) != BPF_DW) { @@ -673,20 +672,7 @@ static int emit_atomic_rmw(u8 rd, u8 rs, const struct bpf_insn *insn, break; /* r0 = atomic_cmpxchg(dst_reg + off16, r0, src_reg); */ case BPF_CMPXCHG: - r0 = bpf_to_rv_reg(BPF_REG_0, ctx); - if (is64) - emit_mv(RV_REG_T2, r0, ctx); - else - emit_addiw(RV_REG_T2, r0, 0, ctx); - emit(is64 ? rv_lr_d(r0, 0, rd, 0, 0) : - rv_lr_w(r0, 0, rd, 0, 0), ctx); - jmp_offset = ninsns_rvoff(8); - emit(rv_bne(RV_REG_T2, r0, jmp_offset >> 1), ctx); - emit(is64 ? rv_sc_d(RV_REG_T3, rs, rd, 0, 1) : - rv_sc_w(RV_REG_T3, rs, rd, 0, 1), ctx); - jmp_offset = ninsns_rvoff(-6); - emit(rv_bne(RV_REG_T3, 0, jmp_offset >> 1), ctx); - emit_fence_rw_rw(ctx); + emit_cmpxchg(rd, rs, regmap[BPF_REG_0], is64, ctx); break; default: pr_err_once("bpf-jit: invalid atomic RMW opcode %02x\n", imm); From b18f4aae6a5db5ada5aba02b43dbdd3909e5f87c Mon Sep 17 00:00:00 2001 From: Pu Lehui Date: Sat, 19 Jul 2025 09:17:28 +0000 Subject: [PATCH 00934/11391] riscv, bpf: Add ex_insn_off and ex_jmp_off for exception table handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add ex_insn_off and ex_jmp_off fields to struct rv_jit_context so that add_exception_handler() does not need to be immediately followed by the instruction to add the exception table. ex_insn_off indicates the offset of the instruction to add the exception table, and ex_jmp_off indicates the offset to jump over the faulting instruction. This is to prepare for adding the exception table to atomic instructions later, because some atomic instructions need to perform zext or other operations. Signed-off-by: Pu Lehui Signed-off-by: Daniel Borkmann Tested-by: Björn Töpel Reviewed-by: Björn Töpel Acked-by: Björn Töpel Link: https://lore.kernel.org/bpf/20250719091730.2660197-9-pulehui@huaweicloud.com --- arch/riscv/net/bpf_jit.h | 2 + arch/riscv/net/bpf_jit_comp64.c | 84 +++++++++++++++------------------ 2 files changed, 39 insertions(+), 47 deletions(-) diff --git a/arch/riscv/net/bpf_jit.h b/arch/riscv/net/bpf_jit.h index 0790f40b7e9d..be2915444ce5 100644 --- a/arch/riscv/net/bpf_jit.h +++ b/arch/riscv/net/bpf_jit.h @@ -78,6 +78,8 @@ struct rv_jit_context { int epilogue_offset; int *offset; /* BPF to RV */ int nexentries; + int ex_insn_off; + int ex_jmp_off; unsigned long flags; int stack_size; u64 arena_vm_start; diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c index 8e813809d305..56b592af53a6 100644 --- a/arch/riscv/net/bpf_jit_comp64.c +++ b/arch/riscv/net/bpf_jit_comp64.c @@ -511,57 +511,54 @@ static void emit_stx_insn(u8 rd, s16 off, u8 rs, u8 size, struct rv_jit_context } } -static int emit_ldx(u8 rd, s16 off, u8 rs, u8 size, bool sign_ext, +static void emit_ldx(u8 rd, s16 off, u8 rs, u8 size, bool sign_ext, struct rv_jit_context *ctx) { - int insns_start; - if (is_12b_int(off)) { - insns_start = ctx->ninsns; + ctx->ex_insn_off = ctx->ninsns; emit_ldx_insn(rd, off, rs, size, sign_ext, ctx); - return ctx->ninsns - insns_start; + ctx->ex_jmp_off = ctx->ninsns; + return; } emit_imm(RV_REG_T1, off, ctx); emit_add(RV_REG_T1, RV_REG_T1, rs, ctx); - insns_start = ctx->ninsns; + ctx->ex_insn_off = ctx->ninsns; emit_ldx_insn(rd, 0, RV_REG_T1, size, sign_ext, ctx); - return ctx->ninsns - insns_start; + ctx->ex_jmp_off = ctx->ninsns; } -static int emit_st(u8 rd, s16 off, s32 imm, u8 size, struct rv_jit_context *ctx) +static void emit_st(u8 rd, s16 off, s32 imm, u8 size, struct rv_jit_context *ctx) { - int insns_start; - emit_imm(RV_REG_T1, imm, ctx); if (is_12b_int(off)) { - insns_start = ctx->ninsns; + ctx->ex_insn_off = ctx->ninsns; emit_stx_insn(rd, off, RV_REG_T1, size, ctx); - return ctx->ninsns - insns_start; + ctx->ex_jmp_off = ctx->ninsns; + return; } emit_imm(RV_REG_T2, off, ctx); emit_add(RV_REG_T2, RV_REG_T2, rd, ctx); - insns_start = ctx->ninsns; + ctx->ex_insn_off = ctx->ninsns; emit_stx_insn(RV_REG_T2, 0, RV_REG_T1, size, ctx); - return ctx->ninsns - insns_start; + ctx->ex_jmp_off = ctx->ninsns; } -static int emit_stx(u8 rd, s16 off, u8 rs, u8 size, struct rv_jit_context *ctx) +static void emit_stx(u8 rd, s16 off, u8 rs, u8 size, struct rv_jit_context *ctx) { - int insns_start; - if (is_12b_int(off)) { - insns_start = ctx->ninsns; + ctx->ex_insn_off = ctx->ninsns; emit_stx_insn(rd, off, rs, size, ctx); - return ctx->ninsns - insns_start; + ctx->ex_jmp_off = ctx->ninsns; + return; } emit_imm(RV_REG_T1, off, ctx); emit_add(RV_REG_T1, RV_REG_T1, rd, ctx); - insns_start = ctx->ninsns; + ctx->ex_insn_off = ctx->ninsns; emit_stx_insn(RV_REG_T1, 0, rs, size, ctx); - return ctx->ninsns - insns_start; + ctx->ex_jmp_off = ctx->ninsns; } static int emit_atomic_ld_st(u8 rd, u8 rs, const struct bpf_insn *insn, @@ -700,9 +697,8 @@ bool ex_handler_bpf(const struct exception_table_entry *ex, } /* For accesses to BTF pointers, add an entry to the exception table */ -static int add_exception_handler(const struct bpf_insn *insn, - struct rv_jit_context *ctx, - int dst_reg, int insn_len) +static int add_exception_handler(const struct bpf_insn *insn, int dst_reg, + struct rv_jit_context *ctx) { struct exception_table_entry *ex; unsigned long pc; @@ -710,21 +706,22 @@ static int add_exception_handler(const struct bpf_insn *insn, off_t fixup_offset; if (!ctx->insns || !ctx->ro_insns || !ctx->prog->aux->extable || - (BPF_MODE(insn->code) != BPF_PROBE_MEM && BPF_MODE(insn->code) != BPF_PROBE_MEMSX && - BPF_MODE(insn->code) != BPF_PROBE_MEM32)) + ctx->ex_insn_off <= 0 || ctx->ex_jmp_off <= 0) + return 0; + + if (BPF_MODE(insn->code) != BPF_PROBE_MEM && + BPF_MODE(insn->code) != BPF_PROBE_MEMSX && + BPF_MODE(insn->code) != BPF_PROBE_MEM32) return 0; if (WARN_ON_ONCE(ctx->nexentries >= ctx->prog->aux->num_exentries)) return -EINVAL; - if (WARN_ON_ONCE(insn_len > ctx->ninsns)) - return -EINVAL; - - if (WARN_ON_ONCE(!rvc_enabled() && insn_len == 1)) + if (WARN_ON_ONCE(ctx->ex_insn_off > ctx->ninsns || ctx->ex_jmp_off > ctx->ninsns)) return -EINVAL; ex = &ctx->prog->aux->extable[ctx->nexentries]; - pc = (unsigned long)&ctx->ro_insns[ctx->ninsns - insn_len]; + pc = (unsigned long)&ctx->ro_insns[ctx->ex_insn_off]; /* * This is the relative offset of the instruction that may fault from @@ -748,7 +745,7 @@ static int add_exception_handler(const struct bpf_insn *insn, * that may fault. The execution will jump to this after handling the * fault. */ - fixup_offset = (long)&ex->fixup - (pc + insn_len * sizeof(u16)); + fixup_offset = (long)&ex->fixup - (long)&ctx->ro_insns[ctx->ex_jmp_off]; if (!FIELD_FIT(BPF_FIXUP_OFFSET_MASK, fixup_offset)) return -ERANGE; @@ -765,6 +762,8 @@ static int add_exception_handler(const struct bpf_insn *insn, FIELD_PREP(BPF_FIXUP_REG_MASK, dst_reg); ex->type = EX_TYPE_BPF; + ctx->ex_insn_off = 0; + ctx->ex_jmp_off = 0; ctx->nexentries++; return 0; } @@ -1774,7 +1773,6 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, case BPF_LDX | BPF_PROBE_MEM32 | BPF_DW: { bool sign_ext; - int insn_len; sign_ext = BPF_MODE(insn->code) == BPF_MEMSX || BPF_MODE(insn->code) == BPF_PROBE_MEMSX; @@ -1784,9 +1782,9 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, rs = RV_REG_T2; } - insn_len = emit_ldx(rd, off, rs, BPF_SIZE(code), sign_ext, ctx); + emit_ldx(rd, off, rs, BPF_SIZE(code), sign_ext, ctx); - ret = add_exception_handler(insn, ctx, rd, insn_len); + ret = add_exception_handler(insn, rd, ctx); if (ret) return ret; @@ -1809,21 +1807,17 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, case BPF_ST | BPF_PROBE_MEM32 | BPF_H: case BPF_ST | BPF_PROBE_MEM32 | BPF_W: case BPF_ST | BPF_PROBE_MEM32 | BPF_DW: - { - int insn_len; - if (BPF_MODE(insn->code) == BPF_PROBE_MEM32) { emit_add(RV_REG_T3, rd, RV_REG_ARENA, ctx); rd = RV_REG_T3; } - insn_len = emit_st(rd, off, imm, BPF_SIZE(code), ctx); + emit_st(rd, off, imm, BPF_SIZE(code), ctx); - ret = add_exception_handler(insn, ctx, REG_DONT_CLEAR_MARKER, insn_len); + ret = add_exception_handler(insn, REG_DONT_CLEAR_MARKER, ctx); if (ret) return ret; break; - } /* STX: *(size *)(dst + off) = src */ case BPF_STX | BPF_MEM | BPF_B: @@ -1835,21 +1829,17 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, case BPF_STX | BPF_PROBE_MEM32 | BPF_H: case BPF_STX | BPF_PROBE_MEM32 | BPF_W: case BPF_STX | BPF_PROBE_MEM32 | BPF_DW: - { - int insn_len; - if (BPF_MODE(insn->code) == BPF_PROBE_MEM32) { emit_add(RV_REG_T2, rd, RV_REG_ARENA, ctx); rd = RV_REG_T2; } - insn_len = emit_stx(rd, off, rs, BPF_SIZE(code), ctx); + emit_stx(rd, off, rs, BPF_SIZE(code), ctx); - ret = add_exception_handler(insn, ctx, REG_DONT_CLEAR_MARKER, insn_len); + ret = add_exception_handler(insn, REG_DONT_CLEAR_MARKER, ctx); if (ret) return ret; break; - } case BPF_STX | BPF_ATOMIC | BPF_B: case BPF_STX | BPF_ATOMIC | BPF_H: From fb7cefabae8117c203155ef169a386bec43bbba9 Mon Sep 17 00:00:00 2001 From: Pu Lehui Date: Sat, 19 Jul 2025 09:17:29 +0000 Subject: [PATCH 00935/11391] riscv, bpf: Add support arena atomics for RV64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add arena atomics support for RMW atomics and load-acquire and store-release instructions. Non-Zacas cmpxchg is implemented via loop, which is not currently supported because it requires more complex extable and loop logic. Signed-off-by: Pu Lehui Signed-off-by: Daniel Borkmann Tested-by: Björn Töpel Reviewed-by: Björn Töpel Acked-by: Björn Töpel Link: https://lore.kernel.org/bpf/20250719091730.2660197-10-pulehui@huaweicloud.com --- arch/riscv/net/bpf_jit.h | 2 ++ arch/riscv/net/bpf_jit_comp64.c | 60 +++++++++++++++++++++++++++++++-- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/arch/riscv/net/bpf_jit.h b/arch/riscv/net/bpf_jit.h index be2915444ce5..632ced07bca4 100644 --- a/arch/riscv/net/bpf_jit.h +++ b/arch/riscv/net/bpf_jit.h @@ -1301,8 +1301,10 @@ static inline void emit_cmpxchg(u8 rd, u8 rs, u8 r0, bool is64, struct rv_jit_co int jmp_offset; if (rv_ext_enabled(ZACAS)) { + ctx->ex_insn_off = ctx->ninsns; emit(is64 ? rvzacas_amocas_d(r0, rs, rd, 1, 1) : rvzacas_amocas_w(r0, rs, rd, 1, 1), ctx); + ctx->ex_jmp_off = ctx->ninsns; if (!is64) emit_zextw(r0, r0, ctx); return; diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c index 56b592af53a6..549c3063c7f1 100644 --- a/arch/riscv/net/bpf_jit_comp64.c +++ b/arch/riscv/net/bpf_jit_comp64.c @@ -571,6 +571,11 @@ static int emit_atomic_ld_st(u8 rd, u8 rs, const struct bpf_insn *insn, switch (imm) { /* dst_reg = load_acquire(src_reg + off16) */ case BPF_LOAD_ACQ: + if (BPF_MODE(code) == BPF_PROBE_ATOMIC) { + emit_add(RV_REG_T2, rs, RV_REG_ARENA, ctx); + rs = RV_REG_T2; + } + emit_ldx(rd, off, rs, BPF_SIZE(code), false, ctx); emit_fence_r_rw(ctx); @@ -582,6 +587,11 @@ static int emit_atomic_ld_st(u8 rd, u8 rs, const struct bpf_insn *insn, break; /* store_release(dst_reg + off16, src_reg) */ case BPF_STORE_REL: + if (BPF_MODE(code) == BPF_PROBE_ATOMIC) { + emit_add(RV_REG_T2, rd, RV_REG_ARENA, ctx); + rd = RV_REG_T2; + } + emit_fence_rw_w(ctx); emit_stx(rd, off, rs, BPF_SIZE(code), ctx); break; @@ -599,13 +609,12 @@ static int emit_atomic_rmw(u8 rd, u8 rs, const struct bpf_insn *insn, u8 code = insn->code; s16 off = insn->off; s32 imm = insn->imm; - bool is64; + bool is64 = BPF_SIZE(code) == BPF_DW; if (BPF_SIZE(code) != BPF_W && BPF_SIZE(code) != BPF_DW) { pr_err_once("bpf-jit: 1- and 2-byte RMW atomics are not supported\n"); return -EINVAL; } - is64 = BPF_SIZE(code) == BPF_DW; if (off) { if (is_12b_int(off)) { @@ -617,53 +626,76 @@ static int emit_atomic_rmw(u8 rd, u8 rs, const struct bpf_insn *insn, rd = RV_REG_T1; } + if (BPF_MODE(code) == BPF_PROBE_ATOMIC) { + emit_add(RV_REG_T1, rd, RV_REG_ARENA, ctx); + rd = RV_REG_T1; + } + switch (imm) { /* lock *(u32/u64 *)(dst_reg + off16) = src_reg */ case BPF_ADD: + ctx->ex_insn_off = ctx->ninsns; emit(is64 ? rv_amoadd_d(RV_REG_ZERO, rs, rd, 0, 0) : rv_amoadd_w(RV_REG_ZERO, rs, rd, 0, 0), ctx); + ctx->ex_jmp_off = ctx->ninsns; break; case BPF_AND: + ctx->ex_insn_off = ctx->ninsns; emit(is64 ? rv_amoand_d(RV_REG_ZERO, rs, rd, 0, 0) : rv_amoand_w(RV_REG_ZERO, rs, rd, 0, 0), ctx); + ctx->ex_jmp_off = ctx->ninsns; break; case BPF_OR: + ctx->ex_insn_off = ctx->ninsns; emit(is64 ? rv_amoor_d(RV_REG_ZERO, rs, rd, 0, 0) : rv_amoor_w(RV_REG_ZERO, rs, rd, 0, 0), ctx); + ctx->ex_jmp_off = ctx->ninsns; break; case BPF_XOR: + ctx->ex_insn_off = ctx->ninsns; emit(is64 ? rv_amoxor_d(RV_REG_ZERO, rs, rd, 0, 0) : rv_amoxor_w(RV_REG_ZERO, rs, rd, 0, 0), ctx); + ctx->ex_jmp_off = ctx->ninsns; break; /* src_reg = atomic_fetch_(dst_reg + off16, src_reg) */ case BPF_ADD | BPF_FETCH: + ctx->ex_insn_off = ctx->ninsns; emit(is64 ? rv_amoadd_d(rs, rs, rd, 1, 1) : rv_amoadd_w(rs, rs, rd, 1, 1), ctx); + ctx->ex_jmp_off = ctx->ninsns; if (!is64) emit_zextw(rs, rs, ctx); break; case BPF_AND | BPF_FETCH: + ctx->ex_insn_off = ctx->ninsns; emit(is64 ? rv_amoand_d(rs, rs, rd, 1, 1) : rv_amoand_w(rs, rs, rd, 1, 1), ctx); + ctx->ex_jmp_off = ctx->ninsns; if (!is64) emit_zextw(rs, rs, ctx); break; case BPF_OR | BPF_FETCH: + ctx->ex_insn_off = ctx->ninsns; emit(is64 ? rv_amoor_d(rs, rs, rd, 1, 1) : rv_amoor_w(rs, rs, rd, 1, 1), ctx); + ctx->ex_jmp_off = ctx->ninsns; if (!is64) emit_zextw(rs, rs, ctx); break; case BPF_XOR | BPF_FETCH: + ctx->ex_insn_off = ctx->ninsns; emit(is64 ? rv_amoxor_d(rs, rs, rd, 1, 1) : rv_amoxor_w(rs, rs, rd, 1, 1), ctx); + ctx->ex_jmp_off = ctx->ninsns; if (!is64) emit_zextw(rs, rs, ctx); break; /* src_reg = atomic_xchg(dst_reg + off16, src_reg); */ case BPF_XCHG: + ctx->ex_insn_off = ctx->ninsns; emit(is64 ? rv_amoswap_d(rs, rs, rd, 1, 1) : rv_amoswap_w(rs, rs, rd, 1, 1), ctx); + ctx->ex_jmp_off = ctx->ninsns; if (!is64) emit_zextw(rs, rs, ctx); break; @@ -711,7 +743,8 @@ static int add_exception_handler(const struct bpf_insn *insn, int dst_reg, if (BPF_MODE(insn->code) != BPF_PROBE_MEM && BPF_MODE(insn->code) != BPF_PROBE_MEMSX && - BPF_MODE(insn->code) != BPF_PROBE_MEM32) + BPF_MODE(insn->code) != BPF_PROBE_MEM32 && + BPF_MODE(insn->code) != BPF_PROBE_ATOMIC) return 0; if (WARN_ON_ONCE(ctx->nexentries >= ctx->prog->aux->num_exentries)) @@ -1841,14 +1874,21 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, return ret; break; + /* Atomics */ case BPF_STX | BPF_ATOMIC | BPF_B: case BPF_STX | BPF_ATOMIC | BPF_H: case BPF_STX | BPF_ATOMIC | BPF_W: case BPF_STX | BPF_ATOMIC | BPF_DW: + case BPF_STX | BPF_PROBE_ATOMIC | BPF_B: + case BPF_STX | BPF_PROBE_ATOMIC | BPF_H: + case BPF_STX | BPF_PROBE_ATOMIC | BPF_W: + case BPF_STX | BPF_PROBE_ATOMIC | BPF_DW: if (bpf_atomic_is_load_store(insn)) ret = emit_atomic_ld_st(rd, rs, insn, ctx); else ret = emit_atomic_rmw(rd, rs, insn, ctx); + + ret = ret ?: add_exception_handler(insn, REG_DONT_CLEAR_MARKER, ctx); if (ret) return ret; break; @@ -1979,6 +2019,20 @@ bool bpf_jit_supports_arena(void) return true; } +bool bpf_jit_supports_insn(struct bpf_insn *insn, bool in_arena) +{ + if (in_arena) { + switch (insn->code) { + case BPF_STX | BPF_ATOMIC | BPF_W: + case BPF_STX | BPF_ATOMIC | BPF_DW: + if (insn->imm == BPF_CMPXCHG) + return rv_ext_enabled(ZACAS); + } + } + + return true; +} + bool bpf_jit_supports_percpu_insn(void) { return true; From dc0fe956144d9ba906bc6b2fe35b3cd54e1bfdb0 Mon Sep 17 00:00:00 2001 From: Pu Lehui Date: Sat, 19 Jul 2025 09:17:30 +0000 Subject: [PATCH 00936/11391] selftests/bpf: Enable arena atomics tests for RV64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable arena atomics tests for RV64. Signed-off-by: Pu Lehui Signed-off-by: Daniel Borkmann Tested-by: Björn Töpel Reviewed-by: Björn Töpel Acked-by: Björn Töpel Link: https://lore.kernel.org/bpf/20250719091730.2660197-11-pulehui@huaweicloud.com --- tools/testing/selftests/bpf/progs/arena_atomics.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/bpf/progs/arena_atomics.c b/tools/testing/selftests/bpf/progs/arena_atomics.c index a52feff98112..d1841aac94a2 100644 --- a/tools/testing/selftests/bpf/progs/arena_atomics.c +++ b/tools/testing/selftests/bpf/progs/arena_atomics.c @@ -28,7 +28,8 @@ bool skip_all_tests = true; #if defined(ENABLE_ATOMICS_TESTS) && \ defined(__BPF_FEATURE_ADDR_SPACE_CAST) && \ - (defined(__TARGET_ARCH_arm64) || defined(__TARGET_ARCH_x86)) + (defined(__TARGET_ARCH_arm64) || defined(__TARGET_ARCH_x86) || \ + (defined(__TARGET_ARCH_riscv) && __riscv_xlen == 64)) bool skip_lacq_srel_tests __attribute((__section__(".data"))) = false; #else bool skip_lacq_srel_tests = true; @@ -314,7 +315,8 @@ int load_acquire(const void *ctx) { #if defined(ENABLE_ATOMICS_TESTS) && \ defined(__BPF_FEATURE_ADDR_SPACE_CAST) && \ - (defined(__TARGET_ARCH_arm64) || defined(__TARGET_ARCH_x86)) + (defined(__TARGET_ARCH_arm64) || defined(__TARGET_ARCH_x86) || \ + (defined(__TARGET_ARCH_riscv) && __riscv_xlen == 64)) #define LOAD_ACQUIRE_ARENA(SIZEOP, SIZE, SRC, DST) \ { asm volatile ( \ @@ -365,7 +367,8 @@ int store_release(const void *ctx) { #if defined(ENABLE_ATOMICS_TESTS) && \ defined(__BPF_FEATURE_ADDR_SPACE_CAST) && \ - (defined(__TARGET_ARCH_arm64) || defined(__TARGET_ARCH_x86)) + (defined(__TARGET_ARCH_arm64) || defined(__TARGET_ARCH_x86) || \ + (defined(__TARGET_ARCH_riscv) && __riscv_xlen == 64)) #define STORE_RELEASE_ARENA(SIZEOP, DST, VAL) \ { asm volatile ( \ From 5d6d30eca4dd1c9e8515a8d4b13106205d5c0ec4 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 14 Aug 2025 18:31:37 -0700 Subject: [PATCH 00937/11391] x86/build: Remove cc-option for GCC retpoline flags The minimum supported version of GCC to build the x86 kernel was bumped to GCC 8.1 in a3e8fe814ad1 ("x86/build: Raise the minimum GCC version to 8.1"). '-mindirect-branch' and '-mindirect-branch-register' were first supported in GCC 8.1, so there is no need to call cc-option to inquire if it is supported. Signed-off-by: Nathan Chancellor Signed-off-by: Borislav Petkov (AMD) Link: https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=da99fd4a3ca06b43b08ba8d96dab84e83ac90aa7 Link: https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=d543c04b795f8af4ebe5b3d5f38156ef4e5734f1 Link: https://lore.kernel.org/20250814-x86-min-ver-cleanups-v1-1-ff7f19457523@kernel.org --- arch/x86/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 1913d342969b..ed5657395d6a 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -13,8 +13,8 @@ else endif ifdef CONFIG_CC_IS_GCC -RETPOLINE_CFLAGS := $(call cc-option,-mindirect-branch=thunk-extern -mindirect-branch-register) -RETPOLINE_VDSO_CFLAGS := $(call cc-option,-mindirect-branch=thunk-inline -mindirect-branch-register) +RETPOLINE_CFLAGS := -mindirect-branch=thunk-extern -mindirect-branch-register +RETPOLINE_VDSO_CFLAGS := -mindirect-branch=thunk-inline -mindirect-branch-register endif ifdef CONFIG_CC_IS_CLANG RETPOLINE_CFLAGS := -mretpoline-external-thunk From e8c4f6ee8eeed8e02800bed6afb9aa22fc3476a1 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 12 Aug 2025 12:38:59 +0200 Subject: [PATCH 00938/11391] perf: Remove redundant condition for AUX buffer size It is already checked whether the VMA size is the same as nr_pages * PAGE_SIZE, so later checking both: aux_size == vma_size && aux_size == nr_pages * PAGE_SIZE is redundant. Remove the vma_size check as nr_pages is what is actually used in the allocation function. That prepares for splitting out the buffer allocation into separate functions, so that only nr_pages needs to be handed in. No functional change. Signed-off-by: Thomas Gleixner Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Lorenzo Stoakes Link: https://lore.kernel.org/r/20250812104018.424519320@infradead.org --- kernel/events/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 8060c2857bb2..eea3a7d6c61d 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -7043,7 +7043,7 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) if (rb_has_aux(rb) && rb->aux_pgoff != vma->vm_pgoff) goto aux_unlock; - if (aux_size != vma_size || aux_size != nr_pages * PAGE_SIZE) + if (aux_size != nr_pages * PAGE_SIZE) goto aux_unlock; /* already mapped with a different size */ From 81e026ca47b386e4213c1beff069038a3ba8bb76 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 12 Aug 2025 12:39:00 +0200 Subject: [PATCH 00939/11391] perf: Split out mlock limit handling To prepare for splitting the buffer allocation out into separate functions for the ring buffer and the AUX buffer, split out mlock limit handling into a helper function, which can be called from both. No functional change intended. Signed-off-by: Thomas Gleixner Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Lorenzo Stoakes Link: https://lore.kernel.org/r/20250812104018.541975109@infradead.org --- kernel/events/core.c | 75 ++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index eea3a7d6c61d..f6299012ed73 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -6927,17 +6927,49 @@ static int map_range(struct perf_buffer *rb, struct vm_area_struct *vma) return err; } +static bool perf_mmap_calc_limits(struct vm_area_struct *vma, long *user_extra, long *extra) +{ + unsigned long user_locked, user_lock_limit, locked, lock_limit; + struct user_struct *user = current_user(); + + user_lock_limit = sysctl_perf_event_mlock >> (PAGE_SHIFT - 10); + /* Increase the limit linearly with more CPUs */ + user_lock_limit *= num_online_cpus(); + + user_locked = atomic_long_read(&user->locked_vm); + + /* + * sysctl_perf_event_mlock may have changed, so that + * user->locked_vm > user_lock_limit + */ + if (user_locked > user_lock_limit) + user_locked = user_lock_limit; + user_locked += *user_extra; + + if (user_locked > user_lock_limit) { + /* + * charge locked_vm until it hits user_lock_limit; + * charge the rest from pinned_vm + */ + *extra = user_locked - user_lock_limit; + *user_extra -= *extra; + } + + lock_limit = rlimit(RLIMIT_MEMLOCK); + lock_limit >>= PAGE_SHIFT; + locked = atomic64_read(&vma->vm_mm->pinned_vm) + *extra; + + return locked <= lock_limit || !perf_is_paranoid() || capable(CAP_IPC_LOCK); +} + static int perf_mmap(struct file *file, struct vm_area_struct *vma) { struct perf_event *event = file->private_data; - unsigned long user_locked, user_lock_limit; struct user_struct *user = current_user(); + unsigned long vma_size, nr_pages; + long user_extra = 0, extra = 0; struct mutex *aux_mutex = NULL; struct perf_buffer *rb = NULL; - unsigned long locked, lock_limit; - unsigned long vma_size; - unsigned long nr_pages; - long user_extra = 0, extra = 0; int ret, flags = 0; mapped_f mapped; @@ -7063,38 +7095,7 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) } } - user_lock_limit = sysctl_perf_event_mlock >> (PAGE_SHIFT - 10); - - /* - * Increase the limit linearly with more CPUs: - */ - user_lock_limit *= num_online_cpus(); - - user_locked = atomic_long_read(&user->locked_vm); - - /* - * sysctl_perf_event_mlock may have changed, so that - * user->locked_vm > user_lock_limit - */ - if (user_locked > user_lock_limit) - user_locked = user_lock_limit; - user_locked += user_extra; - - if (user_locked > user_lock_limit) { - /* - * charge locked_vm until it hits user_lock_limit; - * charge the rest from pinned_vm - */ - extra = user_locked - user_lock_limit; - user_extra -= extra; - } - - lock_limit = rlimit(RLIMIT_MEMLOCK); - lock_limit >>= PAGE_SHIFT; - locked = atomic64_read(&vma->vm_mm->pinned_vm) + extra; - - if ((locked > lock_limit) && perf_is_paranoid() && - !capable(CAP_IPC_LOCK)) { + if (!perf_mmap_calc_limits(vma, &user_extra, &extra)) { ret = -EPERM; goto unlock; } From 1ea3e3b0dadc06c5e6c1bdf5312e70ee861b1ba0 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 12 Aug 2025 12:39:01 +0200 Subject: [PATCH 00940/11391] perf: Split out VM accounting Similarly to the mlock limit calculation the VM accounting is required for both the ringbuffer and the AUX buffer allocations. To prepare for splitting them out into separate functions, move the accounting into a helper function. Signed-off-by: Thomas Gleixner Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Lorenzo Stoakes Link: https://lore.kernel.org/r/20250812104018.660347811@infradead.org --- kernel/events/core.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index f6299012ed73..f90847101ade 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -6962,10 +6962,17 @@ static bool perf_mmap_calc_limits(struct vm_area_struct *vma, long *user_extra, return locked <= lock_limit || !perf_is_paranoid() || capable(CAP_IPC_LOCK); } +static void perf_mmap_account(struct vm_area_struct *vma, long user_extra, long extra) +{ + struct user_struct *user = current_user(); + + atomic_long_add(user_extra, &user->locked_vm); + atomic64_add(extra, &vma->vm_mm->pinned_vm); +} + static int perf_mmap(struct file *file, struct vm_area_struct *vma) { struct perf_event *event = file->private_data; - struct user_struct *user = current_user(); unsigned long vma_size, nr_pages; long user_extra = 0, extra = 0; struct mutex *aux_mutex = NULL; @@ -7136,9 +7143,7 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) unlock: if (!ret) { - atomic_long_add(user_extra, &user->locked_vm); - atomic64_add(extra, &vma->vm_mm->pinned_vm); - + perf_mmap_account(vma, user_extra, extra); atomic_inc(&event->mmap_count); } else if (rb) { /* AUX allocation failed */ From 86a0a7c59845e7093c9c73a7115c9d86349499d1 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 12 Aug 2025 12:39:02 +0200 Subject: [PATCH 00941/11391] perf: Move perf_mmap_calc_limits() into both rb and aux branches if (cond) { A; } else { B; } C; into if (cond) { A; C; } else { B; C; } Suggested-by: Thomas Gleixner Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Lorenzo Stoakes Link: https://lore.kernel.org/r/20250812104018.781244099@infradead.org --- kernel/events/core.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index f90847101ade..9f19c612c80f 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -7054,6 +7054,16 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) ring_buffer_attach(event, NULL); } + if (!perf_mmap_calc_limits(vma, &user_extra, &extra)) { + ret = -EPERM; + goto unlock; + } + + WARN_ON(!rb && event->rb); + + if (vma->vm_flags & VM_WRITE) + flags |= RING_BUFFER_WRITABLE; + } else { /* * AUX area mapping: if rb->aux_nr_pages != 0, it's already @@ -7100,18 +7110,18 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) ret = 0; goto unlock; } + + if (!perf_mmap_calc_limits(vma, &user_extra, &extra)) { + ret = -EPERM; + goto unlock; + } + + WARN_ON(!rb && event->rb); + + if (vma->vm_flags & VM_WRITE) + flags |= RING_BUFFER_WRITABLE; } - if (!perf_mmap_calc_limits(vma, &user_extra, &extra)) { - ret = -EPERM; - goto unlock; - } - - WARN_ON(!rb && event->rb); - - if (vma->vm_flags & VM_WRITE) - flags |= RING_BUFFER_WRITABLE; - if (!rb) { rb = rb_alloc(nr_pages, event->attr.watermark ? event->attr.wakeup_watermark : 0, From 3821f258686691cf12bbfc636ab22fa2b049dc86 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 12 Aug 2025 12:39:03 +0200 Subject: [PATCH 00942/11391] perf: Merge consecutive conditionals in perf_mmap() if (cond) { A; } else { B; } if (cond) { C; } else { D; } into: if (cond) { A; C; } else { B; D; } Notably the conditions are not identical in form, but are equivalent. Suggested-by: Thomas Gleixner Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Lorenzo Stoakes Link: https://lore.kernel.org/r/20250812104018.900078502@infradead.org --- kernel/events/core.c | 41 +++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 9f19c612c80f..085f36f61137 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -7064,6 +7064,25 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) if (vma->vm_flags & VM_WRITE) flags |= RING_BUFFER_WRITABLE; + rb = rb_alloc(nr_pages, + event->attr.watermark ? event->attr.wakeup_watermark : 0, + event->cpu, flags); + + if (!rb) { + ret = -ENOMEM; + goto unlock; + } + + atomic_set(&rb->mmap_count, 1); + rb->mmap_user = get_current_user(); + rb->mmap_locked = extra; + + ring_buffer_attach(event, rb); + + perf_event_update_time(event); + perf_event_init_userpage(event); + perf_event_update_userpage(event); + ret = 0; } else { /* * AUX area mapping: if rb->aux_nr_pages != 0, it's already @@ -7120,29 +7139,7 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) if (vma->vm_flags & VM_WRITE) flags |= RING_BUFFER_WRITABLE; - } - if (!rb) { - rb = rb_alloc(nr_pages, - event->attr.watermark ? event->attr.wakeup_watermark : 0, - event->cpu, flags); - - if (!rb) { - ret = -ENOMEM; - goto unlock; - } - - atomic_set(&rb->mmap_count, 1); - rb->mmap_user = get_current_user(); - rb->mmap_locked = extra; - - ring_buffer_attach(event, rb); - - perf_event_update_time(event); - perf_event_init_userpage(event); - perf_event_update_userpage(event); - ret = 0; - } else { ret = rb_alloc_aux(rb, event, vma->vm_pgoff, nr_pages, event->attr.aux_watermark, flags); if (!ret) { From 4118994b33bb628dd9aeb941c5af6f950f1dea90 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 12 Aug 2025 12:39:04 +0200 Subject: [PATCH 00943/11391] perf: Move common code into both rb and aux branches if (cond) { A; } else { B; } C; into if (cond) { A; C; } else { B; C; } Notably C has a success branch and both A and B have two places for success. For A (rb case), duplicate the success case because later patches will result in them no longer being identical. For B (aux case), share using goto (cleaned up later). Suggested-by: Thomas Gleixner Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Lorenzo Stoakes Link: https://lore.kernel.org/r/20250812104019.016252852@infradead.org --- kernel/events/core.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 085f36f61137..dfe09b033273 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -7043,6 +7043,8 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) ret = 0; /* We need the rb to map pages. */ rb = event->rb; + perf_mmap_account(vma, user_extra, extra); + atomic_inc(&event->mmap_count); goto unlock; } @@ -7083,6 +7085,9 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) perf_event_init_userpage(event); perf_event_update_userpage(event); ret = 0; + + perf_mmap_account(vma, user_extra, extra); + atomic_inc(&event->mmap_count); } else { /* * AUX area mapping: if rb->aux_nr_pages != 0, it's already @@ -7127,11 +7132,12 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) if (rb_has_aux(rb)) { atomic_inc(&rb->aux_mmap_count); ret = 0; - goto unlock; + goto aux_success; } if (!perf_mmap_calc_limits(vma, &user_extra, &extra)) { ret = -EPERM; + atomic_dec(&rb->mmap_count); goto unlock; } @@ -7142,20 +7148,19 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) ret = rb_alloc_aux(rb, event, vma->vm_pgoff, nr_pages, event->attr.aux_watermark, flags); - if (!ret) { - atomic_set(&rb->aux_mmap_count, 1); - rb->aux_mmap_locked = extra; + if (ret) { + atomic_dec(&rb->mmap_count); + goto unlock; } + + atomic_set(&rb->aux_mmap_count, 1); + rb->aux_mmap_locked = extra; +aux_success: + perf_mmap_account(vma, user_extra, extra); + atomic_inc(&event->mmap_count); } unlock: - if (!ret) { - perf_mmap_account(vma, user_extra, extra); - atomic_inc(&event->mmap_count); - } else if (rb) { - /* AUX allocation failed */ - atomic_dec(&rb->mmap_count); - } aux_unlock: if (aux_mutex) mutex_unlock(aux_mutex); From 41b80e1d74bdef5e48ea63d186244b9f6f82a4da Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 12 Aug 2025 12:39:05 +0200 Subject: [PATCH 00944/11391] perf: Remove redundant aux_unlock label unlock and aux_unlock are now identical, remove the aux_unlock one. Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Lorenzo Stoakes Link: https://lore.kernel.org/r/20250812104019.131293512@infradead.org --- kernel/events/core.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index dfe09b033273..89fb069913d0 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -7098,7 +7098,7 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) rb = event->rb; if (!rb) - goto aux_unlock; + goto unlock; aux_mutex = &rb->aux_mutex; mutex_lock(aux_mutex); @@ -7107,27 +7107,27 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) aux_size = READ_ONCE(rb->user_page->aux_size); if (aux_offset < perf_data_size(rb) + PAGE_SIZE) - goto aux_unlock; + goto unlock; if (aux_offset != vma->vm_pgoff << PAGE_SHIFT) - goto aux_unlock; + goto unlock; /* already mapped with a different offset */ if (rb_has_aux(rb) && rb->aux_pgoff != vma->vm_pgoff) - goto aux_unlock; + goto unlock; if (aux_size != nr_pages * PAGE_SIZE) - goto aux_unlock; + goto unlock; /* already mapped with a different size */ if (rb_has_aux(rb) && rb->aux_nr_pages != nr_pages) - goto aux_unlock; + goto unlock; if (!is_power_of_2(nr_pages)) - goto aux_unlock; + goto unlock; if (!atomic_inc_not_zero(&rb->mmap_count)) - goto aux_unlock; + goto unlock; if (rb_has_aux(rb)) { atomic_inc(&rb->aux_mmap_count); @@ -7161,7 +7161,6 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) } unlock: -aux_unlock: if (aux_mutex) mutex_unlock(aux_mutex); mutex_unlock(&event->mmap_mutex); From b33a51564e3eb6c468979f9f08d9b4ad8451bed7 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 12 Aug 2025 12:39:06 +0200 Subject: [PATCH 00945/11391] perf: Use guard() for aux_mutex in perf_mmap() After duplicating the common code into the rb/aux branches is it possible to use a simple guard() for the aux_mutex. Making the aux branch self-contained. Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Lorenzo Stoakes Link: https://lore.kernel.org/r/20250812104019.246250452@infradead.org --- kernel/events/core.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 89fb069913d0..236c60adde88 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -6975,7 +6975,6 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) struct perf_event *event = file->private_data; unsigned long vma_size, nr_pages; long user_extra = 0, extra = 0; - struct mutex *aux_mutex = NULL; struct perf_buffer *rb = NULL; int ret, flags = 0; mapped_f mapped; @@ -7100,8 +7099,7 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) if (!rb) goto unlock; - aux_mutex = &rb->aux_mutex; - mutex_lock(aux_mutex); + guard(mutex)(&rb->aux_mutex); aux_offset = READ_ONCE(rb->user_page->aux_offset); aux_size = READ_ONCE(rb->user_page->aux_size); @@ -7161,8 +7159,6 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) } unlock: - if (aux_mutex) - mutex_unlock(aux_mutex); mutex_unlock(&event->mmap_mutex); if (ret) From 8558dca9fbdf825edf30b5fb74fbbbf3e6ba5dce Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 12 Aug 2025 12:39:07 +0200 Subject: [PATCH 00946/11391] perf: Reflow to get rid of aux_success label Mostly re-indent noise needed to get rid of that label. Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Lorenzo Stoakes Link: https://lore.kernel.org/r/20250812104019.362581570@infradead.org --- kernel/events/core.c | 45 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 236c60adde88..5bbea8127bb6 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -7130,30 +7130,29 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) if (rb_has_aux(rb)) { atomic_inc(&rb->aux_mmap_count); ret = 0; - goto aux_success; + + } else { + if (!perf_mmap_calc_limits(vma, &user_extra, &extra)) { + ret = -EPERM; + atomic_dec(&rb->mmap_count); + goto unlock; + } + + WARN_ON(!rb && event->rb); + + if (vma->vm_flags & VM_WRITE) + flags |= RING_BUFFER_WRITABLE; + + ret = rb_alloc_aux(rb, event, vma->vm_pgoff, nr_pages, + event->attr.aux_watermark, flags); + if (ret) { + atomic_dec(&rb->mmap_count); + goto unlock; + } + + atomic_set(&rb->aux_mmap_count, 1); + rb->aux_mmap_locked = extra; } - - if (!perf_mmap_calc_limits(vma, &user_extra, &extra)) { - ret = -EPERM; - atomic_dec(&rb->mmap_count); - goto unlock; - } - - WARN_ON(!rb && event->rb); - - if (vma->vm_flags & VM_WRITE) - flags |= RING_BUFFER_WRITABLE; - - ret = rb_alloc_aux(rb, event, vma->vm_pgoff, nr_pages, - event->attr.aux_watermark, flags); - if (ret) { - atomic_dec(&rb->mmap_count); - goto unlock; - } - - atomic_set(&rb->aux_mmap_count, 1); - rb->aux_mmap_locked = extra; -aux_success: perf_mmap_account(vma, user_extra, extra); atomic_inc(&event->mmap_count); } From 2aee37682391332d26c01e703170e0d9358c7252 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 12 Aug 2025 12:39:08 +0200 Subject: [PATCH 00947/11391] perf: Split out the AUX buffer allocation Move the AUX buffer allocation branch into its own function. Originally-by: Thomas Gleixner Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Lorenzo Stoakes Link: https://lore.kernel.org/r/20250812104019.494205648@infradead.org --- kernel/events/core.c | 144 +++++++++++++++++++++++-------------------- 1 file changed, 77 insertions(+), 67 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 5bbea8127bb6..e76afd9c1759 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -6970,6 +6970,82 @@ static void perf_mmap_account(struct vm_area_struct *vma, long user_extra, long atomic64_add(extra, &vma->vm_mm->pinned_vm); } +static int perf_mmap_aux(struct vm_area_struct *vma, struct perf_event *event, + unsigned long nr_pages) +{ + long extra = 0, user_extra = nr_pages; + u64 aux_offset, aux_size; + struct perf_buffer *rb; + int ret, rb_flags = 0; + + rb = event->rb; + if (!rb) + return -EINVAL; + + guard(mutex)(&rb->aux_mutex); + + /* + * AUX area mapping: if rb->aux_nr_pages != 0, it's already + * mapped, all subsequent mappings should have the same size + * and offset. Must be above the normal perf buffer. + */ + aux_offset = READ_ONCE(rb->user_page->aux_offset); + aux_size = READ_ONCE(rb->user_page->aux_size); + + if (aux_offset < perf_data_size(rb) + PAGE_SIZE) + return -EINVAL; + + if (aux_offset != vma->vm_pgoff << PAGE_SHIFT) + return -EINVAL; + + /* already mapped with a different offset */ + if (rb_has_aux(rb) && rb->aux_pgoff != vma->vm_pgoff) + return -EINVAL; + + if (aux_size != nr_pages * PAGE_SIZE) + return -EINVAL; + + /* already mapped with a different size */ + if (rb_has_aux(rb) && rb->aux_nr_pages != nr_pages) + return -EINVAL; + + if (!is_power_of_2(nr_pages)) + return -EINVAL; + + if (!atomic_inc_not_zero(&rb->mmap_count)) + return -EINVAL; + + if (rb_has_aux(rb)) { + atomic_inc(&rb->aux_mmap_count); + + } else { + if (!perf_mmap_calc_limits(vma, &user_extra, &extra)) { + atomic_dec(&rb->mmap_count); + return -EPERM; + } + + WARN_ON(!rb && event->rb); + + if (vma->vm_flags & VM_WRITE) + rb_flags |= RING_BUFFER_WRITABLE; + + ret = rb_alloc_aux(rb, event, vma->vm_pgoff, nr_pages, + event->attr.aux_watermark, rb_flags); + if (ret) { + atomic_dec(&rb->mmap_count); + return ret; + } + + atomic_set(&rb->aux_mmap_count, 1); + rb->aux_mmap_locked = extra; + } + + perf_mmap_account(vma, user_extra, extra); + atomic_inc(&event->mmap_count); + + return 0; +} + static int perf_mmap(struct file *file, struct vm_area_struct *vma) { struct perf_event *event = file->private_data; @@ -7088,73 +7164,7 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) perf_mmap_account(vma, user_extra, extra); atomic_inc(&event->mmap_count); } else { - /* - * AUX area mapping: if rb->aux_nr_pages != 0, it's already - * mapped, all subsequent mappings should have the same size - * and offset. Must be above the normal perf buffer. - */ - u64 aux_offset, aux_size; - - rb = event->rb; - if (!rb) - goto unlock; - - guard(mutex)(&rb->aux_mutex); - - aux_offset = READ_ONCE(rb->user_page->aux_offset); - aux_size = READ_ONCE(rb->user_page->aux_size); - - if (aux_offset < perf_data_size(rb) + PAGE_SIZE) - goto unlock; - - if (aux_offset != vma->vm_pgoff << PAGE_SHIFT) - goto unlock; - - /* already mapped with a different offset */ - if (rb_has_aux(rb) && rb->aux_pgoff != vma->vm_pgoff) - goto unlock; - - if (aux_size != nr_pages * PAGE_SIZE) - goto unlock; - - /* already mapped with a different size */ - if (rb_has_aux(rb) && rb->aux_nr_pages != nr_pages) - goto unlock; - - if (!is_power_of_2(nr_pages)) - goto unlock; - - if (!atomic_inc_not_zero(&rb->mmap_count)) - goto unlock; - - if (rb_has_aux(rb)) { - atomic_inc(&rb->aux_mmap_count); - ret = 0; - - } else { - if (!perf_mmap_calc_limits(vma, &user_extra, &extra)) { - ret = -EPERM; - atomic_dec(&rb->mmap_count); - goto unlock; - } - - WARN_ON(!rb && event->rb); - - if (vma->vm_flags & VM_WRITE) - flags |= RING_BUFFER_WRITABLE; - - ret = rb_alloc_aux(rb, event, vma->vm_pgoff, nr_pages, - event->attr.aux_watermark, flags); - if (ret) { - atomic_dec(&rb->mmap_count); - goto unlock; - } - - atomic_set(&rb->aux_mmap_count, 1); - rb->aux_mmap_locked = extra; - } - perf_mmap_account(vma, user_extra, extra); - atomic_inc(&event->mmap_count); + ret = perf_mmap_aux(vma, event, nr_pages); } unlock: From 191759e5ea9f6995171ed2ffcc41a2377f946a3a Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 12 Aug 2025 12:39:09 +0200 Subject: [PATCH 00948/11391] perf: Make RB allocation branch self sufficient Ensure @rb usage doesn't extend out of the branch block. Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Lorenzo Stoakes Link: https://lore.kernel.org/r/20250812104019.605285302@infradead.org --- kernel/events/core.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index e76afd9c1759..875c27b28e9b 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -7116,8 +7116,6 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) * multiple times. */ ret = 0; - /* We need the rb to map pages. */ - rb = event->rb; perf_mmap_account(vma, user_extra, extra); atomic_inc(&event->mmap_count); goto unlock; @@ -7136,8 +7134,6 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) goto unlock; } - WARN_ON(!rb && event->rb); - if (vma->vm_flags & VM_WRITE) flags |= RING_BUFFER_WRITABLE; @@ -7190,7 +7186,7 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) * full cleanup in this case and therefore does not invoke * vmops::close(). */ - ret = map_range(rb, vma); + ret = map_range(event->rb, vma); if (ret) perf_mmap_close(vma); From 5d299897f1e36025400ca84fd36c15925a383b03 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 12 Aug 2025 12:39:10 +0200 Subject: [PATCH 00949/11391] perf: Split out the RB allocation Move the RB buffer allocation branch into its own function. Originally-by: Thomas Gleixner Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Lorenzo Stoakes Link: https://lore.kernel.org/r/20250812104019.722214699@infradead.org --- kernel/events/core.c | 145 ++++++++++++++++++++++--------------------- 1 file changed, 73 insertions(+), 72 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 875c27b28e9b..3a5fd2b802e4 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -6970,6 +6970,75 @@ static void perf_mmap_account(struct vm_area_struct *vma, long user_extra, long atomic64_add(extra, &vma->vm_mm->pinned_vm); } +static int perf_mmap_rb(struct vm_area_struct *vma, struct perf_event *event, + unsigned long nr_pages) +{ + long extra = 0, user_extra = nr_pages; + struct perf_buffer *rb; + int rb_flags = 0; + + nr_pages -= 1; + + /* + * If we have rb pages ensure they're a power-of-two number, so we + * can do bitmasks instead of modulo. + */ + if (nr_pages != 0 && !is_power_of_2(nr_pages)) + return -EINVAL; + + WARN_ON_ONCE(event->ctx->parent_ctx); + + if (event->rb) { + if (data_page_nr(event->rb) != nr_pages) + return -EINVAL; + + if (atomic_inc_not_zero(&event->rb->mmap_count)) { + /* + * Success -- managed to mmap() the same buffer + * multiple times. + */ + perf_mmap_account(vma, user_extra, extra); + atomic_inc(&event->mmap_count); + return 0; + } + + /* + * Raced against perf_mmap_close()'s + * atomic_dec_and_mutex_lock() remove the + * event and continue as if !event->rb + */ + ring_buffer_attach(event, NULL); + } + + if (!perf_mmap_calc_limits(vma, &user_extra, &extra)) + return -EPERM; + + if (vma->vm_flags & VM_WRITE) + rb_flags |= RING_BUFFER_WRITABLE; + + rb = rb_alloc(nr_pages, + event->attr.watermark ? event->attr.wakeup_watermark : 0, + event->cpu, rb_flags); + + if (!rb) + return -ENOMEM; + + atomic_set(&rb->mmap_count, 1); + rb->mmap_user = get_current_user(); + rb->mmap_locked = extra; + + ring_buffer_attach(event, rb); + + perf_event_update_time(event); + perf_event_init_userpage(event); + perf_event_update_userpage(event); + + perf_mmap_account(vma, user_extra, extra); + atomic_inc(&event->mmap_count); + + return 0; +} + static int perf_mmap_aux(struct vm_area_struct *vma, struct perf_event *event, unsigned long nr_pages) { @@ -7050,10 +7119,8 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) { struct perf_event *event = file->private_data; unsigned long vma_size, nr_pages; - long user_extra = 0, extra = 0; - struct perf_buffer *rb = NULL; - int ret, flags = 0; mapped_f mapped; + int ret; /* * Don't allow mmap() of inherited per-task counters. This would @@ -7079,8 +7146,6 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) if (vma_size != PAGE_SIZE * nr_pages) return -EINVAL; - user_extra = nr_pages; - mutex_lock(&event->mmap_mutex); ret = -EINVAL; @@ -7094,74 +7159,10 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) goto unlock; } - if (vma->vm_pgoff == 0) { - nr_pages -= 1; - - /* - * If we have rb pages ensure they're a power-of-two number, so we - * can do bitmasks instead of modulo. - */ - if (nr_pages != 0 && !is_power_of_2(nr_pages)) - goto unlock; - - WARN_ON_ONCE(event->ctx->parent_ctx); - - if (event->rb) { - if (data_page_nr(event->rb) != nr_pages) - goto unlock; - - if (atomic_inc_not_zero(&event->rb->mmap_count)) { - /* - * Success -- managed to mmap() the same buffer - * multiple times. - */ - ret = 0; - perf_mmap_account(vma, user_extra, extra); - atomic_inc(&event->mmap_count); - goto unlock; - } - - /* - * Raced against perf_mmap_close()'s - * atomic_dec_and_mutex_lock() remove the - * event and continue as if !event->rb - */ - ring_buffer_attach(event, NULL); - } - - if (!perf_mmap_calc_limits(vma, &user_extra, &extra)) { - ret = -EPERM; - goto unlock; - } - - if (vma->vm_flags & VM_WRITE) - flags |= RING_BUFFER_WRITABLE; - - rb = rb_alloc(nr_pages, - event->attr.watermark ? event->attr.wakeup_watermark : 0, - event->cpu, flags); - - if (!rb) { - ret = -ENOMEM; - goto unlock; - } - - atomic_set(&rb->mmap_count, 1); - rb->mmap_user = get_current_user(); - rb->mmap_locked = extra; - - ring_buffer_attach(event, rb); - - perf_event_update_time(event); - perf_event_init_userpage(event); - perf_event_update_userpage(event); - ret = 0; - - perf_mmap_account(vma, user_extra, extra); - atomic_inc(&event->mmap_count); - } else { + if (vma->vm_pgoff == 0) + ret = perf_mmap_rb(vma, event, nr_pages); + else ret = perf_mmap_aux(vma, event, nr_pages); - } unlock: mutex_unlock(&event->mmap_mutex); From d23a6dbc0a71741eb7b141fdc04e31360fba46ef Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 12 Aug 2025 12:39:11 +0200 Subject: [PATCH 00950/11391] perf: Use scoped_guard() for mmap_mutex in perf_mmap() Mostly just re-indent noise. Suggested-by: Thomas Gleixner Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Lorenzo Stoakes Link: https://lore.kernel.org/r/20250812104019.838047976@infradead.org --- kernel/events/core.c | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 3a5fd2b802e4..41941dfadfcb 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -7146,30 +7146,23 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) if (vma_size != PAGE_SIZE * nr_pages) return -EINVAL; - mutex_lock(&event->mmap_mutex); - ret = -EINVAL; + scoped_guard (mutex, &event->mmap_mutex) { + /* + * This relies on __pmu_detach_event() taking mmap_mutex after marking + * the event REVOKED. Either we observe the state, or __pmu_detach_event() + * will detach the rb created here. + */ + if (event->state <= PERF_EVENT_STATE_REVOKED) + return -ENODEV; - /* - * This relies on __pmu_detach_event() taking mmap_mutex after marking - * the event REVOKED. Either we observe the state, or __pmu_detach_event() - * will detach the rb created here. - */ - if (event->state <= PERF_EVENT_STATE_REVOKED) { - ret = -ENODEV; - goto unlock; + if (vma->vm_pgoff == 0) + ret = perf_mmap_rb(vma, event, nr_pages); + else + ret = perf_mmap_aux(vma, event, nr_pages); + if (ret) + return ret; } - if (vma->vm_pgoff == 0) - ret = perf_mmap_rb(vma, event, nr_pages); - else - ret = perf_mmap_aux(vma, event, nr_pages); - -unlock: - mutex_unlock(&event->mmap_mutex); - - if (ret) - return ret; - /* * Since pinned accounting is per vm we cannot allow fork() to copy our * vma. From 59741451b49ce9964a9758c19d6f7df2a1255c75 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 12 Aug 2025 12:39:12 +0200 Subject: [PATCH 00951/11391] perf: Identify the 0->1 transition for event::mmap_count Needed because refcount_inc() doesn't allow the 0->1 transition. Specifically, this is the case where we've created the RB, this means there was no RB, and as such there could not have been an mmap. Additionally we hold mmap_mutex to serialize everything. This must be the first. Suggested-by: Thomas Gleixner Signed-off-by: Peter Zijlstra (Intel) Link: https://lore.kernel.org/r/20250812104019.956479989@infradead.org --- kernel/events/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 41941dfadfcb..f6211ab18503 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -7034,7 +7034,7 @@ static int perf_mmap_rb(struct vm_area_struct *vma, struct perf_event *event, perf_event_update_userpage(event); perf_mmap_account(vma, user_extra, extra); - atomic_inc(&event->mmap_count); + atomic_set(&event->mmap_count, 1); return 0; } From 448f97fba9013ffa13f5dd82febd18836b189499 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 12 Aug 2025 12:39:13 +0200 Subject: [PATCH 00952/11391] perf: Convert mmap() refcounts to refcount_t The recently fixed reference count leaks could have been detected by using refcount_t and refcount_t would have mitigated the potential overflow at least. Now that the code is properly structured, convert the mmap() related mmap_count variants over to refcount_t. No functional change intended. Signed-off-by: Thomas Gleixner Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Lorenzo Stoakes Link: https://lore.kernel.org/r/20250812104020.071507932@infradead.org --- include/linux/perf_event.h | 2 +- kernel/events/core.c | 40 ++++++++++++++++++------------------- kernel/events/internal.h | 4 ++-- kernel/events/ring_buffer.c | 2 +- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index ec9d96025683..bfbf9ea53f25 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -859,7 +859,7 @@ struct perf_event { /* mmap bits */ struct mutex mmap_mutex; - atomic_t mmap_count; + refcount_t mmap_count; struct perf_buffer *rb; struct list_head rb_entry; diff --git a/kernel/events/core.c b/kernel/events/core.c index f6211ab18503..ea357044d780 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -3968,7 +3968,7 @@ static noinline int visit_groups_merge(struct perf_event_context *ctx, */ static inline bool event_update_userpage(struct perf_event *event) { - if (likely(!atomic_read(&event->mmap_count))) + if (likely(!refcount_read(&event->mmap_count))) return false; perf_event_update_time(event); @@ -6704,11 +6704,11 @@ static void perf_mmap_open(struct vm_area_struct *vma) struct perf_event *event = vma->vm_file->private_data; mapped_f mapped = get_mapped(event, event_mapped); - atomic_inc(&event->mmap_count); - atomic_inc(&event->rb->mmap_count); + refcount_inc(&event->mmap_count); + refcount_inc(&event->rb->mmap_count); if (vma->vm_pgoff) - atomic_inc(&event->rb->aux_mmap_count); + refcount_inc(&event->rb->aux_mmap_count); if (mapped) mapped(event, vma->vm_mm); @@ -6743,7 +6743,7 @@ static void perf_mmap_close(struct vm_area_struct *vma) * to avoid complications. */ if (rb_has_aux(rb) && vma->vm_pgoff == rb->aux_pgoff && - atomic_dec_and_mutex_lock(&rb->aux_mmap_count, &rb->aux_mutex)) { + refcount_dec_and_mutex_lock(&rb->aux_mmap_count, &rb->aux_mutex)) { /* * Stop all AUX events that are writing to this buffer, * so that we can free its AUX pages and corresponding PMU @@ -6763,10 +6763,10 @@ static void perf_mmap_close(struct vm_area_struct *vma) mutex_unlock(&rb->aux_mutex); } - if (atomic_dec_and_test(&rb->mmap_count)) + if (refcount_dec_and_test(&rb->mmap_count)) detach_rest = true; - if (!atomic_dec_and_mutex_lock(&event->mmap_count, &event->mmap_mutex)) + if (!refcount_dec_and_mutex_lock(&event->mmap_count, &event->mmap_mutex)) goto out_put; ring_buffer_attach(event, NULL); @@ -6992,19 +6992,19 @@ static int perf_mmap_rb(struct vm_area_struct *vma, struct perf_event *event, if (data_page_nr(event->rb) != nr_pages) return -EINVAL; - if (atomic_inc_not_zero(&event->rb->mmap_count)) { + if (refcount_inc_not_zero(&event->rb->mmap_count)) { /* * Success -- managed to mmap() the same buffer * multiple times. */ perf_mmap_account(vma, user_extra, extra); - atomic_inc(&event->mmap_count); + refcount_inc(&event->mmap_count); return 0; } /* * Raced against perf_mmap_close()'s - * atomic_dec_and_mutex_lock() remove the + * refcount_dec_and_mutex_lock() remove the * event and continue as if !event->rb */ ring_buffer_attach(event, NULL); @@ -7023,7 +7023,7 @@ static int perf_mmap_rb(struct vm_area_struct *vma, struct perf_event *event, if (!rb) return -ENOMEM; - atomic_set(&rb->mmap_count, 1); + refcount_set(&rb->mmap_count, 1); rb->mmap_user = get_current_user(); rb->mmap_locked = extra; @@ -7034,7 +7034,7 @@ static int perf_mmap_rb(struct vm_area_struct *vma, struct perf_event *event, perf_event_update_userpage(event); perf_mmap_account(vma, user_extra, extra); - atomic_set(&event->mmap_count, 1); + refcount_set(&event->mmap_count, 1); return 0; } @@ -7081,15 +7081,15 @@ static int perf_mmap_aux(struct vm_area_struct *vma, struct perf_event *event, if (!is_power_of_2(nr_pages)) return -EINVAL; - if (!atomic_inc_not_zero(&rb->mmap_count)) + if (!refcount_inc_not_zero(&rb->mmap_count)) return -EINVAL; if (rb_has_aux(rb)) { - atomic_inc(&rb->aux_mmap_count); + refcount_inc(&rb->aux_mmap_count); } else { if (!perf_mmap_calc_limits(vma, &user_extra, &extra)) { - atomic_dec(&rb->mmap_count); + refcount_dec(&rb->mmap_count); return -EPERM; } @@ -7101,16 +7101,16 @@ static int perf_mmap_aux(struct vm_area_struct *vma, struct perf_event *event, ret = rb_alloc_aux(rb, event, vma->vm_pgoff, nr_pages, event->attr.aux_watermark, rb_flags); if (ret) { - atomic_dec(&rb->mmap_count); + refcount_dec(&rb->mmap_count); return ret; } - atomic_set(&rb->aux_mmap_count, 1); + refcount_set(&rb->aux_mmap_count, 1); rb->aux_mmap_locked = extra; } perf_mmap_account(vma, user_extra, extra); - atomic_inc(&event->mmap_count); + refcount_inc(&event->mmap_count); return 0; } @@ -13254,7 +13254,7 @@ perf_event_set_output(struct perf_event *event, struct perf_event *output_event) mutex_lock_double(&event->mmap_mutex, &output_event->mmap_mutex); set: /* Can't redirect output if we've got an active mmap() */ - if (atomic_read(&event->mmap_count)) + if (refcount_read(&event->mmap_count)) goto unlock; if (output_event) { @@ -13267,7 +13267,7 @@ perf_event_set_output(struct perf_event *event, struct perf_event *output_event) goto unlock; /* did we race against perf_mmap_close() */ - if (!atomic_read(&rb->mmap_count)) { + if (!refcount_read(&rb->mmap_count)) { ring_buffer_put(rb); goto unlock; } diff --git a/kernel/events/internal.h b/kernel/events/internal.h index 249288d82b8d..d9cc57083091 100644 --- a/kernel/events/internal.h +++ b/kernel/events/internal.h @@ -35,7 +35,7 @@ struct perf_buffer { spinlock_t event_lock; struct list_head event_list; - atomic_t mmap_count; + refcount_t mmap_count; unsigned long mmap_locked; struct user_struct *mmap_user; @@ -47,7 +47,7 @@ struct perf_buffer { unsigned long aux_pgoff; int aux_nr_pages; int aux_overwrite; - atomic_t aux_mmap_count; + refcount_t aux_mmap_count; unsigned long aux_mmap_locked; void (*free_aux)(void *); refcount_t aux_refcount; diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c index aa9a759e824f..20a905023736 100644 --- a/kernel/events/ring_buffer.c +++ b/kernel/events/ring_buffer.c @@ -400,7 +400,7 @@ void *perf_aux_output_begin(struct perf_output_handle *handle, * the same order, see perf_mmap_close. Otherwise we end up freeing * aux pages in this path, which is a bug, because in_atomic(). */ - if (!atomic_read(&rb->aux_mmap_count)) + if (!refcount_read(&rb->aux_mmap_count)) goto err; if (!refcount_inc_not_zero(&rb->aux_refcount)) From 2eb676f1410dd7c3aa91534cbf86dfb1dee3bc7c Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 15 Aug 2025 08:51:32 -0500 Subject: [PATCH 00953/11391] Revert "arm64: dts: qcom: sm8450: add initial device tree for Samsung Galaxy S22" This reverts commit 46952305d2b6 ("arm64: dts: qcom: sm8450: add initial device tree for Samsung Galaxy S22"), as the merged version had been superseded and received further feedback. Signed-off-by: Bjorn Andersson --- .../boot/dts/qcom/sm8450-samsung-r0q.dts | 364 ------------------ 1 file changed, 364 deletions(-) delete mode 100644 arch/arm64/boot/dts/qcom/sm8450-samsung-r0q.dts diff --git a/arch/arm64/boot/dts/qcom/sm8450-samsung-r0q.dts b/arch/arm64/boot/dts/qcom/sm8450-samsung-r0q.dts deleted file mode 100644 index e9e21c25444a..000000000000 --- a/arch/arm64/boot/dts/qcom/sm8450-samsung-r0q.dts +++ /dev/null @@ -1,364 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2025, Eric Gonçalves - */ - -/dts-v1/; - -#include -#include -#include - -#include "sm8450.dtsi" -#include "pm8350.dtsi" -#include "pm8350b.dtsi" -#include "pm8350c.dtsi" -#include "pm8450.dtsi" -#include "pmk8350.dtsi" -#include "pmr735a.dtsi" - -/delete-node/ &xbl_ramdump_mem; -/delete-node/ &xbl_sc_mem; -/delete-node/ &adsp_mem; -/delete-node/ &rmtfs_mem; -/delete-node/ &mte_mem; -/delete-node/ &trusted_apps_mem; -/delete-node/ &trusted_apps_ext_mem; - -/ { - chassis-type = "handset"; - model = "Samsung Galaxy S22 (SM-S901E)"; - compatible = "samsung,r0q", "qcom,sm8450"; - - chosen { - #address-cells = <2>; - #size-cells = <2>; - ranges; - - bootargs = "clk_ignore_unused pd_ignore_unused"; - linux,initrd-start = <0x00 0xb6915000>; - linux,initrd-end = <0x00 0xb7fff22c>; - stdout-path = "serial0:115200n8"; - - framebuffer: framebuffer@b8000000 { - compatible = "simple-framebuffer"; - reg = <0x0 0xb8000000 0x0 0x2b00000>; - width = <1080>; - height = <2340>; - stride = <(1080 * 4)>; - format = "a8r8g8b8"; - }; - }; - - gpio-keys { - compatible = "gpio-keys"; - autorepeat; - - pinctrl-0 = <&vol_up_n>; - pinctrl-names = "default"; - - key-vol-up { - label = "Volume Up"; - linux,code = ; - gpios = <&pm8350_gpios 6 GPIO_ACTIVE_LOW>; - debounce-interval = <15>; - }; - }; - - memory { - ddr_device_type = <0x08>; - device_type = "memory"; - reg = <0x00 0x80000000 0x00 0x6a000000 0x00 0xf1c00000 0x00 0xe400000 0x08 0x00 0x00 0x3ab00000 0x08 0x40000000 0x01 0x40000000 0x08 0x3b100000 0x00 0x1e00000>; - }; - - reserved-memory { - xbl_ramdump_mem: memory@a6b80000 { - reg = <0x0 0xa7d00000 0x0 0x300000>; - no-map; - }; - - xbl_sc_mem: memory@a6e00000 { - reg = <0x0 0xa6e00000 0x0 0x40000>; - no-map; - }; - - adsp_mem: memory@9fd00000 { - reg = <0x0 0x84500000 0x0 0x3b00000>; - no-map; - }; - - rmtfs_mem: memory@fe200000 { - compatible = "qcom,rmtfs-mem"; - reg = <0x0 0xfe200000 0x0 0x280000>; - reg-names = "rmtfs"; - qcom,client-id = <1>; - no-map; - - qcom,vmid = ; - }; - - splash_region@b8000000 { - reg = <0x0 0xb8000000 0x0 0x2b00000>; - no-map; - }; - }; - - vph_pwr: vph-pwr-regulator { - compatible = "regulator-fixed"; - regulator-name = "vph_pwr"; - regulator-min-microvolt = <3700000>; - regulator-max-microvolt = <3700000>; - - regulator-always-on; - regulator-boot-on; - }; -}; - -&tlmm { - gpio-reserved-ranges = <36 4>, <50 1>, <93 1>; - - dsi_default: dsi-default-state { - pins = "gpio6"; - function = "gpio"; - drive-strength = <8>; - bias-disable; - }; - - dsi_suspend: dsi-suspend-state { - pins = "gpio6"; - function = "gpio"; - drive-strength = <2>; - bias-pull-down; - }; -}; - -&apps_rsc { - regulators-0 { - compatible = "qcom,pm8350-rpmh-regulators"; - qcom,pmic-id = "b"; - - vdd-s1-supply = <&vph_pwr>; - vdd-s2-supply = <&vph_pwr>; - vdd-s3-supply = <&vph_pwr>; - vdd-s4-supply = <&vph_pwr>; - vdd-s5-supply = <&vph_pwr>; - vdd-s6-supply = <&vph_pwr>; - vdd-s7-supply = <&vph_pwr>; - vdd-s8-supply = <&vph_pwr>; - vdd-s9-supply = <&vph_pwr>; - vdd-s10-supply = <&vph_pwr>; - vdd-s11-supply = <&vph_pwr>; - vdd-s12-supply = <&vph_pwr>; - - vdd-l1-l4-supply = <&vreg_s11b_0p95>; - vdd-l2-l7-supply = <&vreg_bob>; - vdd-l3-l5-supply = <&vreg_bob>; - vdd-l6-l9-l10-supply = <&vreg_s12b_1p25>; - vdd-l8-supply = <&vreg_s2h_0p95>; - - vreg_s11b_0p95: smps11 { - regulator-name = "vreg_s11b_0p95"; - regulator-min-microvolt = <848000>; - regulator-max-microvolt = <1104000>; - }; - - vreg_s12b_1p25: smps12 { - regulator-name = "vreg_s12b_1p25"; - regulator-min-microvolt = <1224000>; - regulator-max-microvolt = <1400000>; - }; - - vreg_l1b_0p91: ldo1 { - regulator-name = "vreg_l1b_0p91"; - regulator-min-microvolt = <912000>; - regulator-max-microvolt = <920000>; - regulator-initial-mode = ; - }; - - vreg_l2b_3p07: ldo2 { - regulator-name = "vreg_l2b_3p07"; - regulator-min-microvolt = <3072000>; - regulator-max-microvolt = <3072000>; - regulator-initial-mode = ; - }; - - vreg_l5b_0p88: ldo5 { - regulator-name = "vreg_l5b_0p88"; - regulator-min-microvolt = <880000>; - regulator-max-microvolt = <888000>; - regulator-initial-mode = ; - }; - - vreg_l6b_1p2: ldo6 { - regulator-name = "vreg_l6b_1p2"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; - regulator-initial-mode = ; - }; - - vreg_l7b_2p5: ldo7 { - regulator-name = "vreg_l7b_2p5"; - regulator-min-microvolt = <2504000>; - regulator-max-microvolt = <2504000>; - regulator-initial-mode = ; - }; - - vreg_l9b_1p2: ldo9 { - regulator-name = "vreg_l9b_1p2"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; - regulator-initial-mode = ; - }; - }; - - regulators-1 { - compatible = "qcom,pm8350c-rpmh-regulators"; - qcom,pmic-id = "c"; - - vdd-s1-supply = <&vph_pwr>; - vdd-s2-supply = <&vph_pwr>; - vdd-s3-supply = <&vph_pwr>; - vdd-s4-supply = <&vph_pwr>; - vdd-s5-supply = <&vph_pwr>; - vdd-s6-supply = <&vph_pwr>; - vdd-s7-supply = <&vph_pwr>; - vdd-s8-supply = <&vph_pwr>; - vdd-s9-supply = <&vph_pwr>; - vdd-s10-supply = <&vph_pwr>; - - vdd-l1-l12-supply = <&vreg_bob>; - vdd-l2-l8-supply = <&vreg_bob>; - vdd-l3-l4-l5-l7-l13-supply = <&vreg_bob>; - vdd-l6-l9-l11-supply = <&vreg_bob>; - - vdd-bob-supply = <&vph_pwr>; - - vreg_s1c_1p86: smps1 { - regulator-name = "vreg_s1c_1p86"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <2024000>; - }; - - vreg_bob: bob { - regulator-name = "vreg_bob"; - regulator-min-microvolt = <3008000>; - regulator-max-microvolt = <3960000>; - regulator-initial-mode = ; - }; - - vreg_l1c_1p8: ldo1 { - regulator-name = "vreg_l1c_1p8"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-initial-mode = ; - }; - }; - - regulators-2 { - compatible = "qcom,pm8450-rpmh-regulators"; - qcom,pmic-id = "h"; - - vdd-s1-supply = <&vph_pwr>; - vdd-s2-supply = <&vph_pwr>; - vdd-s3-supply = <&vph_pwr>; - vdd-s4-supply = <&vph_pwr>; - vdd-s5-supply = <&vph_pwr>; - vdd-s6-supply = <&vph_pwr>; - - vdd-l2-supply = <&vreg_bob>; - vdd-l3-supply = <&vreg_bob>; - vdd-l4-supply = <&vreg_bob>; - - vreg_s2h_0p95: smps2 { - regulator-name = "vreg_s2h_0p95"; - regulator-min-microvolt = <848000>; - regulator-max-microvolt = <1104000>; - }; - }; - - regulators-3 { - compatible = "qcom,pmr735a-rpmh-regulators"; - qcom,pmic-id = "e"; - - vdd-s1-supply = <&vph_pwr>; - vdd-s2-supply = <&vph_pwr>; - vdd-s3-supply = <&vph_pwr>; - - vdd-l1-l2-supply = <&vreg_s2e_0p85>; - vdd-l3-supply = <&vreg_s1e_1p25>; - vdd-l4-supply = <&vreg_s1c_1p86>; - vdd-l5-l6-supply = <&vreg_s1c_1p86>; - vdd-l7-bob-supply = <&vreg_bob>; - - vreg_s1e_1p25: smps1 { - regulator-name = "vreg_s1e_1p25"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1296000>; - }; - - vreg_s2e_0p85: smps2 { - regulator-name = "vreg_s2e_0p85"; - regulator-min-microvolt = <500000>; - regulator-max-microvolt = <1040000>; - }; - }; -}; - -&pm8350_gpios { - vol_up_n: vol-up-n-state { - pins = "gpio6"; - function = "normal"; - power-source = <1>; - input-enable; - }; -}; - -&pon_pwrkey { - status = "okay"; -}; - -&pon_resin { - status = "okay"; - linux,code = ; -}; - -&usb_1 { - qcom,select-utmi-as-pipe-clk; - status = "okay"; -}; - -&usb_1_dwc3 { - dr_mode = "peripheral"; - maximum-speed = "high-speed"; - - phys = <&usb_1_hsphy>; - phy-names = "usb2-phy"; -}; - -&usb_1_hsphy { - status = "okay"; - vdda-pll-supply = <&vreg_l5b_0p88>; - vdda18-supply = <&vreg_l1c_1p8>; - vdda33-supply = <&vreg_l2b_3p07>; -}; - -&ufs_mem_hc { - reset-gpios = <&tlmm 210 GPIO_ACTIVE_LOW>; - - vcc-supply = <&vreg_l7b_2p5>; - vcc-max-microamp = <1100000>; - vccq-supply = <&vreg_l9b_1p2>; - vccq-max-microamp = <1200000>; - vccq2-supply = <&vreg_l9b_1p2>; - vccq2-max-microamp = <1200000>; - vdd-hba-supply = <&vreg_l9b_1p2>; - - status = "okay"; -}; - -&ufs_mem_phy { - status = "okay"; - - vdda-phy-supply = <&vreg_l5b_0p88>; - vdda-pll-supply = <&vreg_l6b_1p2>; -}; 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 00954/11391] 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 00955/11391] 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 00956/11391] 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 00957/11391] 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 00958/11391] 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 00959/11391] 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 00960/11391] 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 00961/11391] 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 00962/11391] 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 00963/11391] 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 00964/11391] 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 00965/11391] 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 00966/11391] 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 00967/11391] 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 00968/11391] 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 00969/11391] 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 00970/11391] 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 15769d9478bdb3e09184c5adbab6e2d2dfcbf1b1 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Sun, 3 Aug 2025 18:22:42 +0800 Subject: [PATCH 00971/11391] fs-writeback: Remove redundant __GFP_NOWARN GFP_NOWAIT already includes __GFP_NOWARN, so let's remove the redundant __GFP_NOWARN. Signed-off-by: Qianfeng Rong Link: https://lore.kernel.org/20250803102243.623705-5-rongqianfeng@vivo.com Signed-off-by: Christian Brauner --- fs/fs-writeback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index cc57367fb641..a3ee79bfb2a4 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -1123,7 +1123,7 @@ int cgroup_writeback_by_id(u64 bdi_id, int memcg_id, dirty = dirty * 10 / 8; /* issue the writeback work */ - work = kzalloc(sizeof(*work), GFP_NOWAIT | __GFP_NOWARN); + work = kzalloc(sizeof(*work), GFP_NOWAIT); if (work) { work->nr_pages = dirty; work->sync_mode = WB_SYNC_NONE; From f8f59a2c05dc16d19432e3154a9ac7bc385f4b92 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Wed, 13 Aug 2025 17:11:05 +0200 Subject: [PATCH 00972/11391] copy_file_range: limit size if in compat mode If the process runs in 32-bit compat mode, copy_file_range results can be in the in-band error range. In this case limit copy length to MAX_RW_COUNT to prevent a signed overflow. Reported-by: Florian Weimer Closes: https://lore.kernel.org/all/lhuh5ynl8z5.fsf@oldenburg.str.redhat.com/ Signed-off-by: Miklos Szeredi Link: https://lore.kernel.org/20250813151107.99856-1-mszeredi@redhat.com Reviewed-by: Amir Goldstein Signed-off-by: Christian Brauner --- fs/read_write.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/fs/read_write.c b/fs/read_write.c index c5b6265d984b..833bae068770 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -1576,6 +1576,13 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in, if (len == 0) return 0; + /* + * Make sure return value doesn't overflow in 32bit compat mode. Also + * limit the size for all cases except when calling ->copy_file_range(). + */ + if (splice || !file_out->f_op->copy_file_range || in_compat_syscall()) + len = min_t(size_t, MAX_RW_COUNT, len); + file_start_write(file_out); /* @@ -1589,9 +1596,7 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in, len, flags); } else if (!splice && file_in->f_op->remap_file_range && samesb) { ret = file_in->f_op->remap_file_range(file_in, pos_in, - file_out, pos_out, - min_t(loff_t, MAX_RW_COUNT, len), - REMAP_FILE_CAN_SHORTEN); + file_out, pos_out, len, REMAP_FILE_CAN_SHORTEN); /* fallback to splice */ if (ret <= 0) splice = true; @@ -1624,8 +1629,7 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in, * to splicing from input file, while file_start_write() is held on * the output file on a different sb. */ - ret = do_splice_direct(file_in, &pos_in, file_out, &pos_out, - min_t(size_t, len, MAX_RW_COUNT), 0); + ret = do_splice_direct(file_in, &pos_in, file_out, &pos_out, len, 0); done: if (ret > 0) { fsnotify_access(file_in); From dee1bcf28a3dd13ddb2e9200407864f73e9c4d63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0erif=20Rami?= Date: Thu, 14 Aug 2025 19:22:16 +0200 Subject: [PATCH 00973/11391] ALSA: usb-audio: Add initial driver for TASCAM US-144MKII MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch introduces a new driver for the TASCAM US-144MKII USB audio/MIDI interface. It includes the basic driver structure for probing and disconnecting from the USB device. It correctly identifies the device using its VID/PID, performs the necessary initial handshake, and sets the required USB interface alternate settings to prepare the device for operation. At this point, no ALSA devices (PCM or MIDI) are created. This commit forms the foundational skeleton upon which audio and MIDI functionality will be built. Signed-off-by: Šerif Rami Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250814172222.9448-2-ramiserifpersia@gmail.com --- sound/usb/usx2y/us144mkii.c | 250 ++++++++++++++++++++++++++++++++++++ sound/usb/usx2y/us144mkii.h | 38 ++++++ 2 files changed, 288 insertions(+) create mode 100644 sound/usb/usx2y/us144mkii.c create mode 100644 sound/usb/usx2y/us144mkii.h diff --git a/sound/usb/usx2y/us144mkii.c b/sound/usb/usx2y/us144mkii.c new file mode 100644 index 000000000000..00d13b039589 --- /dev/null +++ b/sound/usb/usx2y/us144mkii.c @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2025 Šerif Rami +/* + * ALSA Driver for TASCAM US-144MKII Audio Interface + */ + +#include "us144mkii.h" + +MODULE_AUTHOR("Šerif Rami "); +MODULE_DESCRIPTION("ALSA Driver for TASCAM US-144MKII"); +MODULE_LICENSE("GPL"); + +/** + * @brief Module parameters for ALSA card instantiation. + * + * These parameters allow users to configure how the ALSA sound card + * for the TASCAM US-144MKII is instantiated. + * + * @param index: Array of integers specifying the ALSA card index for each + * device. Defaults to -1 (automatic). + * @param id: Array of strings specifying the ALSA card ID for each device. + * Defaults to "US144MKII". + * @param enable: Array of booleans to enable or disable each device. + * Defaults to {1, 0, ..., 0} (first device enabled). + * @param dev_idx: Internal counter for probed TASCAM devices. + */ +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; +static bool enable[SNDRV_CARDS] = { 1, [1 ...(SNDRV_CARDS - 1)] = 0 }; +static int dev_idx; + +static int tascam_probe(struct usb_interface *intf, + const struct usb_device_id *usb_id); +static void tascam_disconnect(struct usb_interface *intf); +static int tascam_suspend(struct usb_interface *intf, pm_message_t message); +static int tascam_resume(struct usb_interface *intf); + +/** + * tascam_card_private_free() - Frees private data for the sound card. + * card. + * @card: Pointer to the ALSA sound card instance. + * + * This function is called when the sound card is being freed. It releases + * the reference to the USB device. + */ +static void tascam_card_private_free(struct snd_card *card) +{ + struct tascam_card *tascam = card->private_data; + + if (tascam && tascam->dev) { + usb_put_dev(tascam->dev); + tascam->dev = NULL; + } +} + +/** + * tascam_probe() - Probes for the TASCAM US-144MKII device. + * @intf: The USB interface being probed. + * @usb_id: The USB device ID. + * + * This function is the entry point for the USB driver on device match. + * is found. It performs initial device setup, including: + * - Checking for the second interface (MIDI) and associating it. + * - Performing a vendor-specific handshake with the device. + * - Setting alternate settings for USB interfaces. + * - Creating and registering the ALSA sound card. + * + * Return: 0 on success, or a negative error code on failure. + */ +static int tascam_probe(struct usb_interface *intf, + const struct usb_device_id *usb_id) +{ + struct usb_device *dev = interface_to_usbdev(intf); + struct snd_card *card; + struct tascam_card *tascam; + int err; + char *handshake_buf __free(kfree) = NULL; + + if (dev->speed != USB_SPEED_HIGH) + dev_info( + &dev->dev, + "Device is connected to a USB 1.1 port, this is not supported.\n"); + + /* The device has two interfaces; we drive both from this driver. */ + if (intf->cur_altsetting->desc.bInterfaceNumber == 1) { + tascam = usb_get_intfdata(usb_ifnum_to_if(dev, 0)); + if (tascam) { + usb_set_intfdata(intf, tascam); + tascam->iface1 = intf; + } + return 0; /* Let the core handle this interface */ + } + + if (dev_idx >= SNDRV_CARDS) { + dev_err(&dev->dev, "Too many TASCAM devices present"); + return -ENODEV; + } + + if (!enable[dev_idx]) { + dev_info(&dev->dev, "TASCAM US-144MKII device disabled"); + return -ENOENT; + } + + handshake_buf = kmalloc(1, GFP_KERNEL); + if (!handshake_buf) + return -ENOMEM; + + /* Perform vendor-specific handshake */ + err = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + VENDOR_REQ_MODE_CONTROL, RT_D2H_VENDOR_DEV, + MODE_VAL_HANDSHAKE_READ, 0x0000, handshake_buf, 1, + USB_CTRL_TIMEOUT_MS); + if (err < 0) { + dev_err(&dev->dev, "Handshake read failed with %d\n", err); + return err; + } + + if (handshake_buf[0] != 0x12 && handshake_buf[0] != 0x16 && + handshake_buf[0] != 0x30) { + dev_err(&dev->dev, "Unexpected handshake value: 0x%x\n", + handshake_buf[0]); + return -ENODEV; + } + + /* Set alternate settings to enable audio/MIDI endpoints */ + err = usb_set_interface(dev, 0, 1); + if (err < 0) { + dev_err(&dev->dev, + "Failed to set alt setting 1 on interface 0: %d\n", + err); + return err; + } + + err = usb_set_interface(dev, 1, 1); + if (err < 0) { + dev_err(&dev->dev, + "Failed to set alt setting 1 on interface 1: %d\n", + err); + return err; + } + + err = snd_card_new(&dev->dev, index[dev_idx], id[dev_idx], THIS_MODULE, + sizeof(struct tascam_card), &card); + if (err < 0) { + dev_err(&dev->dev, "Failed to create sound card instance\n"); + return err; + } + + tascam = card->private_data; + card->private_free = tascam_card_private_free; + tascam->dev = usb_get_dev(dev); + tascam->card = card; + tascam->iface0 = intf; + tascam->digital_out_source = 1; + tascam->capture_34_source = 1; + + strscpy(card->driver, DRIVER_NAME, sizeof(card->driver)); + if (dev->descriptor.idProduct == USB_PID_TASCAM_US144) { + strscpy(card->shortname, "TASCAM US-144", + sizeof(card->shortname)); + } else if (dev->descriptor.idProduct == USB_PID_TASCAM_US144MKII) { + strscpy(card->shortname, "TASCAM US-144MKII", + sizeof(card->shortname)); + } else { + strscpy(card->shortname, "TASCAM Unknown", + sizeof(card->shortname)); + } + snprintf(card->longname, sizeof(card->longname), "%s (%04x:%04x) at %s", + card->shortname, USB_VID_TASCAM, dev->descriptor.idProduct, + dev_name(&dev->dev)); + + err = snd_card_register(card); + if (err < 0) + goto free_card; + + usb_set_intfdata(intf, tascam); + + dev_idx++; + return 0; + +free_card: + snd_card_free(card); + return err; +} + +/** + * tascam_disconnect() - Disconnects the TASCAM US-144MKII device. + * @intf: The USB interface being disconnected. + * + * This function is called when the device is disconnected from the system. + * It cleans up all allocated resources by freeing the sound card. + */ +static void tascam_disconnect(struct usb_interface *intf) +{ + struct tascam_card *tascam = usb_get_intfdata(intf); + + if (!tascam) + return; + + if (intf->cur_altsetting->desc.bInterfaceNumber == 0) { + snd_card_disconnect(tascam->card); + snd_card_free(tascam->card); + dev_idx--; + } +} + +/** + * tascam_suspend() - Handles device suspension. + * @intf: The USB interface being suspended. + * @message: Power management message. + * + * This function is a stub for handling device suspension. + * + * Return: 0 on success. + */ +static int tascam_suspend(struct usb_interface *intf, pm_message_t message) +{ + return 0; +} + +/** + * tascam_resume() - Handles device resumption from suspend. + * @intf: The USB interface being resumed. + * + * This function is a stub for handling device resumption. + * + * Return: 0 on success. + */ +static int tascam_resume(struct usb_interface *intf) +{ + return 0; +} + +static const struct usb_device_id tascam_usb_ids[] = { + { USB_DEVICE(USB_VID_TASCAM, USB_PID_TASCAM_US144) }, + { USB_DEVICE(USB_VID_TASCAM, USB_PID_TASCAM_US144MKII) }, + { /* Terminating entry */ } +}; +MODULE_DEVICE_TABLE(usb, tascam_usb_ids); + +static struct usb_driver tascam_alsa_driver = { + .name = DRIVER_NAME, + .probe = tascam_probe, + .disconnect = tascam_disconnect, + .suspend = tascam_suspend, + .resume = tascam_resume, + .id_table = tascam_usb_ids, +}; + +module_usb_driver(tascam_alsa_driver); diff --git a/sound/usb/usx2y/us144mkii.h b/sound/usb/usx2y/us144mkii.h new file mode 100644 index 000000000000..9f59863fab57 --- /dev/null +++ b/sound/usb/usx2y/us144mkii.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +// Copyright (c) 2025 Šerif Rami + +#ifndef __US144MKII_H +#define __US144MKII_H + +#include +#include +#include + +#define DRIVER_NAME "us144mkii" + +/* --- USB Device Identification --- */ +#define USB_VID_TASCAM 0x0644 +#define USB_PID_TASCAM_US144 0x800f +#define USB_PID_TASCAM_US144MKII 0x8020 + +/* --- USB Control Message Protocol --- */ +#define RT_D2H_VENDOR_DEV (USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_DEVICE) +#define VENDOR_REQ_MODE_CONTROL 0x49 +#define MODE_VAL_HANDSHAKE_READ 0x0000 +#define USB_CTRL_TIMEOUT_MS 1000 + +/** + * struct tascam_card - Driver data structure for TASCAM US-144MKII. + * @dev: Pointer to the USB device. + * @iface0: Pointer to USB interface 0 (audio). + * @iface1: Pointer to USB interface 1 (MIDI). + * @card: Pointer to the ALSA sound card instance. + */ +struct tascam_card { + struct usb_device *dev; + struct usb_interface *iface0; + struct usb_interface *iface1; + struct snd_card *card; +}; + + #endif /* __US144MKII_H */ From 5c8c10796e274d1b5bb48756a45a6f2e865b30f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0erif=20Rami?= Date: Thu, 14 Aug 2025 19:22:17 +0200 Subject: [PATCH 00974/11391] ALSA: usb-audio: us144mkii: Add PCM core infrastructure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds the ALSA PCM device infrastructure. It creates a new PCM device with one playback and one capture stream. The hardware capabilities (formats, rates, channels) are defined in `tascam_pcm_hw`. The core PCM operations (`snd_pcm_ops`) for both playback and capture are implemented, including open, close, hw_params, prepare, and pointer callbacks. The trigger callback is a stub for now. This commit allows user-space applications to interact with the ALSA device, but no audio will be streamed yet. Signed-off-by: Šerif Rami Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250814172222.9448-3-ramiserifpersia@gmail.com --- sound/usb/usx2y/us144mkii.c | 20 ++++- sound/usb/usx2y/us144mkii.h | 46 +++++++++++- sound/usb/usx2y/us144mkii_capture.c | 107 +++++++++++++++++++++++++++ sound/usb/usx2y/us144mkii_pcm.c | 78 +++++++++++++++++++ sound/usb/usx2y/us144mkii_pcm.h | 76 +++++++++++++++++++ sound/usb/usx2y/us144mkii_playback.c | 107 +++++++++++++++++++++++++++ 6 files changed, 428 insertions(+), 6 deletions(-) create mode 100644 sound/usb/usx2y/us144mkii_capture.c create mode 100644 sound/usb/usx2y/us144mkii_pcm.c create mode 100644 sound/usb/usx2y/us144mkii_pcm.h create mode 100644 sound/usb/usx2y/us144mkii_playback.c diff --git a/sound/usb/usx2y/us144mkii.c b/sound/usb/usx2y/us144mkii.c index 00d13b039589..a41f48fe2bee 100644 --- a/sound/usb/usx2y/us144mkii.c +++ b/sound/usb/usx2y/us144mkii.c @@ -22,7 +22,7 @@ MODULE_LICENSE("GPL"); * Defaults to "US144MKII". * @param enable: Array of booleans to enable or disable each device. * Defaults to {1, 0, ..., 0} (first device enabled). - * @param dev_idx: Internal counter for probed TASCAM devices. + * @param dev_idx: Internal counter for the number of TASCAM devices probed. */ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; @@ -36,7 +36,7 @@ static int tascam_suspend(struct usb_interface *intf, pm_message_t message); static int tascam_resume(struct usb_interface *intf); /** - * tascam_card_private_free() - Frees private data for the sound card. + * tascam_card_private_free() - Frees private data associated with the sound * card. * @card: Pointer to the ALSA sound card instance. * @@ -58,12 +58,12 @@ static void tascam_card_private_free(struct snd_card *card) * @intf: The USB interface being probed. * @usb_id: The USB device ID. * - * This function is the entry point for the USB driver on device match. + * This function is the entry point for the USB driver when a matching device * is found. It performs initial device setup, including: * - Checking for the second interface (MIDI) and associating it. * - Performing a vendor-specific handshake with the device. * - Setting alternate settings for USB interfaces. - * - Creating and registering the ALSA sound card. + * - Creating and registering the ALSA sound card and PCM device. * * Return: 0 on success, or a negative error code on failure. */ @@ -154,6 +154,18 @@ static int tascam_probe(struct usb_interface *intf, tascam->digital_out_source = 1; tascam->capture_34_source = 1; + spin_lock_init(&tascam->lock); + + err = snd_pcm_new(card, "US144MKII PCM", 0, 1, 1, &tascam->pcm); + if (err < 0) + goto free_card; + tascam->pcm->private_data = tascam; + strscpy(tascam->pcm->name, "US144MKII PCM", sizeof(tascam->pcm->name)); + + err = tascam_init_pcm(tascam->pcm); + if (err < 0) + goto free_card; + strscpy(card->driver, DRIVER_NAME, sizeof(card->driver)); if (dev->descriptor.idProduct == USB_PID_TASCAM_US144) { strscpy(card->shortname, "TASCAM US-144", diff --git a/sound/usb/usx2y/us144mkii.h b/sound/usb/usx2y/us144mkii.h index 9f59863fab57..44f3b44bbf3b 100644 --- a/sound/usb/usx2y/us144mkii.h +++ b/sound/usb/usx2y/us144mkii.h @@ -21,18 +21,60 @@ #define MODE_VAL_HANDSHAKE_READ 0x0000 #define USB_CTRL_TIMEOUT_MS 1000 +/* --- Audio Format Configuration --- */ +#define BYTES_PER_SAMPLE 3 +#define NUM_CHANNELS 4 +#define BYTES_PER_FRAME (NUM_CHANNELS * BYTES_PER_SAMPLE) + +/* --- USB Control Message Protocol --- */ +#define RT_D2H_VENDOR_DEV (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE) +#define VENDOR_REQ_MODE_CONTROL 0x49 +#define MODE_VAL_HANDSHAKE_READ 0x0000 +#define USB_CTRL_TIMEOUT_MS 1000 + +struct tascam_card; + +#include "us144mkii_pcm.h" + /** - * struct tascam_card - Driver data structure for TASCAM US-144MKII. + * struct tascam_card - Main driver data structure for the TASCAM US-144MKII. * @dev: Pointer to the USB device. * @iface0: Pointer to USB interface 0 (audio). * @iface1: Pointer to USB interface 1 (MIDI). * @card: Pointer to the ALSA sound card instance. + * @pcm: Pointer to the ALSA PCM device. + * @playback_substream: Pointer to the active playback PCM substream. + * @capture_substream: Pointer to the active capture PCM substream. + * @playback_active: Atomic flag indicating if playback is active. + * @capture_active: Atomic flag indicating if capture is active. + * @driver_playback_pos: Current position in the ALSA playback buffer (frames). + * @driver_capture_pos: Current position in the ALSA capture buffer (frames). + * @playback_frames_consumed: Total frames consumed by playback. + * @capture_frames_processed: Total frames processed for capture. + * @current_rate: Currently configured sample rate of the device. + * @lock: Main spinlock for protecting shared driver state. */ struct tascam_card { struct usb_device *dev; struct usb_interface *iface0; struct usb_interface *iface1; struct snd_card *card; + struct snd_pcm *pcm; + + struct snd_pcm_substream *playback_substream; + struct snd_pcm_substream *capture_substream; + + atomic_t playback_active; + atomic_t capture_active; + + snd_pcm_uframes_t driver_playback_pos; + snd_pcm_uframes_t driver_capture_pos; + + u64 playback_frames_consumed; + u64 capture_frames_processed; + + int current_rate; + spinlock_t lock; }; - #endif /* __US144MKII_H */ +#endif /* __US144MKII_H */ diff --git a/sound/usb/usx2y/us144mkii_capture.c b/sound/usb/usx2y/us144mkii_capture.c new file mode 100644 index 000000000000..f258198ec94b --- /dev/null +++ b/sound/usb/usx2y/us144mkii_capture.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2025 Šerif Rami + +#include "us144mkii.h" + +/** + * tascam_capture_open() - Opens the PCM capture substream. + * @substream: The ALSA PCM substream to open. + * + * This function sets the hardware parameters for the capture substream + * and stores a reference to the substream in the driver's private data. + * + * Return: 0 on success. + */ +static int tascam_capture_open(struct snd_pcm_substream *substream) +{ + struct tascam_card *tascam = snd_pcm_substream_chip(substream); + + substream->runtime->hw = tascam_pcm_hw; + tascam->capture_substream = substream; + atomic_set(&tascam->capture_active, 0); + + return 0; +} + +/** + * tascam_capture_close() - Closes the PCM capture substream. + * @substream: The ALSA PCM substream to close. + * + * This function clears the reference to the capture substream in the + * driver's private data. + * + * Return: 0 on success. + */ +static int tascam_capture_close(struct snd_pcm_substream *substream) +{ + struct tascam_card *tascam = snd_pcm_substream_chip(substream); + + tascam->capture_substream = NULL; + + return 0; +} + +/** + * tascam_capture_prepare() - Prepares the PCM capture substream for use. + * @substream: The ALSA PCM substream to prepare. + * + * This function initializes capture-related counters. + * + * Return: 0 on success. + */ +static int tascam_capture_prepare(struct snd_pcm_substream *substream) +{ + struct tascam_card *tascam = snd_pcm_substream_chip(substream); + + tascam->driver_capture_pos = 0; + tascam->capture_frames_processed = 0; + + return 0; +} + +/** + * tascam_capture_pointer() - Returns the current capture pointer position. + * @substream: The ALSA PCM substream. + * + * This function returns the current position of the capture pointer within + * the ALSA ring buffer, in frames. + * + * Return: The current capture pointer position in frames. + */ +static snd_pcm_uframes_t +tascam_capture_pointer(struct snd_pcm_substream *substream) +{ + struct tascam_card *tascam = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + u64 pos; + + if (!atomic_read(&tascam->capture_active)) + return 0; + + scoped_guard(spinlock_irqsave, &tascam->lock) { + pos = tascam->capture_frames_processed; + } + + if (runtime->buffer_size == 0) + return 0; + + return do_div(pos, runtime->buffer_size); +} + +/** + * tascam_capture_ops - ALSA PCM operations for capture. + * + * This structure defines the callback functions for capture stream operations, + * including open, close, ioctl, hardware parameters, hardware free, prepare, + * trigger, and pointer. + */ +const struct snd_pcm_ops tascam_capture_ops = { + .open = tascam_capture_open, + .close = tascam_capture_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = tascam_pcm_hw_params, + .hw_free = tascam_pcm_hw_free, + .prepare = tascam_capture_prepare, + .trigger = tascam_pcm_trigger, + .pointer = tascam_capture_pointer, +}; diff --git a/sound/usb/usx2y/us144mkii_pcm.c b/sound/usb/usx2y/us144mkii_pcm.c new file mode 100644 index 000000000000..944b4d0ee2ec --- /dev/null +++ b/sound/usb/usx2y/us144mkii_pcm.c @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2025 Šerif Rami + +#include "us144mkii.h" + +const struct snd_pcm_hardware tascam_pcm_hw = { + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .rates = (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000), + .rate_min = 44100, + .rate_max = 96000, + .channels_min = NUM_CHANNELS, + .channels_max = NUM_CHANNELS, + .buffer_bytes_max = 1024 * 1024, + .period_bytes_min = 48 * BYTES_PER_FRAME, + .period_bytes_max = 1024 * BYTES_PER_FRAME, + .periods_min = 2, + .periods_max = 1024, +}; + +int tascam_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + return 0; +} + +int tascam_pcm_hw_free(struct snd_pcm_substream *substream) +{ + return 0; +} + +int tascam_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct tascam_card *tascam = snd_pcm_substream_chip(substream); + int err = 0; + + scoped_guard(spinlock_irqsave, &tascam->lock) { + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + if (!atomic_read(&tascam->playback_active)) { + atomic_set(&tascam->playback_active, 1); + atomic_set(&tascam->capture_active, 1); + } + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (atomic_read(&tascam->playback_active)) { + atomic_set(&tascam->playback_active, 0); + atomic_set(&tascam->capture_active, 0); + } + break; + default: + err = -EINVAL; + break; + } + } + + return err; +} + +int tascam_init_pcm(struct snd_pcm *pcm) +{ + struct tascam_card *tascam = pcm->private_data; + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &tascam_playback_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &tascam_capture_ops); + + snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, + tascam->dev->dev.parent, 64 * 1024, + tascam_pcm_hw.buffer_bytes_max); + + return 0; +} diff --git a/sound/usb/usx2y/us144mkii_pcm.h b/sound/usb/usx2y/us144mkii_pcm.h new file mode 100644 index 000000000000..bb8b51f9b6fb --- /dev/null +++ b/sound/usb/usx2y/us144mkii_pcm.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +// Copyright (c) 2025 Šerif Rami + +#ifndef __US144MKII_PCM_H +#define __US144MKII_PCM_H + +#include "us144mkii.h" + +/** + * tascam_pcm_hw - Hardware capabilities for TASCAM US-144MKII PCM. + * + * Defines the supported PCM formats, rates, channels, and buffer/period sizes + * for the TASCAM US-144MKII audio interface. + */ +extern const struct snd_pcm_hardware tascam_pcm_hw; + +/** + * tascam_playback_ops - ALSA PCM operations for playback. + * + * This structure defines the callback functions for playback stream operations. + */ +extern const struct snd_pcm_ops tascam_playback_ops; + +/** + * tascam_capture_ops - ALSA PCM operations for capture. + * + * This structure defines the callback functions for capture stream operations. + */ +extern const struct snd_pcm_ops tascam_capture_ops; + +/** + * tascam_init_pcm() - Initializes the ALSA PCM device. + * @pcm: Pointer to the ALSA PCM device to initialize. + * + * This function sets up the PCM operations and preallocates pages for the + * PCM buffer. + * + * Return: 0 on success, or a negative error code on failure. + */ +int tascam_init_pcm(struct snd_pcm *pcm); + +/** + * tascam_pcm_hw_params() - Configures hardware parameters for PCM streams. + * @substream: The ALSA PCM substream. + * @params: The hardware parameters to apply. + * + * This function is a stub for handling hardware parameter configuration. + * + * Return: 0 on success. + */ +int tascam_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params); + +/** + * tascam_pcm_hw_free() - Frees hardware parameters for PCM streams. + * @substream: The ALSA PCM substream. + * + * This function is a stub for freeing hardware-related resources. + * + * Return: 0 on success. + */ +int tascam_pcm_hw_free(struct snd_pcm_substream *substream); + +/** + * tascam_pcm_trigger() - Triggers the start or stop of PCM streams. + * @substream: The ALSA PCM substream. + * @cmd: The trigger command (e.g., SNDRV_PCM_TRIGGER_START). + * + * This function handles starting and stopping of playback and capture streams + * by setting atomic flags. + * + * Return: 0 on success, or a negative error code on failure. + */ +int tascam_pcm_trigger(struct snd_pcm_substream *substream, int cmd); + +#endif /* __US144MKII_PCM_H */ diff --git a/sound/usb/usx2y/us144mkii_playback.c b/sound/usb/usx2y/us144mkii_playback.c new file mode 100644 index 000000000000..0785c58f1197 --- /dev/null +++ b/sound/usb/usx2y/us144mkii_playback.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2025 Šerif Rami + +#include "us144mkii.h" + +/** + * tascam_playback_open() - Opens the PCM playback substream. + * @substream: The ALSA PCM substream to open. + * + * This function sets the hardware parameters for the playback substream + * and stores a reference to the substream in the driver's private data. + * + * Return: 0 on success. + */ +static int tascam_playback_open(struct snd_pcm_substream *substream) +{ + struct tascam_card *tascam = snd_pcm_substream_chip(substream); + + substream->runtime->hw = tascam_pcm_hw; + tascam->playback_substream = substream; + atomic_set(&tascam->playback_active, 0); + + return 0; +} + +/** + * tascam_playback_close() - Closes the PCM playback substream. + * @substream: The ALSA PCM substream to close. + * + * This function clears the reference to the playback substream in the + * driver's private data. + * + * Return: 0 on success. + */ +static int tascam_playback_close(struct snd_pcm_substream *substream) +{ + struct tascam_card *tascam = snd_pcm_substream_chip(substream); + + tascam->playback_substream = NULL; + + return 0; +} + +/** + * tascam_playback_prepare() - Prepares the PCM playback substream for use. + * @substream: The ALSA PCM substream to prepare. + * + * This function initializes playback-related counters. + * + * Return: 0 on success. + */ +static int tascam_playback_prepare(struct snd_pcm_substream *substream) +{ + struct tascam_card *tascam = snd_pcm_substream_chip(substream); + + tascam->driver_playback_pos = 0; + tascam->playback_frames_consumed = 0; + + return 0; +} + +/** + * tascam_playback_pointer() - Returns the current playback pointer position. + * @substream: The ALSA PCM substream. + * + * This function returns the current position of the playback pointer within + * the ALSA ring buffer, in frames. + * + * Return: The current playback pointer position in frames. + */ +static snd_pcm_uframes_t +tascam_playback_pointer(struct snd_pcm_substream *substream) +{ + struct tascam_card *tascam = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + u64 pos; + + if (!atomic_read(&tascam->playback_active)) + return 0; + + scoped_guard(spinlock_irqsave, &tascam->lock) { + pos = tascam->playback_frames_consumed; + } + + if (runtime->buffer_size == 0) + return 0; + + return do_div(pos, runtime->buffer_size); +} + +/** + * tascam_playback_ops - ALSA PCM operations for playback. + * + * This structure defines the callback functions for playback stream operations, + * including open, close, ioctl, hardware parameters, hardware free, prepare, + * trigger, and pointer. + */ +const struct snd_pcm_ops tascam_playback_ops = { + .open = tascam_playback_open, + .close = tascam_playback_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = tascam_pcm_hw_params, + .hw_free = tascam_pcm_hw_free, + .prepare = tascam_playback_prepare, + .trigger = tascam_pcm_trigger, + .pointer = tascam_playback_pointer, +}; From a2a2210f2c2e65a39631e4be727f1f9cc155171a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0erif=20Rami?= Date: Thu, 14 Aug 2025 19:22:18 +0200 Subject: [PATCH 00975/11391] ALSA: usb-audio: us144mkii: Implement audio playback and feedback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch implements the full audio playback data path. It introduces the allocation, submission, and completion handling for isochronous playback and feedback URBs. The feedback URB completion handler is the core of the driver's clocking mechanism. It reads the number of samples consumed by the device and uses a pattern-based algorithm to adjust the size of outgoing playback packets. This keeps the host and device synchronized and prevents xruns. The patch also adds the necessary vendor and UAC control messages to configure the device's sample rate. The PCM trigger is updated to start and stop the playback and feedback URBs. Basic suspend and resume handlers are included to manage stream state across power cycles. Signed-off-by: Šerif Rami Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250814172222.9448-4-ramiserifpersia@gmail.com --- sound/usb/usx2y/us144mkii.c | 171 ++++++++++++- sound/usb/usx2y/us144mkii.h | 188 ++++++++++++-- sound/usb/usx2y/us144mkii_capture.c | 1 + sound/usb/usx2y/us144mkii_pcm.c | 225 ++++++++++++++++- sound/usb/usx2y/us144mkii_pcm.h | 64 ++++- sound/usb/usx2y/us144mkii_playback.c | 351 ++++++++++++++++++++++++++- 6 files changed, 968 insertions(+), 32 deletions(-) diff --git a/sound/usb/usx2y/us144mkii.c b/sound/usb/usx2y/us144mkii.c index a41f48fe2bee..2265bf8503da 100644 --- a/sound/usb/usx2y/us144mkii.c +++ b/sound/usb/usx2y/us144mkii.c @@ -35,6 +35,110 @@ static void tascam_disconnect(struct usb_interface *intf); static int tascam_suspend(struct usb_interface *intf, pm_message_t message); static int tascam_resume(struct usb_interface *intf); +void tascam_free_urbs(struct tascam_card *tascam) +{ + int i; + + usb_kill_anchored_urbs(&tascam->playback_anchor); + for (i = 0; i < NUM_PLAYBACK_URBS; i++) { + if (tascam->playback_urbs[i]) { + usb_free_coherent( + tascam->dev, tascam->playback_urb_alloc_size, + tascam->playback_urbs[i]->transfer_buffer, + tascam->playback_urbs[i]->transfer_dma); + usb_free_urb(tascam->playback_urbs[i]); + tascam->playback_urbs[i] = NULL; + } + } + + usb_kill_anchored_urbs(&tascam->feedback_anchor); + for (i = 0; i < NUM_FEEDBACK_URBS; i++) { + if (tascam->feedback_urbs[i]) { + usb_free_coherent( + tascam->dev, tascam->feedback_urb_alloc_size, + tascam->feedback_urbs[i]->transfer_buffer, + tascam->feedback_urbs[i]->transfer_dma); + usb_free_urb(tascam->feedback_urbs[i]); + tascam->feedback_urbs[i] = NULL; + } + } +} + +int tascam_alloc_urbs(struct tascam_card *tascam) +{ + int i; + size_t max_packet_size; + + max_packet_size = ((96000 / 8000) + 2) * BYTES_PER_FRAME; + tascam->playback_urb_alloc_size = + max_packet_size * PLAYBACK_URB_PACKETS; + + for (i = 0; i < NUM_PLAYBACK_URBS; i++) { + struct urb *urb = + usb_alloc_urb(PLAYBACK_URB_PACKETS, GFP_KERNEL); + + if (!urb) + goto error; + tascam->playback_urbs[i] = urb; + + urb->transfer_buffer = usb_alloc_coherent( + tascam->dev, tascam->playback_urb_alloc_size, + GFP_KERNEL, &urb->transfer_dma); + if (!urb->transfer_buffer) + goto error; + + urb->dev = tascam->dev; + urb->pipe = usb_sndisocpipe(tascam->dev, EP_AUDIO_OUT); + urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; + urb->interval = 1; + urb->context = tascam; + urb->complete = playback_urb_complete; + } + + tascam->feedback_urb_alloc_size = + FEEDBACK_PACKET_SIZE * FEEDBACK_URB_PACKETS; + + for (i = 0; i < NUM_FEEDBACK_URBS; i++) { + struct urb *f_urb = + usb_alloc_urb(FEEDBACK_URB_PACKETS, GFP_KERNEL); + + if (!f_urb) + goto error; + tascam->feedback_urbs[i] = f_urb; + + f_urb->transfer_buffer = usb_alloc_coherent( + tascam->dev, tascam->feedback_urb_alloc_size, + GFP_KERNEL, &f_urb->transfer_dma); + if (!f_urb->transfer_buffer) + goto error; + + f_urb->dev = tascam->dev; + f_urb->pipe = + usb_rcvisocpipe(tascam->dev, EP_PLAYBACK_FEEDBACK); + f_urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; + f_urb->interval = 4; + f_urb->context = tascam; + f_urb->complete = feedback_urb_complete; + } + + return 0; + +error: + dev_err(tascam->card->dev, "Failed to allocate URBs\n"); + tascam_free_urbs(tascam); + return -ENOMEM; +} + +void tascam_stop_work_handler(struct work_struct *work) +{ + struct tascam_card *tascam = + container_of(work, struct tascam_card, stop_work); + + usb_kill_anchored_urbs(&tascam->playback_anchor); + usb_kill_anchored_urbs(&tascam->feedback_anchor); + atomic_set(&tascam->active_urbs, 0); +} + /** * tascam_card_private_free() - Frees private data associated with the sound * card. @@ -64,6 +168,7 @@ static void tascam_card_private_free(struct snd_card *card) * - Performing a vendor-specific handshake with the device. * - Setting alternate settings for USB interfaces. * - Creating and registering the ALSA sound card and PCM device. + * - Allocating and initializing URBs for audio transfers. * * Return: 0 on success, or a negative error code on failure. */ @@ -155,6 +260,11 @@ static int tascam_probe(struct usb_interface *intf, tascam->capture_34_source = 1; spin_lock_init(&tascam->lock); + init_usb_anchor(&tascam->playback_anchor); + init_usb_anchor(&tascam->feedback_anchor); + + INIT_WORK(&tascam->stop_work, tascam_stop_work_handler); + INIT_WORK(&tascam->stop_pcm_work, tascam_stop_pcm_work_handler); err = snd_pcm_new(card, "US144MKII PCM", 0, 1, 1, &tascam->pcm); if (err < 0) @@ -166,6 +276,10 @@ static int tascam_probe(struct usb_interface *intf, if (err < 0) goto free_card; + err = tascam_alloc_urbs(tascam); + if (err < 0) + goto free_card; + strscpy(card->driver, DRIVER_NAME, sizeof(card->driver)); if (dev->descriptor.idProduct == USB_PID_TASCAM_US144) { strscpy(card->shortname, "TASCAM US-144", @@ -191,6 +305,7 @@ static int tascam_probe(struct usb_interface *intf, return 0; free_card: + tascam_free_urbs(tascam); snd_card_free(card); return err; } @@ -200,7 +315,8 @@ static int tascam_probe(struct usb_interface *intf, * @intf: The USB interface being disconnected. * * This function is called when the device is disconnected from the system. - * It cleans up all allocated resources by freeing the sound card. + * It cleans up all allocated resources by freeing the sound card, which in + * turn triggers freeing of URBs and other resources. */ static void tascam_disconnect(struct usb_interface *intf) { @@ -211,6 +327,9 @@ static void tascam_disconnect(struct usb_interface *intf) if (intf->cur_altsetting->desc.bInterfaceNumber == 0) { snd_card_disconnect(tascam->card); + cancel_work_sync(&tascam->stop_work); + cancel_work_sync(&tascam->stop_pcm_work); + tascam_free_urbs(tascam); snd_card_free(tascam->card); dev_idx--; } @@ -221,12 +340,25 @@ static void tascam_disconnect(struct usb_interface *intf) * @intf: The USB interface being suspended. * @message: Power management message. * - * This function is a stub for handling device suspension. + * This function is called when the device is suspended. It stops all active + * streams and kills all URBs. * * Return: 0 on success. */ static int tascam_suspend(struct usb_interface *intf, pm_message_t message) { + struct tascam_card *tascam = usb_get_intfdata(intf); + + if (!tascam) + return 0; + + snd_pcm_suspend_all(tascam->pcm); + + cancel_work_sync(&tascam->stop_work); + cancel_work_sync(&tascam->stop_pcm_work); + usb_kill_anchored_urbs(&tascam->playback_anchor); + usb_kill_anchored_urbs(&tascam->feedback_anchor); + return 0; } @@ -234,12 +366,43 @@ static int tascam_suspend(struct usb_interface *intf, pm_message_t message) * tascam_resume() - Handles device resumption from suspend. * @intf: The USB interface being resumed. * - * This function is a stub for handling device resumption. + * This function is called when the device resumes from suspend. It + * re-establishes the active USB interface settings and re-configures the sample + * rate if it was previously active. * - * Return: 0 on success. + * Return: 0 on success, or a negative error code on failure. */ static int tascam_resume(struct usb_interface *intf) { + struct tascam_card *tascam = usb_get_intfdata(intf); + int err; + + if (!tascam) + return 0; + + dev_info(&intf->dev, "resuming TASCAM US-144MKII\n"); + + /* Re-establish the active USB interface settings. */ + err = usb_set_interface(tascam->dev, 0, 1); + if (err < 0) { + dev_err(&intf->dev, + "resume: failed to set alt setting on intf 0: %d\n", + err); + return err; + } + err = usb_set_interface(tascam->dev, 1, 1); + if (err < 0) { + dev_err(&intf->dev, + "resume: failed to set alt setting on intf 1: %d\n", + err); + return err; + } + + /* Re-configure the sample rate if one was previously active */ + if (tascam->current_rate > 0) + us144mkii_configure_device_for_rate(tascam, + tascam->current_rate); + return 0; } diff --git a/sound/usb/usx2y/us144mkii.h b/sound/usb/usx2y/us144mkii.h index 44f3b44bbf3b..53a74178e373 100644 --- a/sound/usb/usx2y/us144mkii.h +++ b/sound/usb/usx2y/us144mkii.h @@ -5,6 +5,7 @@ #define __US144MKII_H #include +#include #include #include @@ -15,27 +16,87 @@ #define USB_PID_TASCAM_US144 0x800f #define USB_PID_TASCAM_US144MKII 0x8020 +/* --- USB Endpoints (Alternate Setting 1) --- */ +#define EP_PLAYBACK_FEEDBACK 0x81 +#define EP_AUDIO_OUT 0x02 + /* --- USB Control Message Protocol --- */ -#define RT_D2H_VENDOR_DEV (USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_DEVICE) -#define VENDOR_REQ_MODE_CONTROL 0x49 -#define MODE_VAL_HANDSHAKE_READ 0x0000 +#define RT_H2D_CLASS_EP (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT) +#define RT_D2H_VENDOR_DEV (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE) +#define RT_H2D_VENDOR_DEV (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE) + +enum uac_request { + UAC_SET_CUR = 0x01, +}; + +enum uac_control_selector { + UAC_SAMPLING_FREQ_CONTROL = 0x0100, +}; + +enum tascam_vendor_request { + VENDOR_REQ_REGISTER_WRITE = 0x41, + VENDOR_REQ_MODE_CONTROL = 0x49, +}; + +enum tascam_mode_value { + MODE_VAL_HANDSHAKE_READ = 0x0000, + MODE_VAL_CONFIG = 0x0010, + MODE_VAL_STREAM_START = 0x0030, +}; + +enum tascam_register { + REG_ADDR_UNKNOWN_0D = 0x0d04, + REG_ADDR_UNKNOWN_0E = 0x0e00, + REG_ADDR_UNKNOWN_0F = 0x0f00, + REG_ADDR_RATE_44100 = 0x1000, + REG_ADDR_RATE_48000 = 0x1002, + REG_ADDR_RATE_88200 = 0x1008, + REG_ADDR_RATE_96000 = 0x100a, + REG_ADDR_UNKNOWN_11 = 0x110b, +}; + +#define REG_VAL_ENABLE 0x0101 + +/* --- URB Configuration --- */ +#define NUM_PLAYBACK_URBS 4 +#define PLAYBACK_URB_PACKETS 8 +#define NUM_FEEDBACK_URBS 4 +#define FEEDBACK_URB_PACKETS 1 +#define FEEDBACK_PACKET_SIZE 3 #define USB_CTRL_TIMEOUT_MS 1000 +#define FEEDBACK_SYNC_LOSS_THRESHOLD 41 /* --- Audio Format Configuration --- */ #define BYTES_PER_SAMPLE 3 #define NUM_CHANNELS 4 #define BYTES_PER_FRAME (NUM_CHANNELS * BYTES_PER_SAMPLE) - -/* --- USB Control Message Protocol --- */ -#define RT_D2H_VENDOR_DEV (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE) -#define VENDOR_REQ_MODE_CONTROL 0x49 -#define MODE_VAL_HANDSHAKE_READ 0x0000 -#define USB_CTRL_TIMEOUT_MS 1000 +#define FEEDBACK_ACCUMULATOR_SIZE 128 struct tascam_card; #include "us144mkii_pcm.h" +/** + * struct us144mkii_frame_pattern_observer - State for dynamic feedback + * patterns. + * @sample_rate_khz: The current sample rate in kHz. + * @base_feedback_value: The nominal feedback value for the current rate. + * @feedback_offset: An offset to align the feedback value range. + * @full_frame_patterns: A 2D array of pre-calculated packet size patterns. + * @current_index: The current index into the pattern array. + * @previous_index: The previous index, used for state tracking. + * @sync_locked: A flag indicating if the pattern has locked to the stream. + */ +struct us144mkii_frame_pattern_observer { + unsigned int sample_rate_khz; + unsigned int base_feedback_value; + int feedback_offset; + unsigned int full_frame_patterns[5][8]; + unsigned int current_index; + unsigned int previous_index; + bool sync_locked; +}; + /** * struct tascam_card - Main driver data structure for the TASCAM US-144MKII. * @dev: Pointer to the USB device. @@ -43,38 +104,121 @@ struct tascam_card; * @iface1: Pointer to USB interface 1 (MIDI). * @card: Pointer to the ALSA sound card instance. * @pcm: Pointer to the ALSA PCM device. + * * @playback_substream: Pointer to the active playback PCM substream. - * @capture_substream: Pointer to the active capture PCM substream. + * @playback_urbs: Array of URBs for playback. + * @playback_urb_alloc_size: Size of allocated buffer for each playback URB. + * @feedback_urbs: Array of URBs for feedback. + * @feedback_urb_alloc_size: Size of allocated buffer for each feedback URB. * @playback_active: Atomic flag indicating if playback is active. - * @capture_active: Atomic flag indicating if capture is active. - * @driver_playback_pos: Current position in the ALSA playback buffer (frames). - * @driver_capture_pos: Current position in the ALSA capture buffer (frames). * @playback_frames_consumed: Total frames consumed by playback. + * @driver_playback_pos: Current position in the ALSA playback buffer (frames). + * @last_period_pos: Last reported period position for playback. + * + * @capture_substream: Pointer to the active capture PCM substream. + * @capture_active: Atomic flag indicating if capture is active. + * @driver_capture_pos: Current position in the ALSA capture buffer (frames). * @capture_frames_processed: Total frames processed for capture. - * @current_rate: Currently configured sample rate of the device. + * @last_capture_period_pos: Last reported period position for capture. + * + * @stop_work: Work struct for deferred stream stopping. + * @stop_pcm_work: Work struct for stopping PCM due to a fatal error (e.g. + * xrun). + * * @lock: Main spinlock for protecting shared driver state. + * @active_urbs: Atomic counter for active URBs. + * @current_rate: Currently configured sample rate of the device. + * + * @feedback_accumulator_pattern: Stores the calculated frames per packet for + * feedback. + * @feedback_pattern_out_idx: Read index for feedback_accumulator_pattern. + * @feedback_pattern_in_idx: Write index for feedback_accumulator_pattern. + * @feedback_synced: Flag indicating if feedback is synced. + * @feedback_consecutive_errors: Counter for consecutive feedback errors. + * @feedback_urb_skip_count: Number of feedback URBs to skip initially for + * stabilization. + * @fpo: Holds the state for the dynamic feedback pattern generation. + * + * @playback_anchor: USB anchor for playback URBs. + * @feedback_anchor: USB anchor for feedback URBs. */ struct tascam_card { + /* --- Core device pointers --- */ struct usb_device *dev; struct usb_interface *iface0; struct usb_interface *iface1; struct snd_card *card; struct snd_pcm *pcm; + /* --- PCM Substreams --- */ struct snd_pcm_substream *playback_substream; struct snd_pcm_substream *capture_substream; + /* --- URBs and Anchors --- */ + struct urb *playback_urbs[NUM_PLAYBACK_URBS]; + size_t playback_urb_alloc_size; + struct urb *feedback_urbs[NUM_FEEDBACK_URBS]; + size_t feedback_urb_alloc_size; + struct usb_anchor playback_anchor; + struct usb_anchor feedback_anchor; + + /* --- Stream State --- */ + spinlock_t lock; atomic_t playback_active; atomic_t capture_active; - - snd_pcm_uframes_t driver_playback_pos; - snd_pcm_uframes_t driver_capture_pos; - - u64 playback_frames_consumed; - u64 capture_frames_processed; - + atomic_t active_urbs; int current_rate; - spinlock_t lock; + + /* --- Playback State --- */ + u64 playback_frames_consumed; + snd_pcm_uframes_t driver_playback_pos; + u64 last_period_pos; + + /* --- Capture State --- */ + u64 capture_frames_processed; + snd_pcm_uframes_t driver_capture_pos; + u64 last_capture_period_pos; + + /* --- Feedback Sync State --- */ + unsigned int feedback_accumulator_pattern[FEEDBACK_ACCUMULATOR_SIZE]; + unsigned int feedback_pattern_out_idx; + unsigned int feedback_pattern_in_idx; + bool feedback_synced; + unsigned int feedback_consecutive_errors; + unsigned int feedback_urb_skip_count; + struct us144mkii_frame_pattern_observer fpo; + + /* --- Workqueues --- */ + struct work_struct stop_work; + struct work_struct stop_pcm_work; }; +/** + * tascam_free_urbs() - Free all allocated URBs and associated buffers. + * @tascam: the tascam_card instance + * + * This function kills, unlinks, and frees all playback and feedback URBs, + * along with their transfer buffers. + */ +void tascam_free_urbs(struct tascam_card *tascam); + +/** + * tascam_alloc_urbs() - Allocate all URBs and associated buffers. + * @tascam: the tascam_card instance + * + * This function allocates and initializes all URBs for playback and feedback. + * + * Return: 0 on success, or a negative error code on failure. + */ +int tascam_alloc_urbs(struct tascam_card *tascam); + +/** + * tascam_stop_work_handler() - Work handler to stop all active streams. + * @work: Pointer to the work_struct. + * + * This function is scheduled to stop all active URBs (playback, feedback) + * and reset the active_urbs counter. + */ +void tascam_stop_work_handler(struct work_struct *work); + #endif /* __US144MKII_H */ diff --git a/sound/usb/usx2y/us144mkii_capture.c b/sound/usb/usx2y/us144mkii_capture.c index f258198ec94b..7e1b64f9a7b8 100644 --- a/sound/usb/usx2y/us144mkii_capture.c +++ b/sound/usb/usx2y/us144mkii_capture.c @@ -55,6 +55,7 @@ static int tascam_capture_prepare(struct snd_pcm_substream *substream) tascam->driver_capture_pos = 0; tascam->capture_frames_processed = 0; + tascam->last_capture_period_pos = 0; return 0; } diff --git a/sound/usb/usx2y/us144mkii_pcm.c b/sound/usb/usx2y/us144mkii_pcm.c index 944b4d0ee2ec..423c775051ad 100644 --- a/sound/usb/usx2y/us144mkii_pcm.c +++ b/sound/usb/usx2y/us144mkii_pcm.c @@ -3,6 +3,37 @@ #include "us144mkii.h" +/** + * fpo_init_pattern() - Generates a packet distribution pattern. + * @size: The number of elements in the pattern array (e.g., 8). + * @pattern_array: Pointer to the array to be populated. + * @initial_value: The base value to initialize each element with. + * @target_sum: The desired sum of all elements in the final array. + * + * This function initializes an array with a base value and then iteratively + * adjusts the elements to match a target sum, distributing the difference + * as evenly as possible. + */ +static void fpo_init_pattern(unsigned int size, unsigned int *pattern_array, + unsigned int initial_value, int target_sum) +{ + int diff, i; + + if (!size) + return; + + for (i = 0; i < size; ++i) + pattern_array[i] = initial_value; + + diff = target_sum - (size * initial_value); + for (i = 0; i < abs(diff); ++i) { + if (diff > 0) + pattern_array[i]++; + else + pattern_array[i]--; + } +} + const struct snd_pcm_hardware tascam_pcm_hw = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | @@ -21,9 +52,148 @@ const struct snd_pcm_hardware tascam_pcm_hw = { .periods_max = 1024, }; -int tascam_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +void process_playback_routing_us144mkii(struct tascam_card *tascam, + const u8 *src_buffer, u8 *dst_buffer, + size_t frames) { + /* This is a stub. Routing will be added in a later commit. */ + if (src_buffer != dst_buffer) + memcpy(dst_buffer, src_buffer, frames * BYTES_PER_FRAME); +} + +int us144mkii_configure_device_for_rate(struct tascam_card *tascam, int rate) +{ + struct usb_device *dev = tascam->dev; + u8 *rate_payload_buf __free(kfree) = NULL; + u16 rate_vendor_wValue; + int err = 0; + const u8 *current_payload_src; + + static const u8 payload_44100[] = { 0x44, 0xac, 0x00 }; + static const u8 payload_48000[] = { 0x80, 0xbb, 0x00 }; + static const u8 payload_88200[] = { 0x88, 0x58, 0x01 }; + static const u8 payload_96000[] = { 0x00, 0x77, 0x01 }; + + switch (rate) { + case 44100: + current_payload_src = payload_44100; + rate_vendor_wValue = REG_ADDR_RATE_44100; + break; + case 48000: + current_payload_src = payload_48000; + rate_vendor_wValue = REG_ADDR_RATE_48000; + break; + case 88200: + current_payload_src = payload_88200; + rate_vendor_wValue = REG_ADDR_RATE_88200; + break; + case 96000: + current_payload_src = payload_96000; + rate_vendor_wValue = REG_ADDR_RATE_96000; + break; + default: + dev_err(&dev->dev, + "Unsupported sample rate %d for configuration\n", rate); + return -EINVAL; + } + + rate_payload_buf = kmemdup(current_payload_src, 3, GFP_KERNEL); + if (!rate_payload_buf) + return -ENOMEM; + + dev_info(&dev->dev, "Configuring device for %d Hz\n", rate); + + err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + VENDOR_REQ_MODE_CONTROL, RT_H2D_VENDOR_DEV, + MODE_VAL_CONFIG, 0x0000, NULL, 0, + USB_CTRL_TIMEOUT_MS); + if (err < 0) + goto fail; + err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, + RT_H2D_CLASS_EP, UAC_SAMPLING_FREQ_CONTROL, + EP_AUDIO_OUT, rate_payload_buf, 3, + USB_CTRL_TIMEOUT_MS); + if (err < 0) + goto fail; + err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + VENDOR_REQ_REGISTER_WRITE, RT_H2D_VENDOR_DEV, + REG_ADDR_UNKNOWN_0D, REG_VAL_ENABLE, NULL, 0, + USB_CTRL_TIMEOUT_MS); + if (err < 0) + goto fail; + err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + VENDOR_REQ_REGISTER_WRITE, RT_H2D_VENDOR_DEV, + REG_ADDR_UNKNOWN_0E, REG_VAL_ENABLE, NULL, 0, + USB_CTRL_TIMEOUT_MS); + if (err < 0) + goto fail; + err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + VENDOR_REQ_REGISTER_WRITE, RT_H2D_VENDOR_DEV, + REG_ADDR_UNKNOWN_0F, REG_VAL_ENABLE, NULL, 0, + USB_CTRL_TIMEOUT_MS); + if (err < 0) + goto fail; + err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + VENDOR_REQ_REGISTER_WRITE, RT_H2D_VENDOR_DEV, + rate_vendor_wValue, REG_VAL_ENABLE, NULL, 0, + USB_CTRL_TIMEOUT_MS); + if (err < 0) + goto fail; + err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + VENDOR_REQ_REGISTER_WRITE, RT_H2D_VENDOR_DEV, + REG_ADDR_UNKNOWN_11, REG_VAL_ENABLE, NULL, 0, + USB_CTRL_TIMEOUT_MS); + if (err < 0) + goto fail; + err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + VENDOR_REQ_MODE_CONTROL, RT_H2D_VENDOR_DEV, + MODE_VAL_STREAM_START, 0x0000, NULL, 0, + USB_CTRL_TIMEOUT_MS); + if (err < 0) + goto fail; + return 0; + +fail: + dev_err(&dev->dev, + "Device configuration failed at rate %d with error %d\n", rate, + err); + return err; +} + +int tascam_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct tascam_card *tascam = snd_pcm_substream_chip(substream); + int err; + unsigned int rate = params_rate(params); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + tascam->fpo.sample_rate_khz = rate / 1000; + tascam->fpo.base_feedback_value = tascam->fpo.sample_rate_khz; + tascam->fpo.feedback_offset = 2; + tascam->fpo.current_index = 0; + tascam->fpo.previous_index = 0; + tascam->fpo.sync_locked = false; + + unsigned int initial_value = tascam->fpo.sample_rate_khz / 8; + + for (int i = 0; i < 5; i++) { + int target_sum = tascam->fpo.sample_rate_khz - + tascam->fpo.feedback_offset + i; + fpo_init_pattern(8, tascam->fpo.full_frame_patterns[i], + initial_value, target_sum); + } + } + + if (tascam->current_rate != rate) { + err = us144mkii_configure_device_for_rate(tascam, rate); + if (err < 0) { + tascam->current_rate = 0; + return err; + } + tascam->current_rate = rate; + } + return 0; } @@ -36,6 +206,9 @@ int tascam_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct tascam_card *tascam = snd_pcm_substream_chip(substream); int err = 0; + int i; + bool do_start = false; + bool do_stop = false; scoped_guard(spinlock_irqsave, &tascam->lock) { switch (cmd) { @@ -44,6 +217,7 @@ int tascam_pcm_trigger(struct snd_pcm_substream *substream, int cmd) if (!atomic_read(&tascam->playback_active)) { atomic_set(&tascam->playback_active, 1); atomic_set(&tascam->capture_active, 1); + do_start = true; } break; case SNDRV_PCM_TRIGGER_STOP: @@ -52,6 +226,7 @@ int tascam_pcm_trigger(struct snd_pcm_substream *substream, int cmd) if (atomic_read(&tascam->playback_active)) { atomic_set(&tascam->playback_active, 0); atomic_set(&tascam->capture_active, 0); + do_stop = true; } break; default: @@ -60,6 +235,52 @@ int tascam_pcm_trigger(struct snd_pcm_substream *substream, int cmd) } } + if (do_start) { + if (atomic_read(&tascam->active_urbs) > 0) { + dev_warn(tascam->card->dev, + "Cannot start, URBs still active.\n"); + return -EAGAIN; + } + + for (i = 0; i < NUM_FEEDBACK_URBS; i++) { + usb_get_urb(tascam->feedback_urbs[i]); + usb_anchor_urb(tascam->feedback_urbs[i], + &tascam->feedback_anchor); + err = usb_submit_urb(tascam->feedback_urbs[i], + GFP_ATOMIC); + if (err < 0) { + usb_unanchor_urb(tascam->feedback_urbs[i]); + usb_put_urb(tascam->feedback_urbs[i]); + atomic_dec(&tascam->active_urbs); + goto start_rollback; + } + atomic_inc(&tascam->active_urbs); + } + for (i = 0; i < NUM_PLAYBACK_URBS; i++) { + usb_get_urb(tascam->playback_urbs[i]); + usb_anchor_urb(tascam->playback_urbs[i], + &tascam->playback_anchor); + err = usb_submit_urb(tascam->playback_urbs[i], + GFP_ATOMIC); + if (err < 0) { + usb_unanchor_urb(tascam->playback_urbs[i]); + usb_put_urb(tascam->playback_urbs[i]); + atomic_dec(&tascam->active_urbs); + goto start_rollback; + } + atomic_inc(&tascam->active_urbs); + } + + return 0; +start_rollback: + dev_err(tascam->card->dev, + "Failed to submit URBs to start stream: %d\n", err); + do_stop = true; + } + + if (do_stop) + schedule_work(&tascam->stop_work); + return err; } diff --git a/sound/usb/usx2y/us144mkii_pcm.h b/sound/usb/usx2y/us144mkii_pcm.h index bb8b51f9b6fb..6ca00c3ce53d 100644 --- a/sound/usb/usx2y/us144mkii_pcm.h +++ b/sound/usb/usx2y/us144mkii_pcm.h @@ -28,6 +28,38 @@ extern const struct snd_pcm_ops tascam_playback_ops; */ extern const struct snd_pcm_ops tascam_capture_ops; +/** + * playback_urb_complete() - Completion handler for playback isochronous URBs. + * @urb: the completed URB + * + * This function runs in interrupt context. It calculates the number of bytes + * to send in the next set of packets based on the feedback-driven clock, + * copies the audio data from the ALSA ring buffer, and resubmits the URB. + */ +void playback_urb_complete(struct urb *urb); + +/** + * feedback_urb_complete() - Completion handler for feedback isochronous URBs. + * @urb: the completed URB + * + * This is the master clock for the driver. It runs in interrupt context. + * It reads the feedback value from the device, which indicates how many + * samples the device has consumed. This information is used to adjust the + * playback rate and to advance the capture stream pointer, keeping both + * streams in sync. It then calls snd_pcm_period_elapsed if necessary and + * resubmits itself. + */ +void feedback_urb_complete(struct urb *urb); + +/** + * tascam_stop_pcm_work_handler() - Work handler to stop PCM streams. + * @work: Pointer to the work_struct. + * + * This function is scheduled to stop PCM streams (playback and capture) + * from a workqueue context, avoiding blocking operations in interrupt context. + */ +void tascam_stop_pcm_work_handler(struct work_struct *work); + /** * tascam_init_pcm() - Initializes the ALSA PCM device. * @pcm: Pointer to the ALSA PCM device to initialize. @@ -39,14 +71,40 @@ extern const struct snd_pcm_ops tascam_capture_ops; */ int tascam_init_pcm(struct snd_pcm *pcm); +/** + * us144mkii_configure_device_for_rate() - Set sample rate via USB control msgs + * @tascam: the tascam_card instance + * @rate: the target sample rate (e.g., 44100, 96000) + * + * This function sends a sequence of vendor-specific and UAC control messages + * to configure the device hardware for the specified sample rate. + * + * Return: 0 on success, or a negative error code on failure. + */ +int us144mkii_configure_device_for_rate(struct tascam_card *tascam, int rate); + +/** + * process_playback_routing_us144mkii() - Apply playback routing matrix + * @tascam: The driver instance. + * @src_buffer: Buffer containing 4 channels of S24_3LE audio from ALSA. + * @dst_buffer: Buffer to be filled for the USB device. + * @frames: Number of frames to process. + */ +void process_playback_routing_us144mkii(struct tascam_card *tascam, + const u8 *src_buffer, u8 *dst_buffer, + size_t frames); + /** * tascam_pcm_hw_params() - Configures hardware parameters for PCM streams. * @substream: The ALSA PCM substream. * @params: The hardware parameters to apply. * - * This function is a stub for handling hardware parameter configuration. + * This function allocates pages for the PCM buffer and, for playback streams, + * selects the appropriate feedback patterns based on the requested sample rate. + * It also configures the device hardware for the selected sample rate if it + * has changed. * - * Return: 0 on success. + * Return: 0 on success, or a negative error code on failure. */ int tascam_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params); @@ -67,7 +125,7 @@ int tascam_pcm_hw_free(struct snd_pcm_substream *substream); * @cmd: The trigger command (e.g., SNDRV_PCM_TRIGGER_START). * * This function handles starting and stopping of playback and capture streams - * by setting atomic flags. + * by submitting or killing the associated URBs. * * Return: 0 on success, or a negative error code on failure. */ diff --git a/sound/usb/usx2y/us144mkii_playback.c b/sound/usb/usx2y/us144mkii_playback.c index 0785c58f1197..0cb9699ec211 100644 --- a/sound/usb/usx2y/us144mkii_playback.c +++ b/sound/usb/usx2y/us144mkii_playback.c @@ -45,16 +45,65 @@ static int tascam_playback_close(struct snd_pcm_substream *substream) * tascam_playback_prepare() - Prepares the PCM playback substream for use. * @substream: The ALSA PCM substream to prepare. * - * This function initializes playback-related counters. + * This function initializes playback-related counters and flags, and configures + * the playback URBs with appropriate packet sizes based on the nominal frame + * rate. * * Return: 0 on success. */ static int tascam_playback_prepare(struct snd_pcm_substream *substream) { struct tascam_card *tascam = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + int i, u; + size_t nominal_frames_per_packet, nominal_bytes_per_packet; + size_t total_bytes_in_urb; tascam->driver_playback_pos = 0; tascam->playback_frames_consumed = 0; + tascam->last_period_pos = 0; + tascam->feedback_pattern_in_idx = 0; + tascam->feedback_pattern_out_idx = 0; + tascam->feedback_synced = false; + tascam->feedback_consecutive_errors = 0; + tascam->feedback_urb_skip_count = NUM_FEEDBACK_URBS; + + nominal_frames_per_packet = runtime->rate / 8000; + for (i = 0; i < FEEDBACK_ACCUMULATOR_SIZE; i++) + tascam->feedback_accumulator_pattern[i] = + nominal_frames_per_packet; + + for (i = 0; i < NUM_FEEDBACK_URBS; i++) { + struct urb *f_urb = tascam->feedback_urbs[i]; + int j; + + f_urb->number_of_packets = FEEDBACK_URB_PACKETS; + f_urb->transfer_buffer_length = + FEEDBACK_URB_PACKETS * FEEDBACK_PACKET_SIZE; + for (j = 0; j < FEEDBACK_URB_PACKETS; j++) { + f_urb->iso_frame_desc[j].offset = + j * FEEDBACK_PACKET_SIZE; + f_urb->iso_frame_desc[j].length = FEEDBACK_PACKET_SIZE; + } + } + + nominal_bytes_per_packet = nominal_frames_per_packet * BYTES_PER_FRAME; + total_bytes_in_urb = nominal_bytes_per_packet * PLAYBACK_URB_PACKETS; + + for (u = 0; u < NUM_PLAYBACK_URBS; u++) { + struct urb *urb = tascam->playback_urbs[u]; + + memset(urb->transfer_buffer, 0, + tascam->playback_urb_alloc_size); + urb->transfer_buffer_length = total_bytes_in_urb; + urb->number_of_packets = PLAYBACK_URB_PACKETS; + for (i = 0; i < PLAYBACK_URB_PACKETS; i++) { + urb->iso_frame_desc[i].offset = + i * nominal_bytes_per_packet; + urb->iso_frame_desc[i].length = + nominal_bytes_per_packet; + } + } return 0; } @@ -105,3 +154,303 @@ const struct snd_pcm_ops tascam_playback_ops = { .trigger = tascam_pcm_trigger, .pointer = tascam_playback_pointer, }; + +void playback_urb_complete(struct urb *urb) +{ + struct tascam_card *tascam = urb->context; + struct snd_pcm_substream *substream; + struct snd_pcm_runtime *runtime; + size_t total_bytes_for_urb = 0; + snd_pcm_uframes_t offset_frames; + snd_pcm_uframes_t frames_to_copy; + int ret, i; + + if (urb->status) { + if (urb->status != -ENOENT && urb->status != -ECONNRESET && + urb->status != -ESHUTDOWN && urb->status != -ENODEV) + dev_err_ratelimited(tascam->card->dev, + "Playback URB failed: %d\n", + urb->status); + goto out; + } + if (!tascam || !atomic_read(&tascam->playback_active)) + goto out; + + substream = tascam->playback_substream; + if (!substream || !substream->runtime) + goto out; + runtime = substream->runtime; + + scoped_guard(spinlock_irqsave, &tascam->lock) { + for (i = 0; i < urb->number_of_packets; i++) { + unsigned int frames_for_packet; + size_t bytes_for_packet; + + if (tascam->feedback_synced) { + frames_for_packet = + tascam->feedback_accumulator_pattern + [tascam->feedback_pattern_out_idx]; + tascam->feedback_pattern_out_idx = + (tascam->feedback_pattern_out_idx + 1) % + FEEDBACK_ACCUMULATOR_SIZE; + } else { + frames_for_packet = runtime->rate / 8000; + } + bytes_for_packet = frames_for_packet * BYTES_PER_FRAME; + + urb->iso_frame_desc[i].offset = total_bytes_for_urb; + urb->iso_frame_desc[i].length = bytes_for_packet; + total_bytes_for_urb += bytes_for_packet; + } + urb->transfer_buffer_length = total_bytes_for_urb; + + offset_frames = tascam->driver_playback_pos; + frames_to_copy = bytes_to_frames(runtime, total_bytes_for_urb); + tascam->driver_playback_pos = + (offset_frames + frames_to_copy) % runtime->buffer_size; + } + + if (total_bytes_for_urb > 0) { + u8 *dst_buf = urb->transfer_buffer; + + /* Handle ring buffer wrap-around */ + if (offset_frames + frames_to_copy > runtime->buffer_size) { + size_t first_chunk_bytes = frames_to_bytes( + runtime, runtime->buffer_size - offset_frames); + size_t second_chunk_bytes = + total_bytes_for_urb - first_chunk_bytes; + + memcpy(dst_buf, + runtime->dma_area + + frames_to_bytes(runtime, offset_frames), + first_chunk_bytes); + memcpy(dst_buf + first_chunk_bytes, runtime->dma_area, + second_chunk_bytes); + } else { + memcpy(dst_buf, + runtime->dma_area + + frames_to_bytes(runtime, offset_frames), + total_bytes_for_urb); + } + + process_playback_routing_us144mkii(tascam, dst_buf, dst_buf, + frames_to_copy); + } + + urb->dev = tascam->dev; + usb_get_urb(urb); + usb_anchor_urb(urb, &tascam->playback_anchor); + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret < 0) { + dev_err_ratelimited(tascam->card->dev, + "Failed to resubmit playback URB: %d\n", + ret); + usb_unanchor_urb(urb); + usb_put_urb(urb); + atomic_dec( + &tascam->active_urbs); /* Decrement on failed resubmission */ + } +out: + usb_put_urb(urb); +} + +void feedback_urb_complete(struct urb *urb) +{ + struct tascam_card *tascam = urb->context; + struct snd_pcm_substream *playback_ss, *capture_ss; + struct snd_pcm_runtime *playback_rt, *capture_rt; + u64 total_frames_in_urb = 0; + int ret, p; + unsigned int old_in_idx, new_in_idx; + bool playback_period_elapsed = false; + bool capture_period_elapsed = false; + + if (urb->status) { + if (urb->status != -ENOENT && urb->status != -ECONNRESET && + urb->status != -ESHUTDOWN && urb->status != -ENODEV) { + dev_err_ratelimited(tascam->card->dev, + "Feedback URB failed: %d\n", + urb->status); + atomic_dec( + &tascam->active_urbs); /* Decrement on failed resubmission */ + } + goto out; + } + if (!tascam || !atomic_read(&tascam->playback_active)) + goto out; + + playback_ss = tascam->playback_substream; + if (!playback_ss || !playback_ss->runtime) + goto out; + playback_rt = playback_ss->runtime; + + capture_ss = tascam->capture_substream; + capture_rt = capture_ss ? capture_ss->runtime : NULL; + + scoped_guard(spinlock_irqsave, &tascam->lock) { + if (tascam->feedback_urb_skip_count > 0) { + tascam->feedback_urb_skip_count--; + break; + } + + old_in_idx = tascam->feedback_pattern_in_idx; + + for (p = 0; p < urb->number_of_packets; p++) { + u8 feedback_value = 0; + const unsigned int *pattern; + bool packet_ok = + (urb->iso_frame_desc[p].status == 0 && + urb->iso_frame_desc[p].actual_length >= 1); + + if (packet_ok) + feedback_value = + *((u8 *)urb->transfer_buffer + + urb->iso_frame_desc[p].offset); + + if (packet_ok) { + int delta = feedback_value - + tascam->fpo.base_feedback_value + + tascam->fpo.feedback_offset; + int pattern_idx; + + if (delta < 0) { + pattern_idx = + 0; // Clamp to the lowest pattern + } else if (delta >= 5) { + pattern_idx = + 4; // Clamp to the highest pattern + } else { + pattern_idx = delta; + } + + pattern = + tascam->fpo + .full_frame_patterns[pattern_idx]; + tascam->feedback_consecutive_errors = 0; + int i; + + for (i = 0; i < 8; i++) { + unsigned int in_idx = + (tascam->feedback_pattern_in_idx + + i) % + FEEDBACK_ACCUMULATOR_SIZE; + + tascam->feedback_accumulator_pattern + [in_idx] = pattern[i]; + total_frames_in_urb += pattern[i]; + } + } else { + unsigned int nominal_frames = + playback_rt->rate / 8000; + int i; + + if (tascam->feedback_synced) { + tascam->feedback_consecutive_errors++; + if (tascam->feedback_consecutive_errors > + FEEDBACK_SYNC_LOSS_THRESHOLD) { + dev_err(tascam->card->dev, + "Fatal: Feedback sync lost. Stopping stream.\n"); + schedule_work( + &tascam->stop_pcm_work); + tascam->feedback_synced = false; + break; + } + } + for (i = 0; i < 8; i++) { + unsigned int in_idx = + (tascam->feedback_pattern_in_idx + + i) % + FEEDBACK_ACCUMULATOR_SIZE; + + tascam->feedback_accumulator_pattern + [in_idx] = nominal_frames; + total_frames_in_urb += nominal_frames; + } + } + tascam->feedback_pattern_in_idx = + (tascam->feedback_pattern_in_idx + 8) % + FEEDBACK_ACCUMULATOR_SIZE; + } + + new_in_idx = tascam->feedback_pattern_in_idx; + + if (!tascam->feedback_synced) { + unsigned int out_idx = tascam->feedback_pattern_out_idx; + bool is_ahead = (new_in_idx - out_idx) % + FEEDBACK_ACCUMULATOR_SIZE < + (FEEDBACK_ACCUMULATOR_SIZE / 2); + bool was_behind = (old_in_idx - out_idx) % + FEEDBACK_ACCUMULATOR_SIZE >= + (FEEDBACK_ACCUMULATOR_SIZE / 2); + + if (is_ahead && was_behind) { + dev_dbg(tascam->card->dev, + "Sync Acquired! (in: %u, out: %u)\n", + new_in_idx, out_idx); + tascam->feedback_synced = true; + tascam->feedback_consecutive_errors = 0; + } + } + + if (total_frames_in_urb > 0) { + tascam->playback_frames_consumed += total_frames_in_urb; + if (atomic_read(&tascam->capture_active)) + tascam->capture_frames_processed += + total_frames_in_urb; + } + + if (playback_rt->period_size > 0) { + u64 current_period = + div_u64(tascam->playback_frames_consumed, + playback_rt->period_size); + + if (current_period > tascam->last_period_pos) { + tascam->last_period_pos = current_period; + playback_period_elapsed = true; + } + } + + if (atomic_read(&tascam->capture_active) && capture_rt && + capture_rt->period_size > 0) { + u64 current_capture_period = + div_u64(tascam->capture_frames_processed, + capture_rt->period_size); + + if (current_capture_period > + tascam->last_capture_period_pos) { + tascam->last_capture_period_pos = + current_capture_period; + capture_period_elapsed = true; + } + } + } + if (playback_period_elapsed) + snd_pcm_period_elapsed(playback_ss); + if (capture_period_elapsed) + snd_pcm_period_elapsed(capture_ss); + + urb->dev = tascam->dev; + usb_get_urb(urb); + usb_anchor_urb(urb, &tascam->feedback_anchor); + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret < 0) { + dev_err_ratelimited(tascam->card->dev, + "Failed to resubmit feedback URB: %d\n", + ret); + usb_unanchor_urb(urb); + usb_put_urb(urb); + } +out: + usb_put_urb(urb); +} + +void tascam_stop_pcm_work_handler(struct work_struct *work) +{ + struct tascam_card *tascam = + container_of(work, struct tascam_card, stop_pcm_work); + + if (tascam->playback_substream) + snd_pcm_stop(tascam->playback_substream, SNDRV_PCM_STATE_XRUN); + if (tascam->capture_substream) + snd_pcm_stop(tascam->capture_substream, SNDRV_PCM_STATE_XRUN); +} From c1bb0c13e430623c26543baae5bb9ae21139db87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0erif=20Rami?= Date: Thu, 14 Aug 2025 19:22:19 +0200 Subject: [PATCH 00976/11391] ALSA: usb-audio: us144mkii: Implement audio capture and decoding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds the full audio capture data path. It allocates and manages bulk URBs to receive audio data from the device. The incoming data is in a custom multiplexed format. A workqueue is used to offload the decoding process from the interrupt context. The `capture_urb_complete` handler copies raw data into a ring buffer and schedules the work. The `tascam_capture_work_handler` then reads from this buffer, decodes the data into standard S32_LE samples, and copies it to the ALSA capture buffer. The PCM trigger is updated to manage the submission of capture URBs, and the feedback handler now also advances the capture stream pointer to keep it synchronized with playback. Signed-off-by: Šerif Rami Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250814172222.9448-5-ramiserifpersia@gmail.com --- sound/usb/usx2y/us144mkii.c | 73 ++++++++++ sound/usb/usx2y/us144mkii.h | 44 +++++- sound/usb/usx2y/us144mkii_capture.c | 213 +++++++++++++++++++++++++++- sound/usb/usx2y/us144mkii_pcm.c | 30 ++++ sound/usb/usx2y/us144mkii_pcm.h | 35 ++++- 5 files changed, 387 insertions(+), 8 deletions(-) diff --git a/sound/usb/usx2y/us144mkii.c b/sound/usb/usx2y/us144mkii.c index 2265bf8503da..b2cde06613d2 100644 --- a/sound/usb/usx2y/us144mkii.c +++ b/sound/usb/usx2y/us144mkii.c @@ -62,6 +62,27 @@ void tascam_free_urbs(struct tascam_card *tascam) tascam->feedback_urbs[i] = NULL; } } + + usb_kill_anchored_urbs(&tascam->capture_anchor); + for (i = 0; i < NUM_CAPTURE_URBS; i++) { + if (tascam->capture_urbs[i]) { + usb_free_coherent( + tascam->dev, tascam->capture_urb_alloc_size, + tascam->capture_urbs[i]->transfer_buffer, + tascam->capture_urbs[i]->transfer_dma); + usb_free_urb(tascam->capture_urbs[i]); + tascam->capture_urbs[i] = NULL; + } + } + + kfree(tascam->capture_routing_buffer); + tascam->capture_routing_buffer = NULL; + kfree(tascam->capture_decode_dst_block); + tascam->capture_decode_dst_block = NULL; + kfree(tascam->capture_decode_raw_block); + tascam->capture_decode_raw_block = NULL; + kfree(tascam->capture_ring_buffer); + tascam->capture_ring_buffer = NULL; } int tascam_alloc_urbs(struct tascam_card *tascam) @@ -121,6 +142,52 @@ int tascam_alloc_urbs(struct tascam_card *tascam) f_urb->complete = feedback_urb_complete; } + tascam->capture_urb_alloc_size = CAPTURE_URB_SIZE; + for (i = 0; i < NUM_CAPTURE_URBS; i++) { + struct urb *c_urb = usb_alloc_urb(0, GFP_KERNEL); + + if (!c_urb) + goto error; + tascam->capture_urbs[i] = c_urb; + + c_urb->transfer_buffer = usb_alloc_coherent( + tascam->dev, tascam->capture_urb_alloc_size, GFP_KERNEL, + &c_urb->transfer_dma); + if (!c_urb->transfer_buffer) + goto error; + + usb_fill_bulk_urb(c_urb, tascam->dev, + usb_rcvbulkpipe(tascam->dev, EP_AUDIO_IN), + c_urb->transfer_buffer, + tascam->capture_urb_alloc_size, + capture_urb_complete, tascam); + c_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + } + + tascam->capture_ring_buffer = + kmalloc(CAPTURE_RING_BUFFER_SIZE, GFP_KERNEL); + if (!tascam->capture_ring_buffer) + goto error; + + tascam->capture_decode_raw_block = + kmalloc(RAW_BYTES_PER_DECODE_BLOCK, GFP_KERNEL); + if (!tascam->capture_decode_raw_block) + goto error; + + tascam->capture_decode_dst_block = + kmalloc(FRAMES_PER_DECODE_BLOCK * DECODED_CHANNELS_PER_FRAME * + DECODED_SAMPLE_SIZE, + GFP_KERNEL); + if (!tascam->capture_decode_dst_block) + goto error; + + tascam->capture_routing_buffer = + kmalloc(FRAMES_PER_DECODE_BLOCK * DECODED_CHANNELS_PER_FRAME * + DECODED_SAMPLE_SIZE, + GFP_KERNEL); + if (!tascam->capture_routing_buffer) + goto error; + return 0; error: @@ -136,6 +203,7 @@ void tascam_stop_work_handler(struct work_struct *work) usb_kill_anchored_urbs(&tascam->playback_anchor); usb_kill_anchored_urbs(&tascam->feedback_anchor); + usb_kill_anchored_urbs(&tascam->capture_anchor); atomic_set(&tascam->active_urbs, 0); } @@ -261,10 +329,12 @@ static int tascam_probe(struct usb_interface *intf, spin_lock_init(&tascam->lock); init_usb_anchor(&tascam->playback_anchor); + init_usb_anchor(&tascam->capture_anchor); init_usb_anchor(&tascam->feedback_anchor); INIT_WORK(&tascam->stop_work, tascam_stop_work_handler); INIT_WORK(&tascam->stop_pcm_work, tascam_stop_pcm_work_handler); + INIT_WORK(&tascam->capture_work, tascam_capture_work_handler); err = snd_pcm_new(card, "US144MKII PCM", 0, 1, 1, &tascam->pcm); if (err < 0) @@ -328,6 +398,7 @@ static void tascam_disconnect(struct usb_interface *intf) if (intf->cur_altsetting->desc.bInterfaceNumber == 0) { snd_card_disconnect(tascam->card); cancel_work_sync(&tascam->stop_work); + cancel_work_sync(&tascam->capture_work); cancel_work_sync(&tascam->stop_pcm_work); tascam_free_urbs(tascam); snd_card_free(tascam->card); @@ -355,8 +426,10 @@ static int tascam_suspend(struct usb_interface *intf, pm_message_t message) snd_pcm_suspend_all(tascam->pcm); cancel_work_sync(&tascam->stop_work); + cancel_work_sync(&tascam->capture_work); cancel_work_sync(&tascam->stop_pcm_work); usb_kill_anchored_urbs(&tascam->playback_anchor); + usb_kill_anchored_urbs(&tascam->capture_anchor); usb_kill_anchored_urbs(&tascam->feedback_anchor); return 0; diff --git a/sound/usb/usx2y/us144mkii.h b/sound/usb/usx2y/us144mkii.h index 53a74178e373..4bd7b31261ea 100644 --- a/sound/usb/usx2y/us144mkii.h +++ b/sound/usb/usx2y/us144mkii.h @@ -19,14 +19,17 @@ /* --- USB Endpoints (Alternate Setting 1) --- */ #define EP_PLAYBACK_FEEDBACK 0x81 #define EP_AUDIO_OUT 0x02 +#define EP_AUDIO_IN 0x86 /* --- USB Control Message Protocol --- */ #define RT_H2D_CLASS_EP (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT) +#define RT_D2H_CLASS_EP (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT) #define RT_D2H_VENDOR_DEV (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE) #define RT_H2D_VENDOR_DEV (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE) enum uac_request { UAC_SET_CUR = 0x01, + UAC_GET_CUR = 0x81, }; enum uac_control_selector { @@ -63,6 +66,9 @@ enum tascam_register { #define NUM_FEEDBACK_URBS 4 #define FEEDBACK_URB_PACKETS 1 #define FEEDBACK_PACKET_SIZE 3 +#define NUM_CAPTURE_URBS 8 +#define CAPTURE_URB_SIZE 512 +#define CAPTURE_RING_BUFFER_SIZE (CAPTURE_URB_SIZE * NUM_CAPTURE_URBS * 4) #define USB_CTRL_TIMEOUT_MS 1000 #define FEEDBACK_SYNC_LOSS_THRESHOLD 41 @@ -72,6 +78,12 @@ enum tascam_register { #define BYTES_PER_FRAME (NUM_CHANNELS * BYTES_PER_SAMPLE) #define FEEDBACK_ACCUMULATOR_SIZE 128 +/* --- Capture Decoding Defines --- */ +#define DECODED_CHANNELS_PER_FRAME 4 +#define DECODED_SAMPLE_SIZE 4 +#define FRAMES_PER_DECODE_BLOCK 8 +#define RAW_BYTES_PER_DECODE_BLOCK 512 + struct tascam_card; #include "us144mkii_pcm.h" @@ -116,10 +128,19 @@ struct us144mkii_frame_pattern_observer { * @last_period_pos: Last reported period position for playback. * * @capture_substream: Pointer to the active capture PCM substream. + * @capture_urbs: Array of URBs for capture. + * @capture_urb_alloc_size: Size of allocated buffer for each capture URB. * @capture_active: Atomic flag indicating if capture is active. * @driver_capture_pos: Current position in the ALSA capture buffer (frames). * @capture_frames_processed: Total frames processed for capture. * @last_capture_period_pos: Last reported period position for capture. + * @capture_ring_buffer: Ring buffer for raw capture data from USB. + * @capture_ring_buffer_read_ptr: Read pointer for the capture ring buffer. + * @capture_ring_buffer_write_ptr: Write pointer for the capture ring buffer. + * @capture_decode_raw_block: Buffer for a raw 512-byte capture block. + * @capture_decode_dst_block: Buffer for decoded 32-bit capture samples. + * @capture_routing_buffer: Intermediate buffer for capture routing. + * @capture_work: Work struct for deferred capture processing. * * @stop_work: Work struct for deferred stream stopping. * @stop_pcm_work: Work struct for stopping PCM due to a fatal error (e.g. @@ -140,6 +161,7 @@ struct us144mkii_frame_pattern_observer { * @fpo: Holds the state for the dynamic feedback pattern generation. * * @playback_anchor: USB anchor for playback URBs. + * @capture_anchor: USB anchor for capture URBs. * @feedback_anchor: USB anchor for feedback URBs. */ struct tascam_card { @@ -159,7 +181,10 @@ struct tascam_card { size_t playback_urb_alloc_size; struct urb *feedback_urbs[NUM_FEEDBACK_URBS]; size_t feedback_urb_alloc_size; + struct urb *capture_urbs[NUM_CAPTURE_URBS]; + size_t capture_urb_alloc_size; struct usb_anchor playback_anchor; + struct usb_anchor capture_anchor; struct usb_anchor feedback_anchor; /* --- Stream State --- */ @@ -178,6 +203,12 @@ struct tascam_card { u64 capture_frames_processed; snd_pcm_uframes_t driver_capture_pos; u64 last_capture_period_pos; + u8 *capture_ring_buffer; + size_t capture_ring_buffer_read_ptr; + size_t capture_ring_buffer_write_ptr; + u8 *capture_decode_raw_block; + s32 *capture_decode_dst_block; + s32 *capture_routing_buffer; /* --- Feedback Sync State --- */ unsigned int feedback_accumulator_pattern[FEEDBACK_ACCUMULATOR_SIZE]; @@ -191,14 +222,16 @@ struct tascam_card { /* --- Workqueues --- */ struct work_struct stop_work; struct work_struct stop_pcm_work; + struct work_struct capture_work; }; /** * tascam_free_urbs() - Free all allocated URBs and associated buffers. * @tascam: the tascam_card instance * - * This function kills, unlinks, and frees all playback and feedback URBs, - * along with their transfer buffers. + * This function kills, unlinks, and frees all playback, feedback, and + * capture URBs, along with their transfer buffers and the capture + * ring/decode buffers. */ void tascam_free_urbs(struct tascam_card *tascam); @@ -206,7 +239,8 @@ void tascam_free_urbs(struct tascam_card *tascam); * tascam_alloc_urbs() - Allocate all URBs and associated buffers. * @tascam: the tascam_card instance * - * This function allocates and initializes all URBs for playback and feedback. + * This function allocates and initializes all URBs for playback, feedback, + * and capture, as well as the necessary buffers for data processing. * * Return: 0 on success, or a negative error code on failure. */ @@ -216,8 +250,8 @@ int tascam_alloc_urbs(struct tascam_card *tascam); * tascam_stop_work_handler() - Work handler to stop all active streams. * @work: Pointer to the work_struct. * - * This function is scheduled to stop all active URBs (playback, feedback) - * and reset the active_urbs counter. + * This function is scheduled to stop all active URBs (playback, feedback, + * capture) and reset the active_urbs counter. */ void tascam_stop_work_handler(struct work_struct *work); diff --git a/sound/usb/usx2y/us144mkii_capture.c b/sound/usb/usx2y/us144mkii_capture.c index 7e1b64f9a7b8..00188ff6cd51 100644 --- a/sound/usb/usx2y/us144mkii_capture.c +++ b/sound/usb/usx2y/us144mkii_capture.c @@ -45,7 +45,7 @@ static int tascam_capture_close(struct snd_pcm_substream *substream) * tascam_capture_prepare() - Prepares the PCM capture substream for use. * @substream: The ALSA PCM substream to prepare. * - * This function initializes capture-related counters. + * This function initializes capture-related counters and ring buffer pointers. * * Return: 0 on success. */ @@ -56,6 +56,8 @@ static int tascam_capture_prepare(struct snd_pcm_substream *substream) tascam->driver_capture_pos = 0; tascam->capture_frames_processed = 0; tascam->last_capture_period_pos = 0; + tascam->capture_ring_buffer_read_ptr = 0; + tascam->capture_ring_buffer_write_ptr = 0; return 0; } @@ -106,3 +108,212 @@ const struct snd_pcm_ops tascam_capture_ops = { .trigger = tascam_pcm_trigger, .pointer = tascam_capture_pointer, }; + +/** + * decode_tascam_capture_block() - Decodes a raw 512-byte block from the device. + * @src_block: Pointer to the 512-byte raw source block. + * @dst_block: Pointer to the destination buffer for decoded audio frames. + * + * The device sends audio data in a complex, multiplexed format. This function + * demultiplexes the bits from the raw block into 8 frames of 4-channel, + * 24-bit audio (stored in 32-bit containers). + */ +static void decode_tascam_capture_block(const u8 *src_block, s32 *dst_block) +{ + int frame, bit; + + memset(dst_block, 0, + FRAMES_PER_DECODE_BLOCK * DECODED_CHANNELS_PER_FRAME * + DECODED_SAMPLE_SIZE); + + for (frame = 0; frame < FRAMES_PER_DECODE_BLOCK; ++frame) { + const u8 *p_src_frame_base = src_block + frame * 64; + s32 *p_dst_frame = dst_block + frame * 4; + + s32 ch[4] = { 0 }; + + for (bit = 0; bit < 24; ++bit) { + u8 byte1 = p_src_frame_base[bit]; + u8 byte2 = p_src_frame_base[bit + 32]; + + ch[0] = (ch[0] << 1) | (byte1 & 1); + ch[2] = (ch[2] << 1) | ((byte1 >> 1) & 1); + + ch[1] = (ch[1] << 1) | (byte2 & 1); + ch[3] = (ch[3] << 1) | ((byte2 >> 1) & 1); + } + + /* + * The result is a 24-bit sample. Shift left by 8 to align it to + * the most significant bits of a 32-bit integer (S32_LE format). + */ + p_dst_frame[0] = ch[0] << 8; + p_dst_frame[1] = ch[1] << 8; + p_dst_frame[2] = ch[2] << 8; + p_dst_frame[3] = ch[3] << 8; + } +} + +void tascam_capture_work_handler(struct work_struct *work) +{ + struct tascam_card *tascam = + container_of(work, struct tascam_card, capture_work); + struct snd_pcm_substream *substream = tascam->capture_substream; + struct snd_pcm_runtime *runtime; + u8 *raw_block = tascam->capture_decode_raw_block; + s32 *decoded_block = tascam->capture_decode_dst_block; + s32 *routed_block = tascam->capture_routing_buffer; + + if (!substream || !substream->runtime) + return; + runtime = substream->runtime; + + if (!raw_block || !decoded_block || !routed_block) { + dev_err(tascam->card->dev, + "Capture decode/routing buffers not allocated!\n"); + return; + } + + while (atomic_read(&tascam->capture_active)) { + size_t write_ptr, read_ptr, available_data; + bool can_process; + + scoped_guard(spinlock_irqsave, &tascam->lock) { + write_ptr = tascam->capture_ring_buffer_write_ptr; + read_ptr = tascam->capture_ring_buffer_read_ptr; + available_data = (write_ptr >= read_ptr) ? + (write_ptr - read_ptr) : + (CAPTURE_RING_BUFFER_SIZE - + read_ptr + write_ptr); + can_process = + (available_data >= RAW_BYTES_PER_DECODE_BLOCK); + + if (can_process) { + size_t bytes_to_end = + CAPTURE_RING_BUFFER_SIZE - read_ptr; + if (bytes_to_end >= + RAW_BYTES_PER_DECODE_BLOCK) { + memcpy(raw_block, + tascam->capture_ring_buffer + + read_ptr, + RAW_BYTES_PER_DECODE_BLOCK); + } else { + memcpy(raw_block, + tascam->capture_ring_buffer + + read_ptr, + bytes_to_end); + memcpy(raw_block + bytes_to_end, + tascam->capture_ring_buffer, + RAW_BYTES_PER_DECODE_BLOCK - + bytes_to_end); + } + tascam->capture_ring_buffer_read_ptr = + (read_ptr + + RAW_BYTES_PER_DECODE_BLOCK) % + CAPTURE_RING_BUFFER_SIZE; + } + } + + if (!can_process) + break; + + decode_tascam_capture_block(raw_block, decoded_block); + process_capture_routing_us144mkii(tascam, decoded_block, + routed_block); + + scoped_guard(spinlock_irqsave, &tascam->lock) { + if (atomic_read(&tascam->capture_active)) { + int f; + + for (f = 0; f < FRAMES_PER_DECODE_BLOCK; ++f) { + u8 *dst_frame_start = + runtime->dma_area + + frames_to_bytes( + runtime, + tascam->driver_capture_pos); + s32 *routed_frame_start = + routed_block + + (f * NUM_CHANNELS); + int c; + + for (c = 0; c < NUM_CHANNELS; c++) { + u8 *dst_channel = + dst_frame_start + + (c * BYTES_PER_SAMPLE); + s32 *src_channel_s32 = + routed_frame_start + c; + + memcpy(dst_channel, + ((char *)src_channel_s32) + + 1, + 3); + } + + tascam->driver_capture_pos = + (tascam->driver_capture_pos + + 1) % + runtime->buffer_size; + } + } + } + } +} + +void capture_urb_complete(struct urb *urb) +{ + struct tascam_card *tascam = urb->context; + int ret; + + if (urb->status) { + if (urb->status != -ENOENT && urb->status != -ECONNRESET && + urb->status != -ESHUTDOWN && urb->status != -ENODEV && + urb->status != -EPROTO) + dev_err_ratelimited(tascam->card->dev, + "Capture URB failed: %d\n", + urb->status); + goto out; + } + if (!tascam || !atomic_read(&tascam->capture_active)) + goto out; + + if (urb->actual_length > 0) { + scoped_guard(spinlock_irqsave, &tascam->lock) { + size_t write_ptr = tascam->capture_ring_buffer_write_ptr; + size_t bytes_to_end = CAPTURE_RING_BUFFER_SIZE - write_ptr; + + if (urb->actual_length > bytes_to_end) { + memcpy(tascam->capture_ring_buffer + write_ptr, + urb->transfer_buffer, bytes_to_end); + memcpy(tascam->capture_ring_buffer, + urb->transfer_buffer + bytes_to_end, + urb->actual_length - bytes_to_end); + } else { + memcpy(tascam->capture_ring_buffer + write_ptr, + urb->transfer_buffer, + urb->actual_length); + } + + tascam->capture_ring_buffer_write_ptr = + (write_ptr + urb->actual_length) % + CAPTURE_RING_BUFFER_SIZE; + } + + schedule_work(&tascam->capture_work); + } + + usb_get_urb(urb); + usb_anchor_urb(urb, &tascam->capture_anchor); + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret < 0) { + dev_err_ratelimited(tascam->card->dev, + "Failed to resubmit capture URB: %d\n", + ret); + usb_unanchor_urb(urb); + usb_put_urb(urb); + atomic_dec( + &tascam->active_urbs); /* Decrement on failed resubmission */ + } +out: + usb_put_urb(urb); +} + diff --git a/sound/usb/usx2y/us144mkii_pcm.c b/sound/usb/usx2y/us144mkii_pcm.c index 423c775051ad..f9b29ab819e0 100644 --- a/sound/usb/usx2y/us144mkii_pcm.c +++ b/sound/usb/usx2y/us144mkii_pcm.c @@ -61,6 +61,16 @@ void process_playback_routing_us144mkii(struct tascam_card *tascam, memcpy(dst_buffer, src_buffer, frames * BYTES_PER_FRAME); } +void process_capture_routing_us144mkii(struct tascam_card *tascam, + const s32 *decoded_block, + s32 *routed_block) +{ + /* This is a stub. Routing will be added in a later commit. */ + memcpy(routed_block, decoded_block, + FRAMES_PER_DECODE_BLOCK * DECODED_CHANNELS_PER_FRAME * + DECODED_SAMPLE_SIZE); +} + int us144mkii_configure_device_for_rate(struct tascam_card *tascam, int rate) { struct usb_device *dev = tascam->dev; @@ -109,6 +119,12 @@ int us144mkii_configure_device_for_rate(struct tascam_card *tascam, int rate) USB_CTRL_TIMEOUT_MS); if (err < 0) goto fail; + err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, + RT_H2D_CLASS_EP, UAC_SAMPLING_FREQ_CONTROL, + EP_AUDIO_IN, rate_payload_buf, 3, + USB_CTRL_TIMEOUT_MS); + if (err < 0) + goto fail; err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, RT_H2D_CLASS_EP, UAC_SAMPLING_FREQ_CONTROL, EP_AUDIO_OUT, rate_payload_buf, 3, @@ -270,6 +286,20 @@ int tascam_pcm_trigger(struct snd_pcm_substream *substream, int cmd) } atomic_inc(&tascam->active_urbs); } + for (i = 0; i < NUM_CAPTURE_URBS; i++) { + usb_get_urb(tascam->capture_urbs[i]); + usb_anchor_urb(tascam->capture_urbs[i], + &tascam->capture_anchor); + err = usb_submit_urb(tascam->capture_urbs[i], + GFP_ATOMIC); + if (err < 0) { + usb_unanchor_urb(tascam->capture_urbs[i]); + usb_put_urb(tascam->capture_urbs[i]); + atomic_dec(&tascam->active_urbs); + goto start_rollback; + } + atomic_inc(&tascam->active_urbs); + } return 0; start_rollback: diff --git a/sound/usb/usx2y/us144mkii_pcm.h b/sound/usb/usx2y/us144mkii_pcm.h index 6ca00c3ce53d..74da8564431b 100644 --- a/sound/usb/usx2y/us144mkii_pcm.h +++ b/sound/usb/usx2y/us144mkii_pcm.h @@ -51,6 +51,16 @@ void playback_urb_complete(struct urb *urb); */ void feedback_urb_complete(struct urb *urb); +/** + * capture_urb_complete() - Completion handler for capture bulk URBs. + * @urb: the completed URB + * + * This function runs in interrupt context. It copies the received raw data + * into an intermediate ring buffer and then schedules the workqueue to process + * it. It then resubmits the URB to receive more data. + */ +void capture_urb_complete(struct urb *urb); + /** * tascam_stop_pcm_work_handler() - Work handler to stop PCM streams. * @work: Pointer to the work_struct. @@ -64,8 +74,8 @@ void tascam_stop_pcm_work_handler(struct work_struct *work); * tascam_init_pcm() - Initializes the ALSA PCM device. * @pcm: Pointer to the ALSA PCM device to initialize. * - * This function sets up the PCM operations and preallocates pages for the - * PCM buffer. + * This function sets up the PCM operations, adds ALSA controls for routing + * and sample rate, and preallocates pages for the PCM buffer. * * Return: 0 on success, or a negative error code on failure. */ @@ -94,6 +104,16 @@ void process_playback_routing_us144mkii(struct tascam_card *tascam, const u8 *src_buffer, u8 *dst_buffer, size_t frames); +/** + * process_capture_routing_us144mkii() - Apply capture routing matrix + * @tascam: The driver instance. + * @decoded_block: Buffer containing 4 channels of S32LE decoded audio. + * @routed_block: Buffer to be filled for ALSA. + */ +void process_capture_routing_us144mkii(struct tascam_card *tascam, + const s32 *decoded_block, + s32 *routed_block); + /** * tascam_pcm_hw_params() - Configures hardware parameters for PCM streams. * @substream: The ALSA PCM substream. @@ -131,4 +151,15 @@ int tascam_pcm_hw_free(struct snd_pcm_substream *substream); */ int tascam_pcm_trigger(struct snd_pcm_substream *substream, int cmd); +/** + * tascam_capture_work_handler() - Deferred work for processing capture data. + * @work: the work_struct instance + * + * This function runs in a kernel thread context, not an IRQ context. It reads + * raw data from the capture ring buffer, decodes it, applies routing, and + * copies the final audio data into the ALSA capture ring buffer. This offloads + * the CPU-intensive decoding from the time-sensitive URB completion handlers. + */ +void tascam_capture_work_handler(struct work_struct *work); + #endif /* __US144MKII_PCM_H */ From 67afec157fe63d37f0d8f46fbe11a61364718ece Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0erif=20Rami?= Date: Thu, 14 Aug 2025 19:22:20 +0200 Subject: [PATCH 00977/11391] ALSA: usb-audio: us144mkii: Add MIDI support and mixer controls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds the remaining features to the driver: MIDI I/O and ALSA mixer controls. A raw MIDI device is created, supporting one input and one output port. The implementation handles the device-specific 9-byte packet format for both sending and receiving MIDI data, using bulk URBs and workqueues for processing. ALSA kcontrols are added to the mixer interface, allowing user-space control over the audio routing matrix (e.g., selecting analog/digital sources for capture channels, and routing playback streams to different outputs). A read-only control to display the current sample rate is also included. Finally, the stub routing functions are replaced with the full logic to apply the user-selected mixer settings to the audio streams. With this commit, the driver is feature-complete. Signed-off-by: Šerif Rami Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250814172222.9448-6-ramiserifpersia@gmail.com --- sound/usb/usx2y/us144mkii.c | 303 ++++++++++++------ sound/usb/usx2y/us144mkii.h | 127 +++++++- sound/usb/usx2y/us144mkii_controls.c | 444 +++++++++++++++++++++++++++ sound/usb/usx2y/us144mkii_midi.c | 399 ++++++++++++++++++++++++ sound/usb/usx2y/us144mkii_pcm.c | 55 +++- 5 files changed, 1218 insertions(+), 110 deletions(-) create mode 100644 sound/usb/usx2y/us144mkii_controls.c create mode 100644 sound/usb/usx2y/us144mkii_midi.c diff --git a/sound/usb/usx2y/us144mkii.c b/sound/usb/usx2y/us144mkii.c index b2cde06613d2..55d6e002a310 100644 --- a/sound/usb/usx2y/us144mkii.c +++ b/sound/usb/usx2y/us144mkii.c @@ -75,6 +75,30 @@ void tascam_free_urbs(struct tascam_card *tascam) } } + usb_kill_anchored_urbs(&tascam->midi_in_anchor); + for (i = 0; i < NUM_MIDI_IN_URBS; i++) { + if (tascam->midi_in_urbs[i]) { + usb_free_coherent( + tascam->dev, MIDI_IN_BUF_SIZE, + tascam->midi_in_urbs[i]->transfer_buffer, + tascam->midi_in_urbs[i]->transfer_dma); + usb_free_urb(tascam->midi_in_urbs[i]); + tascam->midi_in_urbs[i] = NULL; + } + } + + usb_kill_anchored_urbs(&tascam->midi_out_anchor); + for (i = 0; i < NUM_MIDI_OUT_URBS; i++) { + if (tascam->midi_out_urbs[i]) { + usb_free_coherent( + tascam->dev, MIDI_OUT_BUF_SIZE, + tascam->midi_out_urbs[i]->transfer_buffer, + tascam->midi_out_urbs[i]->transfer_dma); + usb_free_urb(tascam->midi_out_urbs[i]); + tascam->midi_out_urbs[i] = NULL; + } + } + kfree(tascam->capture_routing_buffer); tascam->capture_routing_buffer = NULL; kfree(tascam->capture_decode_dst_block); @@ -164,6 +188,44 @@ int tascam_alloc_urbs(struct tascam_card *tascam) c_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; } + /* MIDI URB and buffer allocation */ + for (i = 0; i < NUM_MIDI_IN_URBS; i++) { + struct urb *m_urb = usb_alloc_urb(0, GFP_KERNEL); + + if (!m_urb) + goto error; + tascam->midi_in_urbs[i] = m_urb; + m_urb->transfer_buffer = + usb_alloc_coherent(tascam->dev, MIDI_IN_BUF_SIZE, + GFP_KERNEL, &m_urb->transfer_dma); + if (!m_urb->transfer_buffer) + goto error; + usb_fill_bulk_urb(m_urb, tascam->dev, + usb_rcvbulkpipe(tascam->dev, EP_MIDI_IN), + m_urb->transfer_buffer, MIDI_IN_BUF_SIZE, + tascam_midi_in_urb_complete, tascam); + m_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + } + + for (i = 0; i < NUM_MIDI_OUT_URBS; i++) { + struct urb *m_urb = usb_alloc_urb(0, GFP_KERNEL); + + if (!m_urb) + goto error; + tascam->midi_out_urbs[i] = m_urb; + m_urb->transfer_buffer = + usb_alloc_coherent(tascam->dev, MIDI_OUT_BUF_SIZE, + GFP_KERNEL, &m_urb->transfer_dma); + if (!m_urb->transfer_buffer) + goto error; + usb_fill_bulk_urb(m_urb, tascam->dev, + usb_sndbulkpipe(tascam->dev, EP_MIDI_OUT), + m_urb->transfer_buffer, + 0, /* length set later */ + tascam_midi_out_urb_complete, tascam); + m_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + } + tascam->capture_ring_buffer = kmalloc(CAPTURE_RING_BUFFER_SIZE, GFP_KERNEL); if (!tascam->capture_ring_buffer) @@ -213,18 +275,114 @@ void tascam_stop_work_handler(struct work_struct *work) * @card: Pointer to the ALSA sound card instance. * * This function is called when the sound card is being freed. It releases - * the reference to the USB device. + * resources allocated for the tascam_card structure, including the MIDI + * input FIFO and decrements the USB device reference count. */ static void tascam_card_private_free(struct snd_card *card) { struct tascam_card *tascam = card->private_data; - if (tascam && tascam->dev) { - usb_put_dev(tascam->dev); - tascam->dev = NULL; + if (tascam) { + kfifo_free(&tascam->midi_in_fifo); + if (tascam->dev) { + usb_put_dev(tascam->dev); + tascam->dev = NULL; + } } } +/** + * tascam_suspend() - Handles device suspension. + * @intf: The USB interface being suspended. + * @message: Power management message. + * + * This function is called when the device is suspended. It stops all active + * streams, kills all URBs, and sends a vendor-specific deep sleep command + * to the device to ensure a stable low-power state. + * + * Return: 0 on success. + */ +static int tascam_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct tascam_card *tascam = usb_get_intfdata(intf); + + if (!tascam) + return 0; + + snd_pcm_suspend_all(tascam->pcm); + + cancel_work_sync(&tascam->stop_work); + cancel_work_sync(&tascam->capture_work); + cancel_work_sync(&tascam->midi_in_work); + cancel_work_sync(&tascam->midi_out_work); + cancel_work_sync(&tascam->stop_pcm_work); + usb_kill_anchored_urbs(&tascam->playback_anchor); + usb_kill_anchored_urbs(&tascam->capture_anchor); + usb_kill_anchored_urbs(&tascam->feedback_anchor); + usb_kill_anchored_urbs(&tascam->midi_in_anchor); + usb_kill_anchored_urbs(&tascam->midi_out_anchor); + + return 0; +} + +/** + * tascam_resume() - Handles device resumption from suspend. + * @intf: The USB interface being resumed. + * + * This function is called when the device resumes from suspend. It + * re-establishes the active USB interface settings and re-configures the sample + * rate if it was previously active. + * + * Return: 0 on success, or a negative error code on failure. + */ +static int tascam_resume(struct usb_interface *intf) +{ + struct tascam_card *tascam = usb_get_intfdata(intf); + int err; + + if (!tascam) + return 0; + + dev_info(&intf->dev, "resuming TASCAM US-144MKII\n"); + + /* + * The device requires a full re-initialization sequence upon resume. + * First, re-establish the active USB interface settings. + */ + err = usb_set_interface(tascam->dev, 0, 1); + if (err < 0) { + dev_err(&intf->dev, + "resume: failed to set alt setting on intf 0: %d\n", + err); + return err; + } + err = usb_set_interface(tascam->dev, 1, 1); + if (err < 0) { + dev_err(&intf->dev, + "resume: failed to set alt setting on intf 1: %d\n", + err); + return err; + } + + /* Re-configure the sample rate if one was previously active */ + if (tascam->current_rate > 0) + us144mkii_configure_device_for_rate(tascam, + tascam->current_rate); + + return 0; +} + +static void tascam_error_timer(struct timer_list *t) +{ + struct tascam_card *tascam = + container_of(t, struct tascam_card, error_timer); + + if (atomic_read(&tascam->midi_in_active)) + schedule_work(&tascam->midi_in_work); + if (atomic_read(&tascam->midi_out_active)) + schedule_work(&tascam->midi_out_work); +} + /** * tascam_probe() - Probes for the TASCAM US-144MKII device. * @intf: The USB interface being probed. @@ -235,8 +393,8 @@ static void tascam_card_private_free(struct snd_card *card) * - Checking for the second interface (MIDI) and associating it. * - Performing a vendor-specific handshake with the device. * - Setting alternate settings for USB interfaces. - * - Creating and registering the ALSA sound card and PCM device. - * - Allocating and initializing URBs for audio transfers. + * - Creating and registering the ALSA sound card, PCM device, and MIDI device. + * - Allocating and initializing URBs for audio and MIDI transfers. * * Return: 0 on success, or a negative error code on failure. */ @@ -328,27 +486,25 @@ static int tascam_probe(struct usb_interface *intf, tascam->capture_34_source = 1; spin_lock_init(&tascam->lock); + spin_lock_init(&tascam->midi_in_lock); + spin_lock_init(&tascam->midi_out_lock); init_usb_anchor(&tascam->playback_anchor); init_usb_anchor(&tascam->capture_anchor); init_usb_anchor(&tascam->feedback_anchor); + init_usb_anchor(&tascam->midi_in_anchor); + init_usb_anchor(&tascam->midi_out_anchor); + + timer_setup(&tascam->error_timer, tascam_error_timer, 0); INIT_WORK(&tascam->stop_work, tascam_stop_work_handler); INIT_WORK(&tascam->stop_pcm_work, tascam_stop_pcm_work_handler); INIT_WORK(&tascam->capture_work, tascam_capture_work_handler); + init_completion(&tascam->midi_out_drain_completion); - err = snd_pcm_new(card, "US144MKII PCM", 0, 1, 1, &tascam->pcm); - if (err < 0) - goto free_card; - tascam->pcm->private_data = tascam; - strscpy(tascam->pcm->name, "US144MKII PCM", sizeof(tascam->pcm->name)); - - err = tascam_init_pcm(tascam->pcm); - if (err < 0) - goto free_card; - - err = tascam_alloc_urbs(tascam); - if (err < 0) - goto free_card; + if (kfifo_alloc(&tascam->midi_in_fifo, MIDI_IN_FIFO_SIZE, GFP_KERNEL)) { + snd_card_free(card); + return -ENOMEM; + } strscpy(card->driver, DRIVER_NAME, sizeof(card->driver)); if (dev->descriptor.idProduct == USB_PID_TASCAM_US144) { @@ -365,6 +521,28 @@ static int tascam_probe(struct usb_interface *intf, card->shortname, USB_VID_TASCAM, dev->descriptor.idProduct, dev_name(&dev->dev)); + err = snd_pcm_new(card, "US144MKII PCM", 0, 1, 1, &tascam->pcm); + if (err < 0) + goto free_card; + tascam->pcm->private_data = tascam; + strscpy(tascam->pcm->name, "US144MKII PCM", sizeof(tascam->pcm->name)); + + err = tascam_init_pcm(tascam->pcm); + if (err < 0) + goto free_card; + + err = tascam_create_midi(tascam); + if (err < 0) + goto free_card; + + err = tascam_create_controls(tascam); + if (err < 0) + goto free_card; + + err = tascam_alloc_urbs(tascam); + if (err < 0) + goto free_card; + err = snd_card_register(card); if (err < 0) goto free_card; @@ -385,8 +563,8 @@ static int tascam_probe(struct usb_interface *intf, * @intf: The USB interface being disconnected. * * This function is called when the device is disconnected from the system. - * It cleans up all allocated resources by freeing the sound card, which in - * turn triggers freeing of URBs and other resources. + * It cleans up all allocated resources, including killing URBs, freeing + * the sound card, and releasing memory. */ static void tascam_disconnect(struct usb_interface *intf) { @@ -396,89 +574,26 @@ static void tascam_disconnect(struct usb_interface *intf) return; if (intf->cur_altsetting->desc.bInterfaceNumber == 0) { + /* Ensure all deferred work is complete before freeing resources */ snd_card_disconnect(tascam->card); cancel_work_sync(&tascam->stop_work); cancel_work_sync(&tascam->capture_work); + cancel_work_sync(&tascam->midi_in_work); + cancel_work_sync(&tascam->midi_out_work); cancel_work_sync(&tascam->stop_pcm_work); + + usb_kill_anchored_urbs(&tascam->playback_anchor); + usb_kill_anchored_urbs(&tascam->capture_anchor); + usb_kill_anchored_urbs(&tascam->feedback_anchor); + usb_kill_anchored_urbs(&tascam->midi_in_anchor); + usb_kill_anchored_urbs(&tascam->midi_out_anchor); + timer_delete_sync(&tascam->error_timer); tascam_free_urbs(tascam); snd_card_free(tascam->card); dev_idx--; } } -/** - * tascam_suspend() - Handles device suspension. - * @intf: The USB interface being suspended. - * @message: Power management message. - * - * This function is called when the device is suspended. It stops all active - * streams and kills all URBs. - * - * Return: 0 on success. - */ -static int tascam_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct tascam_card *tascam = usb_get_intfdata(intf); - - if (!tascam) - return 0; - - snd_pcm_suspend_all(tascam->pcm); - - cancel_work_sync(&tascam->stop_work); - cancel_work_sync(&tascam->capture_work); - cancel_work_sync(&tascam->stop_pcm_work); - usb_kill_anchored_urbs(&tascam->playback_anchor); - usb_kill_anchored_urbs(&tascam->capture_anchor); - usb_kill_anchored_urbs(&tascam->feedback_anchor); - - return 0; -} - -/** - * tascam_resume() - Handles device resumption from suspend. - * @intf: The USB interface being resumed. - * - * This function is called when the device resumes from suspend. It - * re-establishes the active USB interface settings and re-configures the sample - * rate if it was previously active. - * - * Return: 0 on success, or a negative error code on failure. - */ -static int tascam_resume(struct usb_interface *intf) -{ - struct tascam_card *tascam = usb_get_intfdata(intf); - int err; - - if (!tascam) - return 0; - - dev_info(&intf->dev, "resuming TASCAM US-144MKII\n"); - - /* Re-establish the active USB interface settings. */ - err = usb_set_interface(tascam->dev, 0, 1); - if (err < 0) { - dev_err(&intf->dev, - "resume: failed to set alt setting on intf 0: %d\n", - err); - return err; - } - err = usb_set_interface(tascam->dev, 1, 1); - if (err < 0) { - dev_err(&intf->dev, - "resume: failed to set alt setting on intf 1: %d\n", - err); - return err; - } - - /* Re-configure the sample rate if one was previously active */ - if (tascam->current_rate > 0) - us144mkii_configure_device_for_rate(tascam, - tascam->current_rate); - - return 0; -} - static const struct usb_device_id tascam_usb_ids[] = { { USB_DEVICE(USB_VID_TASCAM, USB_PID_TASCAM_US144) }, { USB_DEVICE(USB_VID_TASCAM, USB_PID_TASCAM_US144MKII) }, diff --git a/sound/usb/usx2y/us144mkii.h b/sound/usb/usx2y/us144mkii.h index 4bd7b31261ea..c740a0b5a0ea 100644 --- a/sound/usb/usx2y/us144mkii.h +++ b/sound/usb/usx2y/us144mkii.h @@ -4,12 +4,18 @@ #ifndef __US144MKII_H #define __US144MKII_H +#include +#include #include #include +#include #include #include +#include +#include #define DRIVER_NAME "us144mkii" +#define DRIVER_VERSION "1.7.6" /* --- USB Device Identification --- */ #define USB_VID_TASCAM 0x0644 @@ -19,13 +25,15 @@ /* --- USB Endpoints (Alternate Setting 1) --- */ #define EP_PLAYBACK_FEEDBACK 0x81 #define EP_AUDIO_OUT 0x02 +#define EP_MIDI_IN 0x83 +#define EP_MIDI_OUT 0x04 #define EP_AUDIO_IN 0x86 /* --- USB Control Message Protocol --- */ #define RT_H2D_CLASS_EP (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT) #define RT_D2H_CLASS_EP (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT) -#define RT_D2H_VENDOR_DEV (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE) #define RT_H2D_VENDOR_DEV (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE) +#define RT_D2H_VENDOR_DEV (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE) enum uac_request { UAC_SET_CUR = 0x01, @@ -47,6 +55,8 @@ enum tascam_mode_value { MODE_VAL_STREAM_START = 0x0030, }; +#define HANDSHAKE_SUCCESS_VAL 0x12 + enum tascam_register { REG_ADDR_UNKNOWN_0D = 0x0d04, REG_ADDR_UNKNOWN_0E = 0x0e00, @@ -69,6 +79,11 @@ enum tascam_register { #define NUM_CAPTURE_URBS 8 #define CAPTURE_URB_SIZE 512 #define CAPTURE_RING_BUFFER_SIZE (CAPTURE_URB_SIZE * NUM_CAPTURE_URBS * 4) +#define NUM_MIDI_IN_URBS 4 +#define MIDI_IN_BUF_SIZE 64 +#define MIDI_IN_FIFO_SIZE (MIDI_IN_BUF_SIZE * NUM_MIDI_IN_URBS) +#define MIDI_OUT_BUF_SIZE 64 +#define NUM_MIDI_OUT_URBS 4 #define USB_CTRL_TIMEOUT_MS 1000 #define FEEDBACK_SYNC_LOSS_THRESHOLD 41 @@ -84,10 +99,6 @@ enum tascam_register { #define FRAMES_PER_DECODE_BLOCK 8 #define RAW_BYTES_PER_DECODE_BLOCK 512 -struct tascam_card; - -#include "us144mkii_pcm.h" - /** * struct us144mkii_frame_pattern_observer - State for dynamic feedback * patterns. @@ -116,6 +127,7 @@ struct us144mkii_frame_pattern_observer { * @iface1: Pointer to USB interface 1 (MIDI). * @card: Pointer to the ALSA sound card instance. * @pcm: Pointer to the ALSA PCM device. + * @rmidi: Pointer to the ALSA rawmidi device. * * @playback_substream: Pointer to the active playback PCM substream. * @playback_urbs: Array of URBs for playback. @@ -141,14 +153,35 @@ struct us144mkii_frame_pattern_observer { * @capture_decode_dst_block: Buffer for decoded 32-bit capture samples. * @capture_routing_buffer: Intermediate buffer for capture routing. * @capture_work: Work struct for deferred capture processing. - * * @stop_work: Work struct for deferred stream stopping. * @stop_pcm_work: Work struct for stopping PCM due to a fatal error (e.g. * xrun). * + * @midi_in_substream: Pointer to the active MIDI input substream. + * @midi_out_substream: Pointer to the active MIDI output substream. + * @midi_in_urbs: Array of URBs for MIDI input. + * @midi_out_urbs: Array of URBs for MIDI output. + * @midi_in_active: Atomic flag indicating if MIDI input is active. + * @midi_out_active: Atomic flag indicating if MIDI output is active. + * @midi_in_fifo: FIFO for raw MIDI input data. + * @midi_in_work: Work struct for deferred MIDI input processing. + * @midi_out_work: Work struct for deferred MIDI output processing. + * @midi_in_lock: Spinlock for MIDI input FIFO. + * @midi_out_lock: Spinlock for MIDI output. + * @midi_out_urbs_in_flight: Bitmap of MIDI output URBs currently in flight. + * @midi_running_status: Stores the last MIDI status byte for running status. + * @error_timer: Timer for MIDI error retry logic. + * * @lock: Main spinlock for protecting shared driver state. * @active_urbs: Atomic counter for active URBs. * @current_rate: Currently configured sample rate of the device. + * @line_out_source: Source for Line Outputs (0: Playback 1-2, 1: Playback 3-4). + * @digital_out_source: Source for Digital Outputs (0: Playback 1-2, 1: Playback + * 3-4). + * @capture_12_source: Source for Capture channels 1-2 (0: Analog In, 1: Digital + * In). + * @capture_34_source: Source for Capture channels 3-4 (0: Analog In, 1: Digital + * In). * * @feedback_accumulator_pattern: Stores the calculated frames per packet for * feedback. @@ -163,6 +196,8 @@ struct us144mkii_frame_pattern_observer { * @playback_anchor: USB anchor for playback URBs. * @capture_anchor: USB anchor for capture URBs. * @feedback_anchor: USB anchor for feedback URBs. + * @midi_in_anchor: USB anchor for MIDI input URBs. + * @midi_out_anchor: USB anchor for MIDI output URBs. */ struct tascam_card { /* --- Core device pointers --- */ @@ -171,6 +206,7 @@ struct tascam_card { struct usb_interface *iface1; struct snd_card *card; struct snd_pcm *pcm; + struct snd_rawmidi *rmidi; /* --- PCM Substreams --- */ struct snd_pcm_substream *playback_substream; @@ -183,9 +219,13 @@ struct tascam_card { size_t feedback_urb_alloc_size; struct urb *capture_urbs[NUM_CAPTURE_URBS]; size_t capture_urb_alloc_size; + struct urb *midi_in_urbs[NUM_MIDI_IN_URBS]; + struct urb *midi_out_urbs[NUM_MIDI_OUT_URBS]; struct usb_anchor playback_anchor; struct usb_anchor capture_anchor; struct usb_anchor feedback_anchor; + struct usb_anchor midi_in_anchor; + struct usb_anchor midi_out_anchor; /* --- Stream State --- */ spinlock_t lock; @@ -210,6 +250,19 @@ struct tascam_card { s32 *capture_decode_dst_block; s32 *capture_routing_buffer; + /* --- MIDI State --- */ + struct snd_rawmidi_substream *midi_in_substream; + struct snd_rawmidi_substream *midi_out_substream; + atomic_t midi_in_active; + atomic_t midi_out_active; + struct kfifo midi_in_fifo; + spinlock_t midi_in_lock; + spinlock_t midi_out_lock; + unsigned long midi_out_urbs_in_flight; + u8 midi_running_status; + struct timer_list error_timer; + struct completion midi_out_drain_completion; + /* --- Feedback Sync State --- */ unsigned int feedback_accumulator_pattern[FEEDBACK_ACCUMULATOR_SIZE]; unsigned int feedback_pattern_out_idx; @@ -223,14 +276,23 @@ struct tascam_card { struct work_struct stop_work; struct work_struct stop_pcm_work; struct work_struct capture_work; + struct work_struct midi_in_work; + struct work_struct midi_out_work; + + /* --- Mixer/Routing State --- */ + unsigned int line_out_source; + unsigned int digital_out_source; + unsigned int capture_12_source; + unsigned int capture_34_source; }; +/* main.c */ /** * tascam_free_urbs() - Free all allocated URBs and associated buffers. * @tascam: the tascam_card instance * - * This function kills, unlinks, and frees all playback, feedback, and - * capture URBs, along with their transfer buffers and the capture + * This function kills, unlinks, and frees all playback, feedback, capture, + * and MIDI URBs, along with their transfer buffers and the capture * ring/decode buffers. */ void tascam_free_urbs(struct tascam_card *tascam); @@ -240,7 +302,7 @@ void tascam_free_urbs(struct tascam_card *tascam); * @tascam: the tascam_card instance * * This function allocates and initializes all URBs for playback, feedback, - * and capture, as well as the necessary buffers for data processing. + * capture, and MIDI, as well as the necessary buffers for data processing. * * Return: 0 on success, or a negative error code on failure. */ @@ -255,4 +317,51 @@ int tascam_alloc_urbs(struct tascam_card *tascam); */ void tascam_stop_work_handler(struct work_struct *work); +/* us144mkii_pcm.h */ +#include "us144mkii_pcm.h" + +/* us144mkii_midi.c */ +/** + * tascam_midi_in_urb_complete() - Completion handler for MIDI IN URBs + * @urb: The completed URB. + * + * This function runs in interrupt context. It places the raw data from the + * USB endpoint into a kfifo and schedules a work item to process it later, + * ensuring the interrupt handler remains fast. + */ +void tascam_midi_in_urb_complete(struct urb *urb); + +/** + * tascam_midi_out_urb_complete() - Completion handler for MIDI OUT bulk URB. + * @urb: The completed URB. + * + * This function runs in interrupt context. It marks the output URB as no + * longer in-flight. It then re-schedules the work handler to check for and + * send any more data waiting in the ALSA buffer. This is a safe, non-blocking + * way to continue the data transmission chain. + */ +void tascam_midi_out_urb_complete(struct urb *urb); + +/** + * tascam_create_midi() - Create and initialize the ALSA rawmidi device. + * @tascam: The driver instance. + * + * Return: 0 on success, or a negative error code on failure. + */ +int tascam_create_midi(struct tascam_card *tascam); + +/* us144mkii_controls.c */ +/** + * tascam_create_controls() - Creates and adds ALSA mixer controls for the + * device. + * @tascam: The driver instance. + * + * This function registers custom ALSA controls for managing audio routing + * (line out source, digital out source, capture 1-2 source, capture 3-4 source) + * and displaying the current sample rate. + * + * Return: 0 on success, or a negative error code on failure. + */ +int tascam_create_controls(struct tascam_card *tascam); + #endif /* __US144MKII_H */ diff --git a/sound/usb/usx2y/us144mkii_controls.c b/sound/usb/usx2y/us144mkii_controls.c new file mode 100644 index 000000000000..5d69441ef414 --- /dev/null +++ b/sound/usb/usx2y/us144mkii_controls.c @@ -0,0 +1,444 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2025 Šerif Rami + +#include "us144mkii.h" + +/** + * @brief Text descriptions for playback output source options. + * + * Used by ALSA kcontrol elements to provide user-friendly names for + * the playback routing options (e.g., "Playback 1-2", "Playback 3-4"). + */ +static const char *const playback_source_texts[] = { "Playback 1-2", + "Playback 3-4" }; + +/** + * @brief Text descriptions for capture input source options. + * + * Used by ALSA kcontrol elements to provide user-friendly names for + * the capture routing options (e.g., "Analog In", "Digital In"). + */ +static const char *const capture_source_texts[] = { "Analog In", "Digital In" }; + +/** + * tascam_playback_source_info() - ALSA control info callback for playback + * source. + * @kcontrol: The ALSA kcontrol instance. + * @uinfo: The ALSA control element info structure to fill. + * + * This function provides information about the enumerated playback source + * control, including its type, count, and available items (Playback 1-2, + * Playback 3-4). + * + * Return: 0 on success. + */ +static int tascam_playback_source_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + return snd_ctl_enum_info(uinfo, 1, 2, playback_source_texts); +} + +/** + * tascam_line_out_get() - ALSA control get callback for Line Outputs Source. + * @kcontrol: The ALSA kcontrol instance. + * @ucontrol: The ALSA control element value structure to fill. + * + * This function retrieves the current selection for the Line Outputs source + * (Playback 1-2 or Playback 3-4) from the driver's private data and populates + * the ALSA control element value. + * + * Return: 0 on success. + */ +static int tascam_line_out_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tascam_card *tascam = snd_kcontrol_chip(kcontrol); + + scoped_guard(spinlock_irqsave, &tascam->lock) { + ucontrol->value.enumerated.item[0] = tascam->line_out_source; + } + return 0; +} + +/** + * tascam_line_out_put() - ALSA control put callback for Line Outputs Source. + * @kcontrol: The ALSA kcontrol instance. + * @ucontrol: The ALSA control element value structure containing the new value. + * + * This function sets the Line Outputs source (Playback 1-2 or Playback 3-4) + * based on the user's selection from the ALSA control element. It validates + * the input and updates the driver's private data. + * + * Return: 1 if the value was changed, 0 if unchanged, or a negative error code. + */ +static int tascam_line_out_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tascam_card *tascam = snd_kcontrol_chip(kcontrol); + int changed = 0; + + if (ucontrol->value.enumerated.item[0] > 1) + return -EINVAL; + + scoped_guard(spinlock_irqsave, &tascam->lock) { + if (tascam->line_out_source != ucontrol->value.enumerated.item[0]) { + tascam->line_out_source = ucontrol->value.enumerated.item[0]; + changed = 1; + } + } + return changed; +} + +/** + * tascam_line_out_control - ALSA kcontrol definition for Line Outputs Source. + * + * This defines a new ALSA mixer control named "Line OUTPUTS Source" that allows + * the user to select between "Playback 1-2" and "Playback 3-4" for the analog + * line outputs of the device. It uses the `tascam_playback_source_info` for + * information and `tascam_line_out_get`/`tascam_line_out_put` for value + * handling. + */ +static const struct snd_kcontrol_new tascam_line_out_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Line Playback Source", + .info = tascam_playback_source_info, + .get = tascam_line_out_get, + .put = tascam_line_out_put, +}; + +/** + * tascam_digital_out_get() - ALSA control get callback for Digital Outputs + * Source. + * @kcontrol: The ALSA kcontrol instance. + * @ucontrol: The ALSA control element value structure to fill. + * + * This function retrieves the current selection for the Digital Outputs source + * (Playback 1-2 or Playback 3-4) from the driver's private data and populates + * the ALSA control element value. + * + * Return: 0 on success. + */ +static int tascam_digital_out_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tascam_card *tascam = snd_kcontrol_chip(kcontrol); + + scoped_guard(spinlock_irqsave, &tascam->lock) { + ucontrol->value.enumerated.item[0] = tascam->digital_out_source; + } + return 0; +} + +/** + * tascam_digital_out_put() - ALSA control put callback for Digital Outputs + * Source. + * @kcontrol: The ALSA kcontrol instance. + * @ucontrol: The ALSA control element value structure containing the new value. + * + * This function sets the Digital Outputs source (Playback 1-2 or Playback 3-4) + * based on the user's selection from the ALSA control element. It validates + * the input and updates the driver's private data. + * + * Return: 1 if the value was changed, 0 if unchanged, or a negative error code. + */ +static int tascam_digital_out_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tascam_card *tascam = snd_kcontrol_chip(kcontrol); + int changed = 0; + + if (ucontrol->value.enumerated.item[0] > 1) + return -EINVAL; + + scoped_guard(spinlock_irqsave, &tascam->lock) { + if (tascam->digital_out_source != ucontrol->value.enumerated.item[0]) { + tascam->digital_out_source = ucontrol->value.enumerated.item[0]; + changed = 1; + } + } + return changed; +} + +/** + * tascam_digital_out_control - ALSA kcontrol definition for Digital Outputs + * Source. + * + * This defines a new ALSA mixer control named "Digital OUTPUTS Source" that + * allows the user to select between "Playback 1-2" and "Playback 3-4" for the + * digital outputs of the device. It uses the `tascam_playback_source_info` for + * information and `tascam_digital_out_get`/`tascam_digital_out_put` for value + * handling. + */ +static const struct snd_kcontrol_new tascam_digital_out_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Digital Playback Source", + .info = tascam_playback_source_info, + .get = tascam_digital_out_get, + .put = tascam_digital_out_put, +}; + +/** + * tascam_capture_source_info() - ALSA control info callback for capture source. + * @kcontrol: The ALSA kcontrol instance. + * @uinfo: The ALSA control element info structure to fill. + * + * This function provides information about the enumerated capture source + * control, including its type, count, and available items (Analog In, Digital + * In). + * + * Return: 0 on success. + */ +static int tascam_capture_source_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + return snd_ctl_enum_info(uinfo, 1, 2, capture_source_texts); +} + +/** + * tascam_capture_12_get() - ALSA control get callback for Capture channels 1 + * and 2 Source. + * @kcontrol: The ALSA kcontrol instance. + * @ucontrol: The ALSA control element value structure to fill. + * + * This function retrieves the current selection for the Capture channels 1 and + * 2 source (Analog In or Digital In) from the driver's private data and + * populates the ALSA control element value. + * + * Return: 0 on success. + */ +static int tascam_capture_12_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tascam_card *tascam = snd_kcontrol_chip(kcontrol); + + scoped_guard(spinlock_irqsave, &tascam->lock) { + ucontrol->value.enumerated.item[0] = tascam->capture_12_source; + } + return 0; +} + +/** + * tascam_capture_12_put() - ALSA control put callback for Capture channels 1 + * and 2 Source. + * @kcontrol: The ALSA kcontrol instance. + * @ucontrol: The ALSA control element value structure containing the new value. + * + * This function sets the Capture channels 1 and 2 source (Analog In or Digital + * In) based on the user's selection from the ALSA control element. It validates + * the input and updates the driver's private data. + * + * Return: 1 if the value was changed, 0 if unchanged, or a negative error code. + */ +static int tascam_capture_12_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tascam_card *tascam = snd_kcontrol_chip(kcontrol); + int changed = 0; + + if (ucontrol->value.enumerated.item[0] > 1) + return -EINVAL; + + scoped_guard(spinlock_irqsave, &tascam->lock) { + if (tascam->capture_12_source != ucontrol->value.enumerated.item[0]) { + tascam->capture_12_source = ucontrol->value.enumerated.item[0]; + changed = 1; + } + } + return changed; +} + +/** + * tascam_capture_12_control - ALSA kcontrol definition for Capture channels 1 + * and 2 Source. + * + * This defines a new ALSA mixer control named "ch1 and ch2 Source" that allows + * the user to select between "Analog In" and "Digital In" for the first two + * capture channels of the device. It uses the `tascam_capture_source_info` for + * information and `tascam_capture_12_get`/`tascam_capture_12_put` for value + * handling. + */ +static const struct snd_kcontrol_new tascam_capture_12_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Ch1/2 Capture Source", + .info = tascam_capture_source_info, + .get = tascam_capture_12_get, + .put = tascam_capture_12_put, +}; + +/** + * tascam_capture_34_get() - ALSA control get callback for Capture channels 3 + * and 4 Source. + * @kcontrol: The ALSA kcontrol instance. + * @ucontrol: The ALSA control element value structure to fill. + * + * This function retrieves the current selection for the Capture channels 3 and + * 4 source (Analog In or Digital In) from the driver's private data and + * populates the ALSA control element value. + * + * Return: 0 on success. + */ +static int tascam_capture_34_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tascam_card *tascam = snd_kcontrol_chip(kcontrol); + + scoped_guard(spinlock_irqsave, &tascam->lock) { + ucontrol->value.enumerated.item[0] = tascam->capture_34_source; + } + return 0; +} + +/** + * tascam_capture_34_put() - ALSA control put callback for Capture channels 3 + * and 4 Source. + * @kcontrol: The ALSA kcontrol instance. + * @ucontrol: The ALSA control element value structure containing the new value. + * + * This function sets the Capture channels 3 and 4 source (Analog In or Digital + * In) based on the user's selection from the ALSA control element. It validates + * the input and updates the driver's private data. + * + * Return: 1 if the value was changed, 0 if unchanged, or a negative error code. + */ +static int tascam_capture_34_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tascam_card *tascam = snd_kcontrol_chip(kcontrol); + int changed = 0; + + if (ucontrol->value.enumerated.item[0] > 1) + return -EINVAL; + + scoped_guard(spinlock_irqsave, &tascam->lock) { + if (tascam->capture_34_source != ucontrol->value.enumerated.item[0]) { + tascam->capture_34_source = ucontrol->value.enumerated.item[0]; + changed = 1; + } + } + return changed; +} + +/** + * tascam_capture_34_control - ALSA kcontrol definition for Capture channels 3 + * and 4 Source. + * + * This defines a new ALSA mixer control named "ch3 and ch4 Source" that allows + * the user to select between "Analog In" and "Digital In" for the third and + * fourth capture channels of the device. It uses the + * `tascam_capture_source_info` for information and + * `tascam_capture_34_get`/`tascam_capture_34_put` for value handling. + */ +static const struct snd_kcontrol_new tascam_capture_34_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Ch3/4 Capture Source", + .info = tascam_capture_source_info, + .get = tascam_capture_34_get, + .put = tascam_capture_34_put, +}; + +/** + * tascam_samplerate_info() - ALSA control info callback for Sample Rate. + * @kcontrol: The ALSA kcontrol instance. + * @uinfo: The ALSA control element info structure to fill. + * + * This function provides information about the Sample Rate control, defining + * it as an integer type with a minimum value of 0 and a maximum of 96000. + * + * Return: 0 on success. + */ +static int tascam_samplerate_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 96000; + return 0; +} + +/** + * tascam_samplerate_get() - ALSA control get callback for Sample Rate. + * @kcontrol: The ALSA kcontrol instance. + * @ucontrol: The ALSA control element value structure to fill. + * + * This function retrieves the current sample rate from the device via a USB + * control message and populates the ALSA control element value. If the rate + * is already known (i.e., `current_rate` is set), it returns that value + * directly. + * + * Return: 0 on success, or a negative error code on failure. + */ +static int tascam_samplerate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tascam_card *tascam = + (struct tascam_card *)snd_kcontrol_chip(kcontrol); + u8 *buf __free(kfree) = NULL; + int err; + u32 rate = 0; + + scoped_guard(spinlock_irqsave, &tascam->lock) { + if (tascam->current_rate > 0) { + ucontrol->value.integer.value[0] = tascam->current_rate; + return 0; + } + } + + buf = kmalloc(3, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + err = usb_control_msg(tascam->dev, usb_rcvctrlpipe(tascam->dev, 0), + UAC_GET_CUR, RT_D2H_CLASS_EP, + UAC_SAMPLING_FREQ_CONTROL, EP_AUDIO_IN, buf, 3, + USB_CTRL_TIMEOUT_MS); + + if (err >= 3) + rate = buf[0] | (buf[1] << 8) | (buf[2] << 16); + + ucontrol->value.integer.value[0] = rate; + return 0; +} + +/** + * tascam_samplerate_control - ALSA kcontrol definition for Sample Rate. + * + * This defines a new ALSA mixer control named "Sample Rate" that displays + * the current sample rate of the device. It is a read-only control. + */ +static const struct snd_kcontrol_new tascam_samplerate_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Sample Rate", + .info = tascam_samplerate_info, + .get = tascam_samplerate_get, + .access = SNDRV_CTL_ELEM_ACCESS_READ, +}; + +int tascam_create_controls(struct tascam_card *tascam) +{ + int err; + + err = snd_ctl_add(tascam->card, + snd_ctl_new1(&tascam_line_out_control, tascam)); + if (err < 0) + return err; + err = snd_ctl_add(tascam->card, + snd_ctl_new1(&tascam_digital_out_control, tascam)); + if (err < 0) + return err; + err = snd_ctl_add(tascam->card, + snd_ctl_new1(&tascam_capture_12_control, tascam)); + if (err < 0) + return err; + err = snd_ctl_add(tascam->card, + snd_ctl_new1(&tascam_capture_34_control, tascam)); + if (err < 0) + return err; + + err = snd_ctl_add(tascam->card, + snd_ctl_new1(&tascam_samplerate_control, tascam)); + if (err < 0) + return err; + + return 0; +} diff --git a/sound/usb/usx2y/us144mkii_midi.c b/sound/usb/usx2y/us144mkii_midi.c new file mode 100644 index 000000000000..5759f601007f --- /dev/null +++ b/sound/usb/usx2y/us144mkii_midi.c @@ -0,0 +1,399 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2025 Šerif Rami + +#include "us144mkii.h" + +/** + * tascam_midi_in_work_handler() - Deferred work for processing MIDI input. + * @work: The work_struct instance. + * + * This function runs in a thread context. It safely reads raw USB data from + * the kfifo, processes it by stripping protocol-specific padding bytes, and + * passes the clean MIDI data to the ALSA rawmidi subsystem. + */ +static void tascam_midi_in_work_handler(struct work_struct *work) +{ + struct tascam_card *tascam = + container_of(work, struct tascam_card, midi_in_work); + u8 buf[9]; + u8 clean_buf[8]; + unsigned int count, clean_count; + + if (!tascam->midi_in_substream) + return; + + while (kfifo_out_spinlocked(&tascam->midi_in_fifo, buf, sizeof(buf), + &tascam->midi_in_lock) == sizeof(buf)) { + clean_count = 0; + for (count = 0; count < 8; ++count) { + if (buf[count] != 0xfd) + clean_buf[clean_count++] = buf[count]; + } + + if (clean_count > 0) + snd_rawmidi_receive(tascam->midi_in_substream, + clean_buf, clean_count); + } +} + +void tascam_midi_in_urb_complete(struct urb *urb) +{ + struct tascam_card *tascam = urb->context; + int ret; + + if (urb->status) { + if (urb->status != -ENOENT && urb->status != -ECONNRESET && + urb->status != -ESHUTDOWN && urb->status != -EPROTO) { + dev_err_ratelimited(tascam->card->dev, + "MIDI IN URB failed: status %d\n", + urb->status); + } + goto out; + } + + if (tascam && atomic_read(&tascam->midi_in_active) && + urb->actual_length > 0) { + kfifo_in_spinlocked(&tascam->midi_in_fifo, urb->transfer_buffer, + urb->actual_length, &tascam->midi_in_lock); + schedule_work(&tascam->midi_in_work); + } + + usb_get_urb(urb); + usb_anchor_urb(urb, &tascam->midi_in_anchor); + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret < 0) { + dev_err(tascam->card->dev, + "Failed to resubmit MIDI IN URB: error %d\n", ret); + usb_unanchor_urb(urb); + usb_put_urb(urb); + } +out: + usb_put_urb(urb); +} + +/** + * tascam_midi_in_open() - Opens the MIDI input substream. + * @substream: The ALSA rawmidi substream to open. + * + * This function stores a reference to the MIDI input substream in the + * driver's private data. + * + * Return: 0 on success. + */ +static int tascam_midi_in_open(struct snd_rawmidi_substream *substream) +{ + struct tascam_card *tascam = substream->rmidi->private_data; + + tascam->midi_in_substream = substream; + return 0; +} + +/** + * tascam_midi_in_close() - Closes the MIDI input substream. + * @substream: The ALSA rawmidi substream to close. + * + * Return: 0 on success. + */ +static int tascam_midi_in_close(struct snd_rawmidi_substream *substream) +{ + return 0; +} + +/** + * tascam_midi_in_trigger() - Triggers MIDI input stream activity. + * @substream: The ALSA rawmidi substream. + * @up: Boolean indicating whether to start (1) or stop (0) the stream. + * + * This function starts or stops the MIDI input URBs based on the 'up' + * parameter. When starting, it resets the kfifo and submits all MIDI input + * URBs. When stopping, it kills all anchored MIDI input URBs and cancels the + * associated workqueue. + */ +static void tascam_midi_in_trigger(struct snd_rawmidi_substream *substream, + int up) +{ + struct tascam_card *tascam = substream->rmidi->private_data; + int i, err; + + if (up) { + if (atomic_xchg(&tascam->midi_in_active, 1) == 0) { + scoped_guard(spinlock_irqsave, &tascam->midi_in_lock) + { + kfifo_reset(&tascam->midi_in_fifo); + } + + for (i = 0; i < NUM_MIDI_IN_URBS; i++) { + usb_get_urb(tascam->midi_in_urbs[i]); + usb_anchor_urb(tascam->midi_in_urbs[i], + &tascam->midi_in_anchor); + err = usb_submit_urb(tascam->midi_in_urbs[i], + GFP_KERNEL); + if (err < 0) { + dev_err(tascam->card->dev, + "Failed to submit MIDI IN URB %d: %d\n", + i, err); + usb_unanchor_urb( + tascam->midi_in_urbs[i]); + usb_put_urb(tascam->midi_in_urbs[i]); + } + } + } + } else { + if (atomic_xchg(&tascam->midi_in_active, 0) == 1) { + usb_kill_anchored_urbs(&tascam->midi_in_anchor); + cancel_work_sync(&tascam->midi_in_work); + } + } +} + +/** + * tascam_midi_in_ops - ALSA rawmidi operations for MIDI input. + * + * This structure defines the callback functions for MIDI input stream + * operations, including open, close, and trigger. + */ +static const struct snd_rawmidi_ops tascam_midi_in_ops = { + .open = tascam_midi_in_open, + .close = tascam_midi_in_close, + .trigger = tascam_midi_in_trigger, +}; + +void tascam_midi_out_urb_complete(struct urb *urb) +{ + struct tascam_card *tascam = urb->context; + int i, urb_index = -1; + + if (urb->status) { + if (urb->status != -ENOENT && urb->status != -ECONNRESET && + urb->status != -ESHUTDOWN) { + dev_err_ratelimited(tascam->card->dev, + "MIDI OUT URB failed: %d\n", + urb->status); + } + goto out; + } + + if (!tascam) + goto out; + + for (i = 0; i < NUM_MIDI_OUT_URBS; i++) { + if (tascam->midi_out_urbs[i] == urb) { + urb_index = i; + break; + } + } + + if (urb_index < 0) { + dev_err_ratelimited(tascam->card->dev, + "Unknown MIDI OUT URB completed!\n"); + goto out; + } + + scoped_guard(spinlock_irqsave, &tascam->midi_out_lock) + { + clear_bit(urb_index, &tascam->midi_out_urbs_in_flight); + } + + if (atomic_read(&tascam->midi_out_active)) + schedule_work(&tascam->midi_out_work); + +out: + usb_put_urb(urb); +} + +/** + * tascam_midi_out_work_handler() - Deferred work for sending MIDI data + * @work: The work_struct instance. + * + * This function handles the proprietary output protocol: take the raw MIDI + * message bytes from the application, place them at the start of a 9-byte + * buffer, pad the rest with 0xFD, and add a terminator byte (0x00). + * This function pulls as many bytes as will fit into one packet from the + * ALSA buffer and sends them. + */ +static void tascam_midi_out_work_handler(struct work_struct *work) +{ + struct tascam_card *tascam = + container_of(work, struct tascam_card, midi_out_work); + struct snd_rawmidi_substream *substream = tascam->midi_out_substream; + int i; + + if (!substream || !atomic_read(&tascam->midi_out_active)) + return; + + while (snd_rawmidi_transmit_peek(substream, (u8[]){ 0 }, 1) == 1) { + int urb_index; + struct urb *urb; + u8 *buf; + int bytes_to_send; + + scoped_guard(spinlock_irqsave, &tascam->midi_out_lock) { + urb_index = -1; + for (i = 0; i < NUM_MIDI_OUT_URBS; i++) { + if (!test_bit( + i, + &tascam->midi_out_urbs_in_flight)) { + urb_index = i; + break; + } + } + + if (urb_index < 0) + return; /* No free URBs, will be rescheduled by + * completion handler + */ + + urb = tascam->midi_out_urbs[urb_index]; + buf = urb->transfer_buffer; + bytes_to_send = snd_rawmidi_transmit(substream, buf, 8); + + if (bytes_to_send <= 0) + break; /* No more data */ + + if (bytes_to_send < 9) + memset(buf + bytes_to_send, 0xfd, + 9 - bytes_to_send); + buf[8] = 0x00; + + set_bit(urb_index, &tascam->midi_out_urbs_in_flight); + urb->transfer_buffer_length = 9; + } + + usb_get_urb(urb); + usb_anchor_urb(urb, &tascam->midi_out_anchor); + if (usb_submit_urb(urb, GFP_KERNEL) < 0) { + dev_err_ratelimited( + tascam->card->dev, + "Failed to submit MIDI OUT URB %d\n", + urb_index); + scoped_guard(spinlock_irqsave, &tascam->midi_out_lock) + { + clear_bit(urb_index, + &tascam->midi_out_urbs_in_flight); + } + usb_unanchor_urb(urb); + usb_put_urb(urb); + break; /* Stop on error */ + } + } +} + +/** + * tascam_midi_out_open() - Opens the MIDI output substream. + * @substream: The ALSA rawmidi substream to open. + * + * This function stores a reference to the MIDI output substream in the + * driver's private data and initializes the MIDI running status. + * + * Return: 0 on success. + */ +static int tascam_midi_out_open(struct snd_rawmidi_substream *substream) +{ + struct tascam_card *tascam = substream->rmidi->private_data; + + tascam->midi_out_substream = substream; + /* Initialize the running status state for the packet packer. */ + tascam->midi_running_status = 0; + return 0; +} + +/** + * tascam_midi_out_close() - Closes the MIDI output substream. + * @substream: The ALSA rawmidi substream to close. + * + * Return: 0 on success. + */ +static int tascam_midi_out_close(struct snd_rawmidi_substream *substream) +{ + return 0; +} + +/** + * tascam_midi_out_drain() - Drains the MIDI output stream. + * @substream: The ALSA rawmidi substream. + * + * This function cancels any pending MIDI output work and kills all + * anchored MIDI output URBs, ensuring all data is sent or discarded. + */ +static void tascam_midi_out_drain(struct snd_rawmidi_substream *substream) +{ + struct tascam_card *tascam = substream->rmidi->private_data; + bool in_flight = true; + + while (in_flight) { + in_flight = false; + for (int i = 0; i < NUM_MIDI_OUT_URBS; i++) { + if (test_bit(i, &tascam->midi_out_urbs_in_flight)) { + in_flight = true; + break; + } + } + if (in_flight) + schedule_timeout_uninterruptible(1); + } + + cancel_work_sync(&tascam->midi_out_work); + usb_kill_anchored_urbs(&tascam->midi_out_anchor); +} + +/** + * tascam_midi_out_trigger() - Triggers MIDI output stream activity. + * @substream: The ALSA rawmidi substream. + * @up: Boolean indicating whether to start (1) or stop (0) the stream. + * + * This function starts or stops the MIDI output workqueue based on the + * 'up' parameter. + */ +static void tascam_midi_out_trigger(struct snd_rawmidi_substream *substream, + int up) +{ + struct tascam_card *tascam = substream->rmidi->private_data; + + if (up) { + atomic_set(&tascam->midi_out_active, 1); + schedule_work(&tascam->midi_out_work); + } else { + atomic_set(&tascam->midi_out_active, 0); + } +} + +/** + * tascam_midi_out_ops - ALSA rawmidi operations for MIDI output. + * + * This structure defines the callback functions for MIDI output stream + * operations, including open, close, trigger, and drain. + */ +static const struct snd_rawmidi_ops tascam_midi_out_ops = { + .open = tascam_midi_out_open, + .close = tascam_midi_out_close, + .trigger = tascam_midi_out_trigger, + .drain = tascam_midi_out_drain, +}; + +int tascam_create_midi(struct tascam_card *tascam) +{ + int err; + + err = snd_rawmidi_new(tascam->card, "US144MKII MIDI", 0, 1, 1, + &tascam->rmidi); + if (err < 0) + return err; + + strscpy(tascam->rmidi->name, "US144MKII MIDI", + sizeof(tascam->rmidi->name)); + tascam->rmidi->private_data = tascam; + + snd_rawmidi_set_ops(tascam->rmidi, SNDRV_RAWMIDI_STREAM_INPUT, + &tascam_midi_in_ops); + snd_rawmidi_set_ops(tascam->rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, + &tascam_midi_out_ops); + + tascam->rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT | + SNDRV_RAWMIDI_INFO_OUTPUT | + SNDRV_RAWMIDI_INFO_DUPLEX; + + INIT_WORK(&tascam->midi_in_work, tascam_midi_in_work_handler); + INIT_WORK(&tascam->midi_out_work, tascam_midi_out_work_handler); + + return 0; +} diff --git a/sound/usb/usx2y/us144mkii_pcm.c b/sound/usb/usx2y/us144mkii_pcm.c index f9b29ab819e0..0c84304d4624 100644 --- a/sound/usb/usx2y/us144mkii_pcm.c +++ b/sound/usb/usx2y/us144mkii_pcm.c @@ -56,19 +56,60 @@ void process_playback_routing_us144mkii(struct tascam_card *tascam, const u8 *src_buffer, u8 *dst_buffer, size_t frames) { - /* This is a stub. Routing will be added in a later commit. */ - if (src_buffer != dst_buffer) - memcpy(dst_buffer, src_buffer, frames * BYTES_PER_FRAME); + size_t f; + const u8 *src_12, *src_34; + u8 *dst_line, *dst_digital; + + for (f = 0; f < frames; ++f) { + src_12 = src_buffer + f * BYTES_PER_FRAME; + src_34 = src_12 + (2 * BYTES_PER_SAMPLE); + dst_line = dst_buffer + f * BYTES_PER_FRAME; + dst_digital = dst_line + (2 * BYTES_PER_SAMPLE); + + /* LINE OUTPUTS (ch1/2 on device) */ + if (tascam->line_out_source == 0) /* "ch1 and ch2" */ + memcpy(dst_line, src_12, 2 * BYTES_PER_SAMPLE); + else /* "ch3 and ch4" */ + memcpy(dst_line, src_34, 2 * BYTES_PER_SAMPLE); + + /* DIGITAL OUTPUTS (ch3/4 on device) */ + if (tascam->digital_out_source == 0) /* "ch1 and ch2" */ + memcpy(dst_digital, src_12, 2 * BYTES_PER_SAMPLE); + else /* "ch3 and ch4" */ + memcpy(dst_digital, src_34, 2 * BYTES_PER_SAMPLE); + } } void process_capture_routing_us144mkii(struct tascam_card *tascam, const s32 *decoded_block, s32 *routed_block) { - /* This is a stub. Routing will be added in a later commit. */ - memcpy(routed_block, decoded_block, - FRAMES_PER_DECODE_BLOCK * DECODED_CHANNELS_PER_FRAME * - DECODED_SAMPLE_SIZE); + int f; + const s32 *src_frame; + s32 *dst_frame; + + for (f = 0; f < FRAMES_PER_DECODE_BLOCK; f++) { + src_frame = decoded_block + (f * DECODED_CHANNELS_PER_FRAME); + dst_frame = routed_block + (f * DECODED_CHANNELS_PER_FRAME); + + /* ch1 and ch2 Source */ + if (tascam->capture_12_source == 0) { /* analog inputs */ + dst_frame[0] = src_frame[0]; /* Analog L */ + dst_frame[1] = src_frame[1]; /* Analog R */ + } else { /* digital inputs */ + dst_frame[0] = src_frame[2]; /* Digital L */ + dst_frame[1] = src_frame[3]; /* Digital R */ + } + + /* ch3 and ch4 Source */ + if (tascam->capture_34_source == 0) { /* analog inputs */ + dst_frame[2] = src_frame[0]; /* Analog L (Duplicate) */ + dst_frame[3] = src_frame[1]; /* Analog R (Duplicate) */ + } else { /* digital inputs */ + dst_frame[2] = src_frame[2]; /* Digital L */ + dst_frame[3] = src_frame[3]; /* Digital R */ + } + } } int us144mkii_configure_device_for_rate(struct tascam_card *tascam, int rate) From fdd1a1ae55b15b3ed0f9d026b995fd00bef68a0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0erif=20Rami?= Date: Thu, 14 Aug 2025 19:22:21 +0200 Subject: [PATCH 00978/11391] ALSA: usb-audio: us144mkii: Add deep sleep command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a deep sleep vendor command to be sent during suspend, allowing the device to enter a lower power state. Signed-off-by: Šerif Rami Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250814172222.9448-7-ramiserifpersia@gmail.com --- sound/usb/usx2y/us144mkii.c | 7 +++++++ sound/usb/usx2y/us144mkii.h | 1 + 2 files changed, 8 insertions(+) diff --git a/sound/usb/usx2y/us144mkii.c b/sound/usb/usx2y/us144mkii.c index 55d6e002a310..da53c1908c4a 100644 --- a/sound/usb/usx2y/us144mkii.c +++ b/sound/usb/usx2y/us144mkii.c @@ -322,6 +322,13 @@ static int tascam_suspend(struct usb_interface *intf, pm_message_t message) usb_kill_anchored_urbs(&tascam->midi_in_anchor); usb_kill_anchored_urbs(&tascam->midi_out_anchor); + dev_info(&intf->dev, "sending deep sleep command\n"); + int err = usb_control_msg(tascam->dev, usb_sndctrlpipe(tascam->dev, 0), + VENDOR_REQ_DEEP_SLEEP, RT_H2D_VENDOR_DEV, + 0x0000, 0x0000, NULL, 0, USB_CTRL_TIMEOUT_MS); + if (err < 0) + dev_err(&intf->dev, "deep sleep command failed: %d\n", err); + return 0; } diff --git a/sound/usb/usx2y/us144mkii.h b/sound/usb/usx2y/us144mkii.h index c740a0b5a0ea..ecc4c2fed9e6 100644 --- a/sound/usb/usx2y/us144mkii.h +++ b/sound/usb/usx2y/us144mkii.h @@ -46,6 +46,7 @@ enum uac_control_selector { enum tascam_vendor_request { VENDOR_REQ_REGISTER_WRITE = 0x41, + VENDOR_REQ_DEEP_SLEEP = 0x44, VENDOR_REQ_MODE_CONTROL = 0x49, }; From 0ec417aa85467c6fad0563621b74868be0faf00d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0erif=20Rami?= Date: Thu, 14 Aug 2025 19:22:22 +0200 Subject: [PATCH 00979/11391] ALSA: usb-audio: Add infrastructure for TASCAM US-144MKII MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds Kconfig and Makefile entries for TASCAM US-144MKII USB audio/MIDI interface support. It includes the configuration option and links new driver files. The Kconfig entry for US-144MKII is added. The Makefile is updated to compile new driver components. The US-122L driver's device ID table is adjusted to remove the US-144MKII entry, as it will now be handled by its dedicated driver. Signed-off-by: Šerif Rami Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250814172222.9448-8-ramiserifpersia@gmail.com --- sound/usb/Kconfig | 12 ++++++++++++ sound/usb/usx2y/Makefile | 2 ++ sound/usb/usx2y/us122l.c | 6 ------ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 41c47301bc19..9b890abd96d3 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -117,6 +117,18 @@ config SND_USB_US122L To compile this driver as a module, choose M here: the module will be called snd-usb-us122l. +config SND_USB_US144MKII + tristate "Tascam US-144MKII USB driver" + depends on X86 || COMPILE_TEST + select SND_RAWMIDI + select SND_PCM + help + Say Y here to include support for Tascam US-144MKII USB Audio/MIDI + interface. + + To compile this driver as a module, choose M here: the module + will be called snd-usb-us144mkii. + config SND_USB_6FIRE tristate "TerraTec DMX 6Fire USB" select FW_LOADER diff --git a/sound/usb/usx2y/Makefile b/sound/usb/usx2y/Makefile index fc033aba03a4..9db87ae39ee9 100644 --- a/sound/usb/usx2y/Makefile +++ b/sound/usb/usx2y/Makefile @@ -1,6 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 snd-usb-usx2y-y := usbusx2y.o usX2Yhwdep.o usx2yhwdeppcm.o snd-usb-us122l-y := us122l.o +snd-usb-us144mkii-y := us144mkii.o us144mkii_pcm.o us144mkii_playback.o us144mkii_capture.o us144mkii_midi.o us144mkii_controls.o obj-$(CONFIG_SND_USB_USX2Y) += snd-usb-usx2y.o obj-$(CONFIG_SND_USB_US122L) += snd-usb-us122l.o +obj-$(CONFIG_SND_USB_US144MKII) += snd-usb-us144mkii.o \ No newline at end of file diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c index 2ace3ba46091..8dbbefe3e730 100644 --- a/sound/usb/usx2y/us122l.c +++ b/sound/usb/usx2y/us122l.c @@ -686,12 +686,6 @@ static const struct usb_device_id snd_us122l_usb_id_table[] = { .idVendor = 0x0644, .idProduct = USB_ID_US122MKII }, - { - .match_flags = USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x0644, - .idProduct = USB_ID_US144MKII, - .driver_info = US122L_FLAG_US144 - }, { /* terminator */ } }; MODULE_DEVICE_TABLE(usb, snd_us122l_usb_id_table); From 7de0eebbb4c3bb44c296f66679ad37480139dc6e Mon Sep 17 00:00:00 2001 From: Wang Liang Date: Thu, 14 Aug 2025 12:23:55 +0800 Subject: [PATCH 00980/11391] net: bridge: remove unused argument of br_multicast_query_expired() Since commit 67b746f94ff3 ("net: bridge: mcast: make sure querier port/address updates are consistent"), the argument 'querier' is unused, just get rid of it. Signed-off-by: Wang Liang Reviewed-by: Ido Schimmel Acked-by: Nikolay Aleksandrov Link: https://patch.msgid.link/20250814042355.1720755-1-wangliang74@huawei.com Signed-off-by: Jakub Kicinski --- net/bridge/br_multicast.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 1377f31b719c..4dc62d01e2d3 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -4049,8 +4049,7 @@ int br_multicast_rcv(struct net_bridge_mcast **brmctx, } static void br_multicast_query_expired(struct net_bridge_mcast *brmctx, - struct bridge_mcast_own_query *query, - struct bridge_mcast_querier *querier) + struct bridge_mcast_own_query *query) { spin_lock(&brmctx->br->multicast_lock); if (br_multicast_ctx_vlan_disabled(brmctx)) @@ -4069,8 +4068,7 @@ static void br_ip4_multicast_query_expired(struct timer_list *t) struct net_bridge_mcast *brmctx = timer_container_of(brmctx, t, ip4_own_query.timer); - br_multicast_query_expired(brmctx, &brmctx->ip4_own_query, - &brmctx->ip4_querier); + br_multicast_query_expired(brmctx, &brmctx->ip4_own_query); } #if IS_ENABLED(CONFIG_IPV6) @@ -4079,8 +4077,7 @@ static void br_ip6_multicast_query_expired(struct timer_list *t) struct net_bridge_mcast *brmctx = timer_container_of(brmctx, t, ip6_own_query.timer); - br_multicast_query_expired(brmctx, &brmctx->ip6_own_query, - &brmctx->ip6_querier); + br_multicast_query_expired(brmctx, &brmctx->ip6_own_query); } #endif From 29128da29dbabfe567c0133bf069052d2d5d588c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 13 Aug 2025 08:28:30 +0200 Subject: [PATCH 00981/11391] kunit: Always descend into kunit directory during build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For kbuild to properly clean up these build artifacts in the subdirectory, even after CONFIG_KUNIT changed do disabled, the directory needs to be processed always. Pushing the special logic for hook.o into the kunit Makefile also makes the logic easier to understand. Link: https://lore.kernel.org/r/20250813-kunit-always-descend-v1-1-7bbd387ff13b@linutronix.de Signed-off-by: Thomas Weißschuh Reviewed-by: David Gow Signed-off-by: Shuah Khan --- lib/Makefile | 4 ---- lib/kunit/Makefile | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/Makefile b/lib/Makefile index 392ff808c9b9..15a03f4c16e2 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -109,11 +109,7 @@ test_fpu-y := test_fpu_glue.o test_fpu_impl.o CFLAGS_test_fpu_impl.o += $(CC_FLAGS_FPU) CFLAGS_REMOVE_test_fpu_impl.o += $(CC_FLAGS_NO_FPU) -# Some KUnit files (hooks.o) need to be built-in even when KUnit is a module, -# so we can't just use obj-$(CONFIG_KUNIT). -ifdef CONFIG_KUNIT obj-y += kunit/ -endif ifeq ($(CONFIG_DEBUG_KOBJECT),y) CFLAGS_kobject.o += -DDEBUG diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile index 5aa51978e456..656f1fa35abc 100644 --- a/lib/kunit/Makefile +++ b/lib/kunit/Makefile @@ -17,7 +17,7 @@ kunit-objs += debugfs.o endif # KUnit 'hooks' are built-in even when KUnit is built as a module. -obj-y += hooks.o +obj-$(if $(CONFIG_KUNIT),y) += hooks.o obj-$(CONFIG_KUNIT_TEST) += kunit-test.o obj-$(CONFIG_KUNIT_TEST) += platform-test.o From bd80c4d6e4b0f3060b00d9d2337c595c6bb1c88f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 13 Aug 2025 08:32:13 +0200 Subject: [PATCH 00982/11391] kunit: tool: Parse skipped tests from kselftest.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Skipped tests reported by kselftest.h use a different format than KTAP, there is no explicit test name. Normally the test name is part of the free-form string after the SKIP keyword: ok 3 # SKIP test: some reason Extend the parser to handle those correctly. Use the free-form string as test name instead. Link: https://lore.kernel.org/r/20250813-kunit-kselftesth-skip-v1-1-57ae3de4f109@linutronix.de Signed-off-by: Thomas Weißschuh Reviewed-by: David Gow Signed-off-by: Shuah Khan --- tools/testing/kunit/kunit_parser.py | 8 +++++--- .../kunit/test_data/test_is_test_passed-kselftest.log | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/tools/testing/kunit/kunit_parser.py b/tools/testing/kunit/kunit_parser.py index c176487356e6..333cd3a4a56b 100644 --- a/tools/testing/kunit/kunit_parser.py +++ b/tools/testing/kunit/kunit_parser.py @@ -352,9 +352,9 @@ def parse_test_plan(lines: LineStream, test: Test) -> bool: lines.pop() return True -TEST_RESULT = re.compile(r'^\s*(ok|not ok) ([0-9]+) (- )?([^#]*)( # .*)?$') +TEST_RESULT = re.compile(r'^\s*(ok|not ok) ([0-9]+) ?(- )?([^#]*)( # .*)?$') -TEST_RESULT_SKIP = re.compile(r'^\s*(ok|not ok) ([0-9]+) (- )?(.*) # SKIP(.*)$') +TEST_RESULT_SKIP = re.compile(r'^\s*(ok|not ok) ([0-9]+) ?(- )?(.*) # SKIP ?(.*)$') def peek_test_name_match(lines: LineStream, test: Test) -> bool: """ @@ -379,6 +379,8 @@ def peek_test_name_match(lines: LineStream, test: Test) -> bool: if not match: return False name = match.group(4) + if not name: + return False return name == test.name def parse_test_result(lines: LineStream, test: Test, @@ -416,7 +418,7 @@ def parse_test_result(lines: LineStream, test: Test, # Set name of test object if skip_match: - test.name = skip_match.group(4) + test.name = skip_match.group(4) or skip_match.group(5) else: test.name = match.group(4) diff --git a/tools/testing/kunit/test_data/test_is_test_passed-kselftest.log b/tools/testing/kunit/test_data/test_is_test_passed-kselftest.log index 65d3f27feaf2..30d9ef18bcec 100644 --- a/tools/testing/kunit/test_data/test_is_test_passed-kselftest.log +++ b/tools/testing/kunit/test_data/test_is_test_passed-kselftest.log @@ -1,5 +1,5 @@ TAP version 13 -1..2 +1..3 # selftests: membarrier: membarrier_test_single_thread # TAP version 13 # 1..2 @@ -12,3 +12,4 @@ ok 1 selftests: membarrier: membarrier_test_single_thread # ok 1 sys_membarrier available # ok 2 sys membarrier invalid command test: command = -1, flags = 0, errno = 22. Failed as expected ok 2 selftests: membarrier: membarrier_test_multi_thread +ok 3 # SKIP selftests: membarrier: membarrier_test_multi_thread From 8d3e8057eeadab134a71d6a495d6f1b6818144fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Sun, 20 Jul 2025 12:48:37 +0300 Subject: [PATCH 00983/11391] rust: make `ArrayLayout::new_unchecked` a `const fn` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Makes `ArrayLayout::new_unchecked` a `const fn` to allow compile-time evaluation. Signed-off-by: Onur Özkan Reviewed-by: Alice Ryhl Reviewed-by: Benno Lossin Link: https://lore.kernel.org/r/20250720094838.29530-3-work@onurozkan.dev Signed-off-by: Danilo Krummrich --- rust/kernel/alloc/layout.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/kernel/alloc/layout.rs b/rust/kernel/alloc/layout.rs index 93ed514f7cc7..52cbf61c4539 100644 --- a/rust/kernel/alloc/layout.rs +++ b/rust/kernel/alloc/layout.rs @@ -80,7 +80,7 @@ pub const fn new(len: usize) -> Result { /// # Safety /// /// `len` must be a value, for which `len * size_of::() <= isize::MAX` is true. - pub unsafe fn new_unchecked(len: usize) -> Self { + pub const unsafe fn new_unchecked(len: usize) -> Self { // INVARIANT: By the safety requirements of this function // `len * size_of::() <= isize::MAX`. Self { From f87de6919dc126f22c7b5bf92e378f0346f190a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Sun, 20 Jul 2025 12:48:38 +0300 Subject: [PATCH 00984/11391] rust: make `kvec::Vec` functions `const fn` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Makes various `kvec::Vec` functions `const fn` to allow compile-time evaluation. Signed-off-by: Onur Özkan Reviewed-by: Alice Ryhl Reviewed-by: Benno Lossin Link: https://lore.kernel.org/r/20250720094838.29530-4-work@onurozkan.dev Signed-off-by: Danilo Krummrich --- rust/kernel/alloc/kvec.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs index 7316f48aaa90..d42dbdc44f0f 100644 --- a/rust/kernel/alloc/kvec.rs +++ b/rust/kernel/alloc/kvec.rs @@ -175,7 +175,7 @@ const fn is_zst() -> bool { /// Returns the number of elements that can be stored within the vector without allocating /// additional memory. - pub fn capacity(&self) -> usize { + pub const fn capacity(&self) -> usize { if const { Self::is_zst() } { usize::MAX } else { @@ -185,7 +185,7 @@ pub fn capacity(&self) -> usize { /// Returns the number of elements stored within the vector. #[inline] - pub fn len(&self) -> usize { + pub const fn len(&self) -> usize { self.len } @@ -196,7 +196,7 @@ pub fn len(&self) -> usize { /// - `additional` must be less than or equal to `self.capacity - self.len`. /// - All elements within the interval [`self.len`,`self.len + additional`) must be initialized. #[inline] - pub unsafe fn inc_len(&mut self, additional: usize) { + pub const unsafe fn inc_len(&mut self, additional: usize) { // Guaranteed by the type invariant to never underflow. debug_assert!(additional <= self.capacity() - self.len()); // INVARIANT: By the safety requirements of this method this represents the exact number of @@ -255,7 +255,7 @@ pub fn as_mut_ptr(&mut self) -> *mut T { /// Returns a raw pointer to the vector's backing buffer, or, if `T` is a ZST, a dangling raw /// pointer. #[inline] - pub fn as_ptr(&self) -> *const T { + pub const fn as_ptr(&self) -> *const T { self.ptr.as_ptr() } @@ -271,7 +271,7 @@ pub fn as_ptr(&self) -> *const T { /// assert!(!v.is_empty()); /// ``` #[inline] - pub fn is_empty(&self) -> bool { + pub const fn is_empty(&self) -> bool { self.len() == 0 } From 4005dac6573128d6e7b46c4ed43df1b23dab7765 Mon Sep 17 00:00:00 2001 From: Abhinav Ananthu Date: Tue, 12 Aug 2025 13:21:10 +0530 Subject: [PATCH 00985/11391] rust: auxiliary: Use `c_` types from prelude instead of Update auxiliary FFI callback signatures to reference the `c_` types provided by the kernel prelude, rather than accessing them via `kernel::ffi::`. Signed-off-by: Abhinav Ananthu Link: https://lore.kernel.org/r/20250812075109.4099-1-abhinav.ogl@gmail.com Signed-off-by: Danilo Krummrich --- rust/kernel/auxiliary.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs index 4749fb6bffef..f73c460665ec 100644 --- a/rust/kernel/auxiliary.rs +++ b/rust/kernel/auxiliary.rs @@ -55,7 +55,7 @@ impl Adapter { extern "C" fn probe_callback( adev: *mut bindings::auxiliary_device, id: *const bindings::auxiliary_device_id, - ) -> kernel::ffi::c_int { + ) -> c_int { // SAFETY: The auxiliary bus only ever calls the probe callback with a valid pointer to a // `struct auxiliary_device`. // From b0d73ad126957df989c26d78bd4747a270244dd0 Mon Sep 17 00:00:00 2001 From: Abhinav Ananthu Date: Tue, 12 Aug 2025 09:01:02 +0530 Subject: [PATCH 00986/11391] rust: pci: use c_* types via kernel prelude Update PCI FFI callback signatures to use `c_` from the prelude, instead of accessing it via `kernel::ffi::`. Signed-off-by: Abhinav Ananthu Reviewed-by: Benno Lossin Link: https://lore.kernel.org/r/20250812033101.5257-1-abhinav.ogl@gmail.com Signed-off-by: Danilo Krummrich --- rust/kernel/pci.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index 3bf1737635a9..71d25dbcb392 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -60,7 +60,7 @@ impl Adapter { extern "C" fn probe_callback( pdev: *mut bindings::pci_dev, id: *const bindings::pci_device_id, - ) -> kernel::ffi::c_int { + ) -> c_int { // SAFETY: The PCI bus only ever calls the probe callback with a valid pointer to a // `struct pci_dev`. // @@ -347,7 +347,7 @@ unsafe fn do_release(pdev: &Device, ioptr: usize, num: i32) { // `ioptr` is valid by the safety requirements. // `num` is valid by the safety requirements. unsafe { - bindings::pci_iounmap(pdev.as_raw(), ioptr as *mut kernel::ffi::c_void); + bindings::pci_iounmap(pdev.as_raw(), ioptr as *mut c_void); bindings::pci_release_region(pdev.as_raw(), num); } } From cd58b0b11d2160b174f82b71eb3847457aedaeca Mon Sep 17 00:00:00 2001 From: Alistair Popple Date: Wed, 30 Jul 2025 11:34:16 +1000 Subject: [PATCH 00987/11391] rust: Update PCI binding safety comments and add inline compiler hint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update the safety comments to be consistent with other safety comments in the PCI bindings. Also add an inline compiler hint. Suggested-by: Danilo Krummrich Cc: Danilo Krummrich Cc: Bjorn Helgaas Cc: Krzysztof Wilczyński Cc: Miguel Ojeda Cc: Alex Gaynor Cc: Boqun Feng Cc: Gary Guo Cc: Björn Roy Baron Cc: Benno Lossin Cc: Andreas Hindborg Cc: Alice Ryhl Cc: Trevor Gross Cc: Greg Kroah-Hartman Cc: Rafael J. Wysocki Cc: John Hubbard Cc: Alexandre Courbot Cc: linux-pci@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Alistair Popple Link: https://lore.kernel.org/r/20250730013417.640593-1-apopple@nvidia.com Signed-off-by: Danilo Krummrich --- rust/kernel/pci.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index 71d25dbcb392..5fa74d627730 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -388,14 +388,18 @@ fn as_raw(&self) -> *mut bindings::pci_dev { impl Device { /// Returns the PCI vendor ID. + #[inline] pub fn vendor_id(&self) -> u16 { - // SAFETY: `self.as_raw` is a valid pointer to a `struct pci_dev`. + // SAFETY: By its type invariant `self.as_raw` is always a valid pointer to a + // `struct pci_dev`. unsafe { (*self.as_raw()).vendor } } /// Returns the PCI device ID. + #[inline] pub fn device_id(&self) -> u16 { - // SAFETY: `self.as_raw` is a valid pointer to a `struct pci_dev`. + // SAFETY: By its type invariant `self.as_raw` is always a valid pointer to a + // `struct pci_dev`. unsafe { (*self.as_raw()).device } } From b6a37d1d4694111895248b771513153ccace606a Mon Sep 17 00:00:00 2001 From: Alistair Popple Date: Wed, 30 Jul 2025 11:34:17 +1000 Subject: [PATCH 00988/11391] rust: Add several miscellaneous PCI helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add bindings to obtain a PCI device's resource start address, bus/ device function, revision ID and subsystem device and vendor IDs. These will be used by the nova-core GPU driver which is currently in development. Reviewed-by: Alexandre Courbot Cc: Danilo Krummrich Cc: Bjorn Helgaas Cc: Krzysztof Wilczyński Cc: Miguel Ojeda Cc: Alex Gaynor Cc: Boqun Feng Cc: Gary Guo Cc: Björn Roy Baron Cc: Benno Lossin Cc: Andreas Hindborg Cc: Alice Ryhl Cc: Trevor Gross Cc: Greg Kroah-Hartman Cc: Rafael J. Wysocki Cc: John Hubbard Cc: Alexandre Courbot Cc: linux-pci@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Alistair Popple Link: https://lore.kernel.org/r/20250730013417.640593-2-apopple@nvidia.com Signed-off-by: Danilo Krummrich --- rust/helpers/pci.c | 10 ++++++++++ rust/kernel/pci.rs | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/rust/helpers/pci.c b/rust/helpers/pci.c index 5bf56004478c..fb814572b236 100644 --- a/rust/helpers/pci.c +++ b/rust/helpers/pci.c @@ -2,6 +2,16 @@ #include +u16 rust_helper_pci_dev_id(struct pci_dev *dev) +{ + return PCI_DEVID(dev->bus->number, dev->devfn); +} + +resource_size_t rust_helper_pci_resource_start(struct pci_dev *pdev, int bar) +{ + return pci_resource_start(pdev, bar); +} + resource_size_t rust_helper_pci_resource_len(struct pci_dev *pdev, int bar) { return pci_resource_len(pdev, bar); diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index 5fa74d627730..08fb69e5eb97 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -403,6 +403,50 @@ pub fn device_id(&self) -> u16 { unsafe { (*self.as_raw()).device } } + /// Returns the PCI revision ID. + #[inline] + pub fn revision_id(&self) -> u8 { + // SAFETY: By its type invariant `self.as_raw` is always a valid pointer to a + // `struct pci_dev`. + unsafe { (*self.as_raw()).revision } + } + + /// Returns the PCI bus device/function. + #[inline] + pub fn dev_id(&self) -> u16 { + // SAFETY: By its type invariant `self.as_raw` is always a valid pointer to a + // `struct pci_dev`. + unsafe { bindings::pci_dev_id(self.as_raw()) } + } + + /// Returns the PCI subsystem vendor ID. + #[inline] + pub fn subsystem_vendor_id(&self) -> u16 { + // SAFETY: By its type invariant `self.as_raw` is always a valid pointer to a + // `struct pci_dev`. + unsafe { (*self.as_raw()).subsystem_vendor } + } + + /// Returns the PCI subsystem device ID. + #[inline] + pub fn subsystem_device_id(&self) -> u16 { + // SAFETY: By its type invariant `self.as_raw` is always a valid pointer to a + // `struct pci_dev`. + unsafe { (*self.as_raw()).subsystem_device } + } + + /// Returns the start of the given PCI bar resource. + pub fn resource_start(&self, bar: u32) -> Result { + if !Bar::index_is_valid(bar) { + return Err(EINVAL); + } + + // SAFETY: + // - `bar` is a valid bar number, as guaranteed by the above call to `Bar::index_is_valid`, + // - by its type invariant `self.as_raw` is always a valid pointer to a `struct pci_dev`. + Ok(unsafe { bindings::pci_resource_start(self.as_raw(), bar.try_into()?) }) + } + /// Returns the size of the given PCI bar resource. pub fn resource_len(&self, bar: u32) -> Result { if !Bar::index_is_valid(bar) { From 1b1a946dc2b535785663742f9e4f15fd64bece60 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Mon, 11 Aug 2025 12:31:50 +0000 Subject: [PATCH 00989/11391] rust: alloc: specify the minimum alignment of each allocator The kernel's allocators sometimes provide a higher alignment than the end-user requested, so add a new constant on the Allocator trait to let the allocator specify what its minimum guaranteed alignment is. This allows the ForeignOwnable trait to provide a more accurate value of FOREIGN_ALIGN when using a pointer type such as Box, which will be useful with certain collections such as XArray that store its own data in the low bits of pointers. Reviewed-by: Benno Lossin Signed-off-by: Alice Ryhl Acked-by: Liam R. Howlett Reviewed-by: Andreas Hindborg Link: https://lore.kernel.org/r/20250811-align-min-allocator-v2-1-3386cc94f4fc@google.com [ Add helper for ARCH_KMALLOC_MINALIGN; remove cast to usize. - Danilo ] Signed-off-by: Danilo Krummrich --- rust/bindings/bindings_helper.h | 1 + rust/kernel/alloc.rs | 8 ++++++++ rust/kernel/alloc/allocator.rs | 8 ++++++++ 3 files changed, 17 insertions(+) diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 84d60635e8a9..4ad9add117ea 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -84,6 +84,7 @@ /* `bindgen` gets confused at certain things. */ const size_t RUST_CONST_HELPER_ARCH_SLAB_MINALIGN = ARCH_SLAB_MINALIGN; +const size_t RUST_CONST_HELPER_ARCH_KMALLOC_MINALIGN = ARCH_KMALLOC_MINALIGN; const size_t RUST_CONST_HELPER_PAGE_SIZE = PAGE_SIZE; const gfp_t RUST_CONST_HELPER_GFP_ATOMIC = GFP_ATOMIC; const gfp_t RUST_CONST_HELPER_GFP_KERNEL = GFP_KERNEL; diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs index a2c49e5494d3..907301334d8c 100644 --- a/rust/kernel/alloc.rs +++ b/rust/kernel/alloc.rs @@ -137,6 +137,14 @@ pub mod flags { /// - Implementers must ensure that all trait functions abide by the guarantees documented in the /// `# Guarantees` sections. pub unsafe trait Allocator { + /// The minimum alignment satisfied by all allocations from this allocator. + /// + /// # Guarantees + /// + /// Any pointer allocated by this allocator is guaranteed to be aligned to `MIN_ALIGN` even if + /// the requested layout has a smaller alignment. + const MIN_ALIGN: usize; + /// Allocate memory based on `layout` and `flags`. /// /// On success, returns a buffer represented as `NonNull<[u8]>` that satisfies the layout diff --git a/rust/kernel/alloc/allocator.rs b/rust/kernel/alloc/allocator.rs index aa2dfa9dca4c..5003907f0240 100644 --- a/rust/kernel/alloc/allocator.rs +++ b/rust/kernel/alloc/allocator.rs @@ -17,6 +17,8 @@ use crate::bindings; use crate::pr_warn; +const ARCH_KMALLOC_MINALIGN: usize = bindings::ARCH_KMALLOC_MINALIGN; + /// The contiguous kernel allocator. /// /// `Kmalloc` is typically used for physically contiguous allocations up to page size, but also @@ -128,6 +130,8 @@ unsafe fn call( // - passing a pointer to a valid memory allocation is OK, // - `realloc` satisfies the guarantees, since `ReallocFunc::call` has the same. unsafe impl Allocator for Kmalloc { + const MIN_ALIGN: usize = ARCH_KMALLOC_MINALIGN; + #[inline] unsafe fn realloc( ptr: Option>, @@ -145,6 +149,8 @@ unsafe fn realloc( // - passing a pointer to a valid memory allocation is OK, // - `realloc` satisfies the guarantees, since `ReallocFunc::call` has the same. unsafe impl Allocator for Vmalloc { + const MIN_ALIGN: usize = kernel::page::PAGE_SIZE; + #[inline] unsafe fn realloc( ptr: Option>, @@ -169,6 +175,8 @@ unsafe fn realloc( // - passing a pointer to a valid memory allocation is OK, // - `realloc` satisfies the guarantees, since `ReallocFunc::call` has the same. unsafe impl Allocator for KVmalloc { + const MIN_ALIGN: usize = ARCH_KMALLOC_MINALIGN; + #[inline] unsafe fn realloc( ptr: Option>, From bb9749f32ad38cf343e6650a34125be6aacd65d1 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Mon, 11 Aug 2025 12:31:51 +0000 Subject: [PATCH 00990/11391] rust: alloc: take the allocator into account for FOREIGN_ALIGN When converting a Box into a void pointer, the allocator might guarantee a higher alignment than the type itself does, and in that case it is guaranteed that the void pointer has that higher alignment. This is quite useful when combined with the XArray, which you can only create using a ForeignOwnable whose FOREIGN_ALIGN is at least 4. This means that you can now always use a Box with the XArray no matter the alignment of T. Reviewed-by: Benno Lossin Signed-off-by: Alice Ryhl Acked-by: Liam R. Howlett Reviewed-by: Andreas Hindborg Link: https://lore.kernel.org/r/20250811-align-min-allocator-v2-2-3386cc94f4fc@google.com Signed-off-by: Danilo Krummrich --- rust/kernel/alloc/kbox.rs | 13 +++++++++---- rust/kernel/sync/arc.rs | 6 +++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs index 856d05aa60f1..eedab0be1eff 100644 --- a/rust/kernel/alloc/kbox.rs +++ b/rust/kernel/alloc/kbox.rs @@ -401,12 +401,17 @@ fn try_init(init: impl Init, flags: Flags) -> Result } // SAFETY: The pointer returned by `into_foreign` comes from a well aligned -// pointer to `T`. +// pointer to `T` allocated by `A`. unsafe impl ForeignOwnable for Box where A: Allocator, { - const FOREIGN_ALIGN: usize = core::mem::align_of::(); + const FOREIGN_ALIGN: usize = if core::mem::align_of::() < A::MIN_ALIGN { + A::MIN_ALIGN + } else { + core::mem::align_of::() + }; + type Borrowed<'a> = &'a T; type BorrowedMut<'a> = &'a mut T; @@ -435,12 +440,12 @@ unsafe fn borrow_mut<'a>(ptr: *mut c_void) -> &'a mut T { } // SAFETY: The pointer returned by `into_foreign` comes from a well aligned -// pointer to `T`. +// pointer to `T` allocated by `A`. unsafe impl ForeignOwnable for Pin> where A: Allocator, { - const FOREIGN_ALIGN: usize = core::mem::align_of::(); + const FOREIGN_ALIGN: usize = as ForeignOwnable>::FOREIGN_ALIGN; type Borrowed<'a> = Pin<&'a T>; type BorrowedMut<'a> = Pin<&'a mut T>; diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index 63a66761d0c7..74121cf935f3 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -373,10 +373,10 @@ pub fn into_unique_or_drop(self) -> Option>> { } } -// SAFETY: The pointer returned by `into_foreign` comes from a well aligned -// pointer to `ArcInner`. +// SAFETY: The pointer returned by `into_foreign` was originally allocated as an +// `KBox>`, so that type is what determines the alignment. unsafe impl ForeignOwnable for Arc { - const FOREIGN_ALIGN: usize = core::mem::align_of::>(); + const FOREIGN_ALIGN: usize = > as ForeignOwnable>::FOREIGN_ALIGN; type Borrowed<'a> = ArcBorrow<'a, T>; type BorrowedMut<'a> = Self::Borrowed<'a>; From 2335b3f56690f76ac34b972fcaef368bab1f76f2 Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Mon, 16 Jun 2025 23:41:53 -0700 Subject: [PATCH 00991/11391] net/mlx5: mlx5_ifc, Add hardware definitions needed for adjacent vports Next patches will implement the discovery and creation of adjacent functions vports, this patch introduces the hardware structures definitions needed for the driver implementation. Signed-off-by: Saeed Mahameed Reviewed-by: Mark Bloch Reviewed-by: Parav Pandit Reviewed-by: Jack Morgenstein Signed-off-by: Alexei Lazar --- include/linux/mlx5/mlx5_ifc.h | 133 +++++++++++++++++++++++++++++++++- 1 file changed, 129 insertions(+), 4 deletions(-) diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index 8360d9011d4f..44d497272162 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -189,6 +189,9 @@ enum { MLX5_CMD_OP_QUERY_XRQ_ERROR_PARAMS = 0x727, MLX5_CMD_OP_RELEASE_XRQ_ERROR = 0x729, MLX5_CMD_OP_MODIFY_XRQ = 0x72a, + MLX5_CMD_OPCODE_QUERY_DELEGATED_VHCA = 0x732, + MLX5_CMD_OPCODE_CREATE_ESW_VPORT = 0x733, + MLX5_CMD_OPCODE_DESTROY_ESW_VPORT = 0x734, MLX5_CMD_OP_QUERY_ESW_FUNCTIONS = 0x740, MLX5_CMD_OP_QUERY_VPORT_STATE = 0x750, MLX5_CMD_OP_MODIFY_VPORT_STATE = 0x751, @@ -2207,7 +2210,19 @@ struct mlx5_ifc_cmd_hca_cap_2_bits { u8 reserved_at_440[0x8]; u8 max_num_eqs_24b[0x18]; - u8 reserved_at_460[0x3a0]; + + u8 reserved_at_460[0x160]; + + u8 query_adjacent_functions_id[0x1]; + u8 ingress_egress_esw_vport_connect[0x1]; + u8 function_id_type_vhca_id[0x1]; + u8 reserved_at_5c3[0xd]; + u8 delegate_vhca_management_profiles[0x10]; + + u8 delegated_vhca_max[0x10]; + u8 delegate_vhca_max[0x10]; + + u8 reserved_at_600[0x200]; }; enum mlx5_ifc_flow_destination_type { @@ -5159,7 +5174,9 @@ struct mlx5_ifc_set_hca_cap_in_bits { u8 other_function[0x1]; u8 ec_vf_function[0x1]; - u8 reserved_at_42[0xe]; + u8 reserved_at_42[0x1]; + u8 function_id_type[0x1]; + u8 reserved_at_44[0xc]; u8 function_id[0x10]; u8 reserved_at_60[0x20]; @@ -6357,7 +6374,9 @@ struct mlx5_ifc_query_hca_cap_in_bits { u8 other_function[0x1]; u8 ec_vf_function[0x1]; - u8 reserved_at_42[0xe]; + u8 reserved_at_42[0x1]; + u8 function_id_type[0x1]; + u8 reserved_at_44[0xc]; u8 function_id[0x10]; u8 reserved_at_60[0x20]; @@ -6983,6 +7002,28 @@ struct mlx5_ifc_query_esw_vport_context_in_bits { u8 reserved_at_60[0x20]; }; +struct mlx5_ifc_destroy_esw_vport_out_bits { + u8 status[0x8]; + u8 reserved_at_8[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_at_40[0x20]; +}; + +struct mlx5_ifc_destroy_esw_vport_in_bits { + u8 opcode[0x10]; + u8 uid[0x10]; + + u8 reserved_at_20[0x10]; + u8 op_mod[0x10]; + + u8 reserved_at_40[0x10]; + u8 vport_num[0x10]; + + u8 reserved_at_60[0x20]; +}; + struct mlx5_ifc_modify_esw_vport_context_out_bits { u8 status[0x8]; u8 reserved_at_8[0x18]; @@ -7484,6 +7525,85 @@ struct mlx5_ifc_query_adapter_in_bits { u8 reserved_at_40[0x40]; }; +struct mlx5_ifc_function_vhca_rid_info_reg_bits { + u8 host_number[0x8]; + u8 host_pci_device_function[0x8]; + u8 host_pci_bus[0x8]; + u8 reserved_at_18[0x3]; + u8 pci_bus_assigned[0x1]; + u8 function_type[0x4]; + + u8 parent_pci_device_function[0x8]; + u8 parent_pci_bus[0x8]; + u8 vhca_id[0x10]; + + u8 reserved_at_40[0x10]; + u8 function_id[0x10]; + + u8 reserved_at_60[0x20]; +}; + +struct mlx5_ifc_delegated_function_vhca_rid_info_bits { + struct mlx5_ifc_function_vhca_rid_info_reg_bits function_vhca_rid_info; + + u8 reserved_at_80[0x18]; + u8 manage_profile[0x8]; + + u8 reserved_at_a0[0x60]; +}; + +struct mlx5_ifc_query_delegated_vhca_out_bits { + u8 status[0x8]; + u8 reserved_at_8[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_at_40[0x20]; + + u8 reserved_at_60[0x10]; + u8 functions_count[0x10]; + + u8 reserved_at_80[0x80]; + + struct mlx5_ifc_delegated_function_vhca_rid_info_bits + delegated_function_vhca_rid_info[]; +}; + +struct mlx5_ifc_query_delegated_vhca_in_bits { + u8 opcode[0x10]; + u8 uid[0x10]; + + u8 reserved_at_20[0x10]; + u8 op_mod[0x10]; + + u8 reserved_at_40[0x40]; +}; + +struct mlx5_ifc_create_esw_vport_out_bits { + u8 status[0x8]; + u8 reserved_at_8[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_at_40[0x20]; + + u8 reserved_at_60[0x10]; + u8 vport_num[0x10]; +}; + +struct mlx5_ifc_create_esw_vport_in_bits { + u8 opcode[0x10]; + u8 reserved_at_10[0x10]; + + u8 reserved_at_20[0x10]; + u8 op_mod[0x10]; + + u8 reserved_at_40[0x10]; + u8 managed_vhca_id[0x10]; + + u8 reserved_at_60[0x20]; +}; + struct mlx5_ifc_qp_2rst_out_bits { u8 status[0x8]; u8 reserved_at_8[0x18]; @@ -7611,7 +7731,12 @@ struct mlx5_ifc_modify_vport_state_in_bits { u8 reserved_at_41[0xf]; u8 vport_number[0x10]; - u8 reserved_at_60[0x18]; + u8 reserved_at_60[0x10]; + u8 ingress_connect[0x1]; + u8 egress_connect[0x1]; + u8 ingress_connect_valid[0x1]; + u8 egress_connect_valid[0x1]; + u8 reserved_at_74[0x4]; u8 admin_state[0x4]; u8 reserved_at_7c[0x4]; }; From 864c05b9bc4077c99730512babc991a9d92730e0 Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Sat, 14 Jun 2025 02:29:41 -0700 Subject: [PATCH 00992/11391] net/mlx5: E-Switch, Cache vport vhca id on first cap query We need vhca_id to set up the vhca_id to vport mapping for every vport, for that we query the firmware in mlx5_esw_vport_vhca_id_set, and it is redundant since in esw_vport_setup, we already query hca caps which has the vhca_id, cache it there and save 2 extra fw queries per vport. Signed-off-by: Saeed Mahameed Reviewed-by: Mark Bloch Reviewed-by: Parav Pandit Signed-off-by: Alexei Lazar Reviewed-by: Feng Liu --- .../net/ethernet/mellanox/mlx5/core/eswitch.c | 6 ++-- .../net/ethernet/mellanox/mlx5/core/eswitch.h | 12 +++++-- .../mellanox/mlx5/core/eswitch_offloads.c | 34 +++++++++---------- 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 4917d185d0c3..eeffe9c4aa56 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -820,6 +820,7 @@ static int mlx5_esw_vport_caps_get(struct mlx5_eswitch *esw, struct mlx5_vport * hca_caps = MLX5_ADDR_OF(query_hca_cap_out, query_ctx, capability); vport->info.roce_enabled = MLX5_GET(cmd_hca_cap, hca_caps, roce); + vport->vhca_id = MLX5_GET(cmd_hca_cap, hca_caps, vhca_id); if (!MLX5_CAP_GEN_MAX(esw->dev, hca_cap_2)) goto out_free; @@ -929,7 +930,7 @@ int mlx5_esw_vport_enable(struct mlx5_eswitch *esw, struct mlx5_vport *vport, if (!mlx5_esw_is_manager_vport(esw, vport_num) && MLX5_CAP_GEN(esw->dev, vhca_resource_manager)) { - ret = mlx5_esw_vport_vhca_id_set(esw, vport_num); + ret = mlx5_esw_vport_vhca_id_map(esw, vport); if (ret) goto err_vhca_mapping; } @@ -973,7 +974,7 @@ void mlx5_esw_vport_disable(struct mlx5_eswitch *esw, struct mlx5_vport *vport) if (!mlx5_esw_is_manager_vport(esw, vport_num) && MLX5_CAP_GEN(esw->dev, vhca_resource_manager)) - mlx5_esw_vport_vhca_id_clear(esw, vport_num); + mlx5_esw_vport_vhca_id_unmap(esw, vport); if (vport->vport != MLX5_VPORT_PF && (vport->info.ipsec_crypto_enabled || vport->info.ipsec_packet_enabled)) @@ -1710,6 +1711,7 @@ static int mlx5_esw_vport_alloc(struct mlx5_eswitch *esw, vport->vport = vport_num; vport->index = index; vport->info.link_state = MLX5_VPORT_ADMIN_STATE_AUTO; + vport->vhca_id = MLX5_VHCA_ID_INVALID; INIT_WORK(&vport->vport_change_handler, esw_vport_change_handler); err = xa_insert(&esw->vports, vport_num, vport, GFP_KERNEL); if (err) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index b0b8ef3ec3c4..7f6bfaae5f5f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -197,6 +197,11 @@ static inline struct mlx5_vport *mlx5_devlink_port_vport_get(struct devlink_port return mlx5_devlink_port_get(dl_port)->vport; } +#define MLX5_VHCA_ID_INVALID (-1) + +#define MLX5_VPORT_INVAL_VHCA_ID(vport) \ + ((vport)->vhca_id == MLX5_VHCA_ID_INVALID) + struct mlx5_vport { struct mlx5_core_dev *dev; struct hlist_head uc_list[MLX5_L2_ADDR_HASH_SIZE]; @@ -209,6 +214,7 @@ struct mlx5_vport { struct vport_egress egress; u32 default_metadata; u32 metadata; + int vhca_id; struct mlx5_vport_info info; @@ -822,8 +828,10 @@ struct devlink_port *mlx5_esw_offloads_devlink_port(struct mlx5_eswitch *esw, u1 int mlx5_esw_sf_max_hpf_functions(struct mlx5_core_dev *dev, u16 *max_sfs, u16 *sf_base_id); -int mlx5_esw_vport_vhca_id_set(struct mlx5_eswitch *esw, u16 vport_num); -void mlx5_esw_vport_vhca_id_clear(struct mlx5_eswitch *esw, u16 vport_num); +int mlx5_esw_vport_vhca_id_map(struct mlx5_eswitch *esw, + struct mlx5_vport *vport); +void mlx5_esw_vport_vhca_id_unmap(struct mlx5_eswitch *esw, + struct mlx5_vport *vport); int mlx5_eswitch_vhca_id_to_vport(struct mlx5_eswitch *esw, u16 vhca_id, u16 *vport_num); /** diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index bee906661282..19decaa8a96e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -4161,23 +4161,28 @@ u32 mlx5_eswitch_get_vport_metadata_for_match(struct mlx5_eswitch *esw, } EXPORT_SYMBOL(mlx5_eswitch_get_vport_metadata_for_match); -int mlx5_esw_vport_vhca_id_set(struct mlx5_eswitch *esw, u16 vport_num) +int mlx5_esw_vport_vhca_id_map(struct mlx5_eswitch *esw, + struct mlx5_vport *vport) { u16 *old_entry, *vhca_map_entry, vhca_id; - int err; - err = mlx5_vport_get_vhca_id(esw->dev, vport_num, &vhca_id); - if (err) { - esw_warn(esw->dev, "Getting vhca_id for vport failed (vport=%u,err=%d)\n", - vport_num, err); - return err; + if (WARN_ONCE(MLX5_VPORT_INVAL_VHCA_ID(vport), + "vport %d vhca_id is not set", vport->vport)) { + int err; + + err = mlx5_vport_get_vhca_id(vport->dev, vport->vport, + &vhca_id); + if (err) + return err; + vport->vhca_id = vhca_id; } + vhca_id = vport->vhca_id; vhca_map_entry = kmalloc(sizeof(*vhca_map_entry), GFP_KERNEL); if (!vhca_map_entry) return -ENOMEM; - *vhca_map_entry = vport_num; + *vhca_map_entry = vport->vport; old_entry = xa_store(&esw->offloads.vhca_map, vhca_id, vhca_map_entry, GFP_KERNEL); if (xa_is_err(old_entry)) { kfree(vhca_map_entry); @@ -4187,17 +4192,12 @@ int mlx5_esw_vport_vhca_id_set(struct mlx5_eswitch *esw, u16 vport_num) return 0; } -void mlx5_esw_vport_vhca_id_clear(struct mlx5_eswitch *esw, u16 vport_num) +void mlx5_esw_vport_vhca_id_unmap(struct mlx5_eswitch *esw, + struct mlx5_vport *vport) { - u16 *vhca_map_entry, vhca_id; - int err; + u16 *vhca_map_entry; - err = mlx5_vport_get_vhca_id(esw->dev, vport_num, &vhca_id); - if (err) - esw_warn(esw->dev, "Getting vhca_id for vport failed (vport=%hu,err=%d)\n", - vport_num, err); - - vhca_map_entry = xa_erase(&esw->offloads.vhca_map, vhca_id); + vhca_map_entry = xa_erase(&esw->offloads.vhca_map, vport->vhca_id); kfree(vhca_map_entry); } From 1baf30426553efb3ac518b0e9d5c1c3f8ed7762a Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Mon, 16 Jun 2025 15:07:59 -0700 Subject: [PATCH 00993/11391] net/mlx5: E-Switch, Set/Query hca cap via vhca id Dynamically created vports require vhca id as input to set/query other vport hca cap, when FW is capable and the vhca id of a vport is valid use it instead of the local function id. Signed-off-by: Saeed Mahameed Signed-off-by: Adithya Jayachandran Reviewed-by: Parav Pandit Reviewed-by: Feng Liu Reviewed-by: William Tu Reviewed-by: Mark Bloch --- .../net/ethernet/mellanox/mlx5/core/eswitch.c | 12 +++++ .../net/ethernet/mellanox/mlx5/core/eswitch.h | 8 +++ .../net/ethernet/mellanox/mlx5/core/vport.c | 53 +++++++++++++++++-- 3 files changed, 68 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index eeffe9c4aa56..21c42138d93c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -840,6 +840,18 @@ static int mlx5_esw_vport_caps_get(struct mlx5_eswitch *esw, struct mlx5_vport * return err; } +bool mlx5_esw_vport_vhca_id(struct mlx5_eswitch *esw, u16 vportn, u16 *vhca_id) +{ + struct mlx5_vport *vport; + + vport = mlx5_eswitch_get_vport(esw, vportn); + if (IS_ERR(vport) || MLX5_VPORT_INVAL_VHCA_ID(vport)) + return false; + + *vhca_id = vport->vhca_id; + return true; +} + static int esw_vport_setup(struct mlx5_eswitch *esw, struct mlx5_vport *vport) { bool vst_mode_steering = esw_vst_mode_is_steering(esw); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index 7f6bfaae5f5f..f47389629c62 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -833,6 +833,7 @@ int mlx5_esw_vport_vhca_id_map(struct mlx5_eswitch *esw, void mlx5_esw_vport_vhca_id_unmap(struct mlx5_eswitch *esw, struct mlx5_vport *vport); int mlx5_eswitch_vhca_id_to_vport(struct mlx5_eswitch *esw, u16 vhca_id, u16 *vport_num); +bool mlx5_esw_vport_vhca_id(struct mlx5_eswitch *esw, u16 vportn, u16 *vhca_id); /** * struct mlx5_esw_event_info - Indicates eswitch mode changed/changing. @@ -973,6 +974,13 @@ static inline bool mlx5_eswitch_block_ipsec(struct mlx5_core_dev *dev) } static inline void mlx5_eswitch_unblock_ipsec(struct mlx5_core_dev *dev) {} + +static inline bool +mlx5_esw_vport_vhca_id(struct mlx5_eswitch *esw, u16 vportn, u16 *vhca_id) +{ + return -EOPNOTSUPP; +} + #endif /* CONFIG_MLX5_ESWITCH */ #endif /* __MLX5_ESWITCH_H__ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c index da5c24fc7b30..231bedc6a252 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c @@ -36,6 +36,7 @@ #include #include #include "mlx5_core.h" +#include "eswitch.h" #include "sf/sf.h" /* Mutex to hold while enabling or disabling RoCE */ @@ -1189,18 +1190,44 @@ u64 mlx5_query_nic_system_image_guid(struct mlx5_core_dev *mdev) } EXPORT_SYMBOL_GPL(mlx5_query_nic_system_image_guid); +static bool mlx5_vport_use_vhca_id_as_func_id(struct mlx5_core_dev *dev, + u16 vport_num, u16 *vhca_id) +{ + if (!MLX5_CAP_GEN_2(dev, function_id_type_vhca_id)) + return false; + + return mlx5_esw_vport_vhca_id(dev->priv.eswitch, vport_num, vhca_id); +} + int mlx5_vport_get_other_func_cap(struct mlx5_core_dev *dev, u16 vport, void *out, u16 opmod) { - bool ec_vf_func = mlx5_core_is_ec_vf_vport(dev, vport); u8 in[MLX5_ST_SZ_BYTES(query_hca_cap_in)] = {}; + u16 vhca_id = 0, function_id = 0; + bool ec_vf_func = false; + + /* if this vport is referring to a vport on the ec PF (embedded cpu ) + * let the FW know which domain we are querying since vport numbers or + * function_ids are not unique across the different PF domains, + * unless we use vhca_id as the function_id below. + */ + ec_vf_func = mlx5_core_is_ec_vf_vport(dev, vport); + function_id = mlx5_vport_to_func_id(dev, vport, ec_vf_func); + + if (mlx5_vport_use_vhca_id_as_func_id(dev, vport, &vhca_id)) { + MLX5_SET(query_hca_cap_in, in, function_id_type, 1); + function_id = vhca_id; + ec_vf_func = false; + mlx5_core_dbg(dev, "%s using vhca_id as function_id for vport %d vhca_id 0x%x\n", + __func__, vport, vhca_id); + } opmod = (opmod << 1) | (HCA_CAP_OPMOD_GET_MAX & 0x01); MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP); MLX5_SET(query_hca_cap_in, in, op_mod, opmod); - MLX5_SET(query_hca_cap_in, in, function_id, mlx5_vport_to_func_id(dev, vport, ec_vf_func)); MLX5_SET(query_hca_cap_in, in, other_function, true); MLX5_SET(query_hca_cap_in, in, ec_vf_function, ec_vf_func); + MLX5_SET(query_hca_cap_in, in, function_id, function_id); return mlx5_cmd_exec_inout(dev, query_hca_cap, in, out); } EXPORT_SYMBOL_GPL(mlx5_vport_get_other_func_cap); @@ -1233,8 +1260,9 @@ int mlx5_vport_get_vhca_id(struct mlx5_core_dev *dev, u16 vport, u16 *vhca_id) int mlx5_vport_set_other_func_cap(struct mlx5_core_dev *dev, const void *hca_cap, u16 vport, u16 opmod) { - bool ec_vf_func = mlx5_core_is_ec_vf_vport(dev, vport); int set_sz = MLX5_ST_SZ_BYTES(set_hca_cap_in); + u16 vhca_id = 0, function_id = 0; + bool ec_vf_func = false; void *set_hca_cap; void *set_ctx; int ret; @@ -1243,14 +1271,29 @@ int mlx5_vport_set_other_func_cap(struct mlx5_core_dev *dev, const void *hca_cap if (!set_ctx) return -ENOMEM; + /* if this vport is referring to a vport on the ec PF (embedded cpu ) + * let the FW know which domain we are querying since vport numbers or + * function_ids are not unique across the different PF domains, + * unless we use vhca_id as the function_id below. + */ + ec_vf_func = mlx5_core_is_ec_vf_vport(dev, vport); + function_id = mlx5_vport_to_func_id(dev, vport, ec_vf_func); + + if (mlx5_vport_use_vhca_id_as_func_id(dev, vport, &vhca_id)) { + MLX5_SET(set_hca_cap_in, set_ctx, function_id_type, 1); + function_id = vhca_id; + ec_vf_func = false; + mlx5_core_dbg(dev, "%s using vhca_id as function_id for vport %d vhca_id 0x%x\n", + __func__, vport, vhca_id); + } + MLX5_SET(set_hca_cap_in, set_ctx, opcode, MLX5_CMD_OP_SET_HCA_CAP); MLX5_SET(set_hca_cap_in, set_ctx, op_mod, opmod << 1); set_hca_cap = MLX5_ADDR_OF(set_hca_cap_in, set_ctx, capability); memcpy(set_hca_cap, hca_cap, MLX5_ST_SZ_BYTES(cmd_hca_cap)); - MLX5_SET(set_hca_cap_in, set_ctx, function_id, - mlx5_vport_to_func_id(dev, vport, ec_vf_func)); MLX5_SET(set_hca_cap_in, set_ctx, other_function, true); MLX5_SET(set_hca_cap_in, set_ctx, ec_vf_function, ec_vf_func); + MLX5_SET(set_hca_cap_in, set_ctx, function_id, function_id); ret = mlx5_cmd_exec_in(dev, set_hca_cap, set_ctx); kfree(set_ctx); From 40653f280b2640e5caa94eeedee43e0f1df97704 Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Mon, 16 Jun 2025 17:28:20 -0700 Subject: [PATCH 00994/11391] {rdma,net}/mlx5: export mlx5_vport_get_vhca_id vhca id is already cached in the vport structure no need to query on every mlx5 layer, use the mlx5_vport_get_vhca_id, where possible. Signed-off-by: Saeed Mahameed Reviewed-by: Mark Bloch Reviewed-by: Parav Pandit Signed-off-by: Alexei Lazar Reviewed-by: Feng Liu Reviewed-by: Tariq Toukan --- drivers/infiniband/hw/mlx5/std_types.c | 27 +++---------------- .../mellanox/mlx5/core/diag/reporter_vnic.c | 2 ++ .../ethernet/mellanox/mlx5/core/mlx5_core.h | 2 -- .../mellanox/mlx5/core/steering/hws/cmd.c | 16 +++++++---- .../mellanox/mlx5/core/steering/sws/dr_cmd.c | 16 ++++++++--- .../net/ethernet/mellanox/mlx5/core/vport.c | 5 +++- include/linux/mlx5/vport.h | 2 ++ 7 files changed, 35 insertions(+), 35 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/std_types.c b/drivers/infiniband/hw/mlx5/std_types.c index bdb568411091..2fcf553044e1 100644 --- a/drivers/infiniband/hw/mlx5/std_types.c +++ b/drivers/infiniband/hw/mlx5/std_types.c @@ -83,33 +83,14 @@ static int fill_vport_icm_addr(struct mlx5_core_dev *mdev, u16 vport, static int fill_vport_vhca_id(struct mlx5_core_dev *mdev, u16 vport, struct mlx5_ib_uapi_query_port *info) { - size_t out_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out); - u32 in[MLX5_ST_SZ_DW(query_hca_cap_in)] = {}; - void *out; - int err; + int err = mlx5_vport_get_vhca_id(mdev, vport, &info->vport_vhca_id); - out = kzalloc(out_sz, GFP_KERNEL); - if (!out) - return -ENOMEM; - - MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP); - MLX5_SET(query_hca_cap_in, in, other_function, true); - MLX5_SET(query_hca_cap_in, in, function_id, vport); - MLX5_SET(query_hca_cap_in, in, op_mod, - MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE | - HCA_CAP_OPMOD_GET_CUR); - - err = mlx5_cmd_exec(mdev, in, sizeof(in), out, out_sz); if (err) - goto out; - - info->vport_vhca_id = MLX5_GET(query_hca_cap_out, out, - capability.cmd_hca_cap.vhca_id); + return err; info->flags |= MLX5_IB_UAPI_QUERY_PORT_VPORT_VHCA_ID; -out: - kfree(out); - return err; + + return 0; } static int fill_multiport_info(struct mlx5_ib_dev *dev, u32 port_num, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/reporter_vnic.c b/drivers/net/ethernet/mellanox/mlx5/core/diag/reporter_vnic.c index 86253a89c24c..32bb769f1829 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/diag/reporter_vnic.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/reporter_vnic.c @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB /* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. */ +#include + #include "reporter_vnic.h" #include "en_stats.h" #include "devlink.h" diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index b6d53db27cd5..81857c6f6bf7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -447,8 +447,6 @@ int mlx5_vport_set_other_func_cap(struct mlx5_core_dev *dev, const void *hca_cap #define mlx5_vport_get_other_func_general_cap(dev, vport, out) \ mlx5_vport_get_other_func_cap(dev, vport, out, MLX5_CAP_GENERAL) -int mlx5_vport_get_vhca_id(struct mlx5_core_dev *dev, u16 vport, u16 *vhca_id); - static inline u32 mlx5_sriov_get_vf_total_msix(struct pci_dev *pdev) { struct mlx5_core_dev *dev = pci_get_drvdata(pdev); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/cmd.c index 9c83753e4592..d447574d86fe 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/cmd.c @@ -1199,22 +1199,28 @@ int mlx5hws_cmd_query_caps(struct mlx5_core_dev *mdev, int mlx5hws_cmd_query_gvmi(struct mlx5_core_dev *mdev, bool other_function, u16 vport_number, u16 *gvmi) { - bool ec_vf_func = other_function ? mlx5_core_is_ec_vf_vport(mdev, vport_number) : false; u32 in[MLX5_ST_SZ_DW(query_hca_cap_in)] = {}; int out_size; void *out; int err; + if (other_function) { + err = mlx5_vport_get_vhca_id(mdev, vport_number, gvmi); + if (!err) + return 0; + + mlx5_core_err(mdev, "Failed to get vport vhca id for vport %d\n", + vport_number); + return err; + } + + /* get vhca_id for `this` function */ out_size = MLX5_ST_SZ_BYTES(query_hca_cap_out); out = kzalloc(out_size, GFP_KERNEL); if (!out) return -ENOMEM; MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP); - MLX5_SET(query_hca_cap_in, in, other_function, other_function); - MLX5_SET(query_hca_cap_in, in, function_id, - mlx5_vport_to_func_id(mdev, vport_number, ec_vf_func)); - MLX5_SET(query_hca_cap_in, in, ec_vf_function, ec_vf_func); MLX5_SET(query_hca_cap_in, in, op_mod, MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE << 1 | HCA_CAP_OPMOD_GET_CUR); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_cmd.c index baefb9a3fa05..bf99b933fd14 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_cmd.c @@ -2,6 +2,7 @@ /* Copyright (c) 2019 Mellanox Technologies. */ #include "dr_types.h" +#include "eswitch.h" int mlx5dr_cmd_query_esw_vport_context(struct mlx5_core_dev *mdev, bool other_vport, @@ -34,21 +35,28 @@ int mlx5dr_cmd_query_esw_vport_context(struct mlx5_core_dev *mdev, int mlx5dr_cmd_query_gvmi(struct mlx5_core_dev *mdev, bool other_vport, u16 vport_number, u16 *gvmi) { - bool ec_vf_func = other_vport ? mlx5_core_is_ec_vf_vport(mdev, vport_number) : false; u32 in[MLX5_ST_SZ_DW(query_hca_cap_in)] = {}; int out_size; void *out; int err; + if (other_vport) { + err = mlx5_vport_get_vhca_id(mdev, vport_number, gvmi); + if (!err) + return 0; + + mlx5_core_err(mdev, "Failed to get vport vhca id for vport %d\n", + vport_number); + return err; + } + + /* get vhca_id for `this` function */ out_size = MLX5_ST_SZ_BYTES(query_hca_cap_out); out = kzalloc(out_size, GFP_KERNEL); if (!out) return -ENOMEM; MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP); - MLX5_SET(query_hca_cap_in, in, other_function, other_vport); - MLX5_SET(query_hca_cap_in, in, function_id, mlx5_vport_to_func_id(mdev, vport_number, ec_vf_func)); - MLX5_SET(query_hca_cap_in, in, ec_vf_function, ec_vf_func); MLX5_SET(query_hca_cap_in, in, op_mod, MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE << 1 | HCA_CAP_OPMOD_GET_CUR); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c index 231bedc6a252..2ed2e530b07d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c @@ -1239,7 +1239,9 @@ int mlx5_vport_get_vhca_id(struct mlx5_core_dev *dev, u16 vport, u16 *vhca_id) void *hca_caps; int err; - *vhca_id = 0; + /* try get vhca_id via eswitch */ + if (mlx5_esw_vport_vhca_id(dev->priv.eswitch, vport, vhca_id)) + return 0; query_ctx = kzalloc(query_out_sz, GFP_KERNEL); if (!query_ctx) @@ -1256,6 +1258,7 @@ int mlx5_vport_get_vhca_id(struct mlx5_core_dev *dev, u16 vport, u16 *vhca_id) kfree(query_ctx); return err; } +EXPORT_SYMBOL_GPL(mlx5_vport_get_vhca_id); int mlx5_vport_set_other_func_cap(struct mlx5_core_dev *dev, const void *hca_cap, u16 vport, u16 opmod) diff --git a/include/linux/mlx5/vport.h b/include/linux/mlx5/vport.h index c36cc6d82926..c87b9507cfa1 100644 --- a/include/linux/mlx5/vport.h +++ b/include/linux/mlx5/vport.h @@ -135,4 +135,6 @@ int mlx5_nic_vport_unaffiliate_multiport(struct mlx5_core_dev *port_mdev); u64 mlx5_query_nic_system_image_guid(struct mlx5_core_dev *mdev); int mlx5_vport_get_other_func_cap(struct mlx5_core_dev *dev, u16 vport, void *out, u16 opmod); +int mlx5_vport_get_vhca_id(struct mlx5_core_dev *dev, u16 vport, u16 *vhca_id); + #endif /* __MLX5_VPORT_H__ */ From d0f110773d776f919f93ba2e7dc254f80a7297b2 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 13 Aug 2025 21:18:03 +0200 Subject: [PATCH 00995/11391] net: phy: fixed: remove usage of a faux device A struct mii_bus doesn't need a parent, so we can simplify the code and remove using a faux device. Only difference is the following in sysfs under /sys/class/mdio_bus: old: fixed-0 -> '../../devices/faux/Fixed MDIO bus/mdio_bus/fixed-0' new: fixed-0 -> ../../devices/virtual/mdio_bus/fixed-0 Signed-off-by: Heiner Kallweit Link: https://patch.msgid.link/e9426bb9-f228-4b99-bc09-a80a958b5a93@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/fixed_phy.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/net/phy/fixed_phy.c b/drivers/net/phy/fixed_phy.c index 033656d574b8..8ad49dc1105d 100644 --- a/drivers/net/phy/fixed_phy.c +++ b/drivers/net/phy/fixed_phy.c @@ -10,7 +10,6 @@ #include #include -#include #include #include #include @@ -40,7 +39,6 @@ struct fixed_phy { struct gpio_desc *link_gpiod; }; -static struct faux_device *fdev; static struct fixed_mdio_bus platform_fmb = { .phys = LIST_HEAD_INIT(platform_fmb.phys), }; @@ -317,20 +315,13 @@ static int __init fixed_mdio_bus_init(void) struct fixed_mdio_bus *fmb = &platform_fmb; int ret; - fdev = faux_device_create("Fixed MDIO bus", NULL, NULL); - if (!fdev) - return -ENODEV; - fmb->mii_bus = mdiobus_alloc(); - if (fmb->mii_bus == NULL) { - ret = -ENOMEM; - goto err_mdiobus_reg; - } + if (!fmb->mii_bus) + return -ENOMEM; snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, "fixed-0"); fmb->mii_bus->name = "Fixed MDIO Bus"; fmb->mii_bus->priv = fmb; - fmb->mii_bus->parent = &fdev->dev; fmb->mii_bus->read = &fixed_mdio_read; fmb->mii_bus->write = &fixed_mdio_write; fmb->mii_bus->phy_mask = ~0; @@ -343,8 +334,6 @@ static int __init fixed_mdio_bus_init(void) err_mdiobus_alloc: mdiobus_free(fmb->mii_bus); -err_mdiobus_reg: - faux_device_destroy(fdev); return ret; } module_init(fixed_mdio_bus_init); @@ -356,7 +345,6 @@ static void __exit fixed_mdio_bus_exit(void) mdiobus_unregister(fmb->mii_bus); mdiobus_free(fmb->mii_bus); - faux_device_destroy(fdev); list_for_each_entry_safe(fp, tmp, &fmb->phys, node) { list_del(&fp->node); From 9e84de72aef9bcf0e751a0bff3ac91b0cf52366f Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Wed, 13 Aug 2025 22:19:55 +0300 Subject: [PATCH 00996/11391] net/mlx5: Query to see if host PF is disabled The host PF can be disabled, query firmware to check if the host PF of this function exists. Signed-off-by: Daniel Jurgens Reviewed-by: William Tu Signed-off-by: Tariq Toukan Link: https://patch.msgid.link/1755112796-467444-2-git-send-email-tariqt@nvidia.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/mellanox/mlx5/core/eswitch.c | 23 +++++++++++++++++++ .../net/ethernet/mellanox/mlx5/core/eswitch.h | 1 + 2 files changed, 24 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 4917d185d0c3..31059fff30ec 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1038,6 +1038,25 @@ const u32 *mlx5_esw_query_functions(struct mlx5_core_dev *dev) return ERR_PTR(err); } +static int mlx5_esw_host_functions_enabled_query(struct mlx5_eswitch *esw) +{ + const u32 *query_host_out; + + if (!mlx5_core_is_ecpf_esw_manager(esw->dev)) + return 0; + + query_host_out = mlx5_esw_query_functions(esw->dev); + if (IS_ERR(query_host_out)) + return PTR_ERR(query_host_out); + + esw->esw_funcs.host_funcs_disabled = + MLX5_GET(query_esw_functions_out, query_host_out, + host_params_context.host_pf_not_exist); + + kvfree(query_host_out); + return 0; +} + static void mlx5_eswitch_event_handler_register(struct mlx5_eswitch *esw) { if (esw->mode == MLX5_ESWITCH_OFFLOADS && mlx5_eswitch_is_funcs_handler(esw->dev)) { @@ -1874,6 +1893,10 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev) goto abort; } + err = mlx5_esw_host_functions_enabled_query(esw); + if (err) + goto abort; + err = mlx5_esw_vports_init(esw); if (err) goto abort; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index b0b8ef3ec3c4..6d86db20f468 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -323,6 +323,7 @@ struct mlx5_host_work { struct mlx5_esw_functions { struct mlx5_nb nb; + bool host_funcs_disabled; u16 num_vfs; u16 num_ec_vfs; }; From 520369ef43a8504f9d54ee219bb6c692d2e40028 Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Wed, 13 Aug 2025 22:19:56 +0300 Subject: [PATCH 00997/11391] net/mlx5: Support disabling host PFs Some devices support disabling the physical function on the host. When this is configured the vports for the host functions do not exist. This patch checks if host functions are enabled before trying to access their vports. Signed-off-by: Daniel Jurgens Reviewed-by: William Tu Signed-off-by: Tariq Toukan Link: https://patch.msgid.link/1755112796-467444-3-git-send-email-tariqt@nvidia.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/mellanox/mlx5/core/eswitch.c | 62 ++++++++++++------- .../net/ethernet/mellanox/mlx5/core/eswitch.h | 7 +++ .../mellanox/mlx5/core/eswitch_offloads.c | 34 +++++----- 3 files changed, 66 insertions(+), 37 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 31059fff30ec..3d533061311b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1297,17 +1297,19 @@ mlx5_eswitch_enable_pf_vf_vports(struct mlx5_eswitch *esw, esw->mode == MLX5_ESWITCH_LEGACY; /* Enable PF vport */ - if (pf_needed) { + if (pf_needed && mlx5_esw_host_functions_enabled(esw->dev)) { ret = mlx5_eswitch_load_pf_vf_vport(esw, MLX5_VPORT_PF, enabled_events); if (ret) return ret; } - /* Enable external host PF HCA */ - ret = host_pf_enable_hca(esw->dev); - if (ret) - goto pf_hca_err; + if (mlx5_esw_host_functions_enabled(esw->dev)) { + /* Enable external host PF HCA */ + ret = host_pf_enable_hca(esw->dev); + if (ret) + goto pf_hca_err; + } /* Enable ECPF vport */ if (mlx5_ecpf_vport_exists(esw->dev)) { @@ -1339,9 +1341,10 @@ mlx5_eswitch_enable_pf_vf_vports(struct mlx5_eswitch *esw, if (mlx5_ecpf_vport_exists(esw->dev)) mlx5_eswitch_unload_pf_vf_vport(esw, MLX5_VPORT_ECPF); ecpf_err: - host_pf_disable_hca(esw->dev); + if (mlx5_esw_host_functions_enabled(esw->dev)) + host_pf_disable_hca(esw->dev); pf_hca_err: - if (pf_needed) + if (pf_needed && mlx5_esw_host_functions_enabled(esw->dev)) mlx5_eswitch_unload_pf_vf_vport(esw, MLX5_VPORT_PF); return ret; } @@ -1361,10 +1364,12 @@ void mlx5_eswitch_disable_pf_vf_vports(struct mlx5_eswitch *esw) mlx5_eswitch_unload_pf_vf_vport(esw, MLX5_VPORT_ECPF); } - host_pf_disable_hca(esw->dev); + if (mlx5_esw_host_functions_enabled(esw->dev)) + host_pf_disable_hca(esw->dev); - if (mlx5_core_is_ecpf_esw_manager(esw->dev) || - esw->mode == MLX5_ESWITCH_LEGACY) + if ((mlx5_core_is_ecpf_esw_manager(esw->dev) || + esw->mode == MLX5_ESWITCH_LEGACY) && + mlx5_esw_host_functions_enabled(esw->dev)) mlx5_eswitch_unload_pf_vf_vport(esw, MLX5_VPORT_PF); } @@ -1693,7 +1698,8 @@ int mlx5_esw_sf_max_hpf_functions(struct mlx5_core_dev *dev, u16 *max_sfs, u16 * void *hca_caps; int err; - if (!mlx5_core_is_ecpf(dev)) { + if (!mlx5_core_is_ecpf(dev) || + !mlx5_esw_host_functions_enabled(dev)) { *max_sfs = 0; return 0; } @@ -1769,21 +1775,23 @@ static int mlx5_esw_vports_init(struct mlx5_eswitch *esw) xa_init(&esw->vports); - err = mlx5_esw_vport_alloc(esw, idx, MLX5_VPORT_PF); - if (err) - goto err; - if (esw->first_host_vport == MLX5_VPORT_PF) - xa_set_mark(&esw->vports, idx, MLX5_ESW_VPT_HOST_FN); - idx++; - - for (i = 0; i < mlx5_core_max_vfs(dev); i++) { - err = mlx5_esw_vport_alloc(esw, idx, idx); + if (mlx5_esw_host_functions_enabled(dev)) { + err = mlx5_esw_vport_alloc(esw, idx, MLX5_VPORT_PF); if (err) goto err; - xa_set_mark(&esw->vports, idx, MLX5_ESW_VPT_VF); - xa_set_mark(&esw->vports, idx, MLX5_ESW_VPT_HOST_FN); + if (esw->first_host_vport == MLX5_VPORT_PF) + xa_set_mark(&esw->vports, idx, MLX5_ESW_VPT_HOST_FN); idx++; + for (i = 0; i < mlx5_core_max_vfs(dev); i++) { + err = mlx5_esw_vport_alloc(esw, idx, idx); + if (err) + goto err; + xa_set_mark(&esw->vports, idx, MLX5_ESW_VPT_VF); + xa_set_mark(&esw->vports, idx, MLX5_ESW_VPT_HOST_FN); + idx++; + } } + base_sf_num = mlx5_sf_start_function_id(dev); for (i = 0; i < mlx5_sf_max_functions(dev); i++) { err = mlx5_esw_vport_alloc(esw, idx, base_sf_num + i); @@ -1883,6 +1891,7 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev) goto free_esw; esw->dev = dev; + dev->priv.eswitch = esw; esw->manager_vport = mlx5_eswitch_manager_vport(dev); esw->first_host_vport = mlx5_eswitch_first_host_vport_num(dev); @@ -1901,7 +1910,6 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev) if (err) goto abort; - dev->priv.eswitch = esw; err = esw_offloads_init(esw); if (err) goto reps_err; @@ -2433,3 +2441,11 @@ void mlx5_eswitch_unblock_ipsec(struct mlx5_core_dev *dev) dev->num_ipsec_offloads--; mutex_unlock(&esw->state_lock); } + +bool mlx5_esw_host_functions_enabled(const struct mlx5_core_dev *dev) +{ + if (!dev->priv.eswitch) + return true; + + return !dev->priv.eswitch->esw_funcs.host_funcs_disabled; +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index 6d86db20f468..6c72080ac2a1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -899,6 +899,7 @@ int mlx5_esw_ipsec_vf_packet_offload_set(struct mlx5_eswitch *esw, struct mlx5_v bool enable); int mlx5_esw_ipsec_vf_packet_offload_supported(struct mlx5_core_dev *dev, u16 vport_num); +bool mlx5_esw_host_functions_enabled(const struct mlx5_core_dev *dev); #else /* CONFIG_MLX5_ESWITCH */ /* eswitch API stubs */ static inline int mlx5_eswitch_init(struct mlx5_core_dev *dev) { return 0; } @@ -966,6 +967,12 @@ static inline bool mlx5_eswitch_block_ipsec(struct mlx5_core_dev *dev) } static inline void mlx5_eswitch_unblock_ipsec(struct mlx5_core_dev *dev) {} + +static inline bool +mlx5_esw_host_functions_enabled(const struct mlx5_core_dev *dev) +{ + return true; +} #endif /* CONFIG_MLX5_ESWITCH */ #endif /* __MLX5_ESWITCH_H__ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index bee906661282..8ec9c0e0f4b9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -1213,7 +1213,8 @@ static int esw_add_fdb_peer_miss_rules(struct mlx5_eswitch *esw, misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters); - if (mlx5_core_is_ecpf_esw_manager(peer_dev)) { + if (mlx5_core_is_ecpf_esw_manager(peer_dev) && + mlx5_esw_host_functions_enabled(peer_dev)) { peer_vport = mlx5_eswitch_get_vport(peer_esw, MLX5_VPORT_PF); esw_set_peer_miss_rule_source_port(esw, peer_esw, spec, MLX5_VPORT_PF); @@ -1239,19 +1240,21 @@ static int esw_add_fdb_peer_miss_rules(struct mlx5_eswitch *esw, flows[peer_vport->index] = flow; } - mlx5_esw_for_each_vf_vport(peer_esw, i, peer_vport, - mlx5_core_max_vfs(peer_dev)) { - esw_set_peer_miss_rule_source_port(esw, - peer_esw, - spec, peer_vport->vport); + if (mlx5_esw_host_functions_enabled(esw->dev)) { + mlx5_esw_for_each_vf_vport(peer_esw, i, peer_vport, + mlx5_core_max_vfs(peer_dev)) { + esw_set_peer_miss_rule_source_port(esw, peer_esw, + spec, + peer_vport->vport); - flow = mlx5_add_flow_rules(mlx5_eswitch_get_slow_fdb(esw), - spec, &flow_act, &dest, 1); - if (IS_ERR(flow)) { - err = PTR_ERR(flow); - goto add_vf_flow_err; + flow = mlx5_add_flow_rules(mlx5_eswitch_get_slow_fdb(esw), + spec, &flow_act, &dest, 1); + if (IS_ERR(flow)) { + err = PTR_ERR(flow); + goto add_vf_flow_err; + } + flows[peer_vport->index] = flow; } - flows[peer_vport->index] = flow; } if (mlx5_core_ec_sriov_enabled(peer_dev)) { @@ -1301,7 +1304,9 @@ static int esw_add_fdb_peer_miss_rules(struct mlx5_eswitch *esw, mlx5_del_flow_rules(flows[peer_vport->index]); } add_ecpf_flow_err: - if (mlx5_core_is_ecpf_esw_manager(peer_dev)) { + + if (mlx5_core_is_ecpf_esw_manager(peer_dev) && + mlx5_esw_host_functions_enabled(peer_dev)) { peer_vport = mlx5_eswitch_get_vport(peer_esw, MLX5_VPORT_PF); mlx5_del_flow_rules(flows[peer_vport->index]); } @@ -4059,7 +4064,8 @@ mlx5_eswitch_vport_has_rep(const struct mlx5_eswitch *esw, u16 vport_num) { /* Currently, only ECPF based device has representor for host PF. */ if (vport_num == MLX5_VPORT_PF && - !mlx5_core_is_ecpf_esw_manager(esw->dev)) + (!mlx5_core_is_ecpf_esw_manager(esw->dev) || + !mlx5_esw_host_functions_enabled(esw->dev))) return false; if (vport_num == MLX5_VPORT_ECPF && From 8159572936392b514e404bab2d60e47cebd5acfe Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Thu, 14 Aug 2025 20:05:14 +0200 Subject: [PATCH 00998/11391] net: Space: Replace memset(0) + strscpy() with strscpy_pad() Replace memset(0) followed by strscpy() with strscpy_pad() to improve netdev_boot_setup_add(). 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. Signed-off-by: Thorsten Blum Link: https://patch.msgid.link/20250814180514.251000-2-thorsten.blum@linux.dev Signed-off-by: Jakub Kicinski --- drivers/net/Space.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/Space.c b/drivers/net/Space.c index dc50797a2ed0..c01e2c2f7d6c 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -67,8 +67,7 @@ static int netdev_boot_setup_add(char *name, struct ifmap *map) s = dev_boot_setup; for (i = 0; i < NETDEV_BOOT_SETUP_MAX; i++) { if (s[i].name[0] == '\0' || s[i].name[0] == ' ') { - memset(s[i].name, 0, sizeof(s[i].name)); - strscpy(s[i].name, name, IFNAMSIZ); + strscpy_pad(s[i].name, name); memcpy(&s[i].map, map, sizeof(s[i].map)); break; } From c80d79720647ed77ebc0198abd5a0807efdaff0b Mon Sep 17 00:00:00 2001 From: Matt Bobrowski Date: Fri, 15 Aug 2025 12:12:14 +0000 Subject: [PATCH 00999/11391] bpf/selftests: Fix test_tcpnotify_user Based on a bisect, it appears that commit 7ee988770326 ("timers: Implement the hierarchical pull model") has somehow inadvertently broken BPF selftest test_tcpnotify_user. The error that is being generated by this test is as follows: FAILED: Wrong stats Expected 10 calls, got 8 It looks like the change allows timer functions to be run on CPUs different from the one they are armed on. The test had pinned itself to CPU 0, and in the past the retransmit attempts also occurred on CPU 0. The test had set the max_entries attribute for BPF_MAP_TYPE_PERF_EVENT_ARRAY to 2 and was calling bpf_perf_event_output() with BPF_F_CURRENT_CPU, so the entry was likely to be in range. With the change to allow timers to run on other CPUs, the current CPU tasked with performing the retransmit might be bumped and in turn fall out of range, as the event will be filtered out via __bpf_perf_event_output() using: if (unlikely(index >= array->map.max_entries)) return -E2BIG; A possible change would be to explicitly set the max_entries attribute for perf_event_map in test_tcpnotify_kern.c to a value that's at least as large as the number of CPUs. As it turns out however, if the field is left unset, then the libbpf will determine the number of CPUs available on the underlying system and update the max_entries attribute accordingly in map_set_def_max_entries(). A further problem with the test is that it has a thread that continues running up until the program exits. The main thread cleans up some LIBBPF data structures, while the other thread continues to use them, which inevitably will trigger a SIGSEGV. This can be dealt with by telling the thread to run for as long as necessary and doing a pthread_join on it before exiting the program. Finally, I don't think binding the process to CPU 0 is meaningful for this test any more, so get rid of that. Fixes: 435f90a338ae ("selftests/bpf: add a test case for sock_ops perf-event notification") Signed-off-by: Matt Bobrowski Signed-off-by: Martin KaFai Lau Acked-by: Stanislav Fomichev Link: https://patch.msgid.link/aJ8kHhwgATmA3rLf@google.com --- .../selftests/bpf/progs/test_tcpnotify_kern.c | 1 - .../selftests/bpf/test_tcpnotify_user.c | 20 +++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/tools/testing/selftests/bpf/progs/test_tcpnotify_kern.c b/tools/testing/selftests/bpf/progs/test_tcpnotify_kern.c index 540181c115a8..ef00d38b0a8d 100644 --- a/tools/testing/selftests/bpf/progs/test_tcpnotify_kern.c +++ b/tools/testing/selftests/bpf/progs/test_tcpnotify_kern.c @@ -23,7 +23,6 @@ struct { struct { __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); - __uint(max_entries, 2); __type(key, int); __type(value, __u32); } perf_event_map SEC(".maps"); diff --git a/tools/testing/selftests/bpf/test_tcpnotify_user.c b/tools/testing/selftests/bpf/test_tcpnotify_user.c index 595194453ff8..35b4893ccdf8 100644 --- a/tools/testing/selftests/bpf/test_tcpnotify_user.c +++ b/tools/testing/selftests/bpf/test_tcpnotify_user.c @@ -15,20 +15,18 @@ #include #include #include -#include #include -#include -#include "bpf_util.h" #include "cgroup_helpers.h" #include "test_tcpnotify.h" -#include "trace_helpers.h" #include "testing_helpers.h" #define SOCKET_BUFFER_SIZE (getpagesize() < 8192L ? getpagesize() : 8192L) pthread_t tid; +static bool exit_thread; + int rx_callbacks; static void dummyfn(void *ctx, int cpu, void *data, __u32 size) @@ -45,7 +43,7 @@ void tcp_notifier_poller(struct perf_buffer *pb) { int err; - while (1) { + while (!exit_thread) { err = perf_buffer__poll(pb, 100); if (err < 0 && err != -EINTR) { printf("failed perf_buffer__poll: %d\n", err); @@ -78,15 +76,10 @@ int main(int argc, char **argv) int error = EXIT_FAILURE; struct bpf_object *obj; char test_script[80]; - cpu_set_t cpuset; __u32 key = 0; libbpf_set_strict_mode(LIBBPF_STRICT_ALL); - CPU_ZERO(&cpuset); - CPU_SET(0, &cpuset); - pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); - cg_fd = cgroup_setup_and_join(cg_path); if (cg_fd < 0) goto err; @@ -151,6 +144,13 @@ int main(int argc, char **argv) sleep(10); + exit_thread = true; + int ret = pthread_join(tid, NULL); + if (ret) { + printf("FAILED: pthread_join\n"); + goto err; + } + if (verify_result(&g)) { printf("FAILED: Wrong stats Expected %d calls, got %d\n", g.ncalls, rx_callbacks); From 27f94b71532203b079537180924023a5f636fca1 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Tue, 8 Jul 2025 12:28:42 +0200 Subject: [PATCH 01000/11391] arm64: dts: qcom: qcm2290: Disable USB SS bus instances in park mode 2290 was found in the field to also require this quirk, as long & high-bandwidth workloads (e.g. USB ethernet) are consistently able to crash the controller otherwise. The same change has been made for a number of SoCs in [1], but QCM2290 somehow escaped the list (even though the very closely related SM6115 was there). Upon a controller crash, the log would read: xhci-hcd.12.auto: xHCI host not responding to stop endpoint command xhci-hcd.12.auto: xHCI host controller not responding, assume dead xhci-hcd.12.auto: HC died; cleaning up Add snps,parkmode-disable-ss-quirk to the DWC3 instance in order to prevent the aforementioned breakage. [1] https://lore.kernel.org/all/20240704152848.3380602-1-quic_kriskura@quicinc.com/ Cc: stable@vger.kernel.org Reported-by: Rob Clark Fixes: a64a0192b70c ("arm64: dts: qcom: Add initial QCM2290 device tree") Signed-off-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250708-topic-2290_usb-v1-1-661e70a63339@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/qcm2290.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/qcm2290.dtsi b/arch/arm64/boot/dts/qcom/qcm2290.dtsi index eb489d0a684a..77d7ee17ba90 100644 --- a/arch/arm64/boot/dts/qcom/qcm2290.dtsi +++ b/arch/arm64/boot/dts/qcom/qcm2290.dtsi @@ -1460,6 +1460,7 @@ usb_dwc3: usb@4e00000 { snps,has-lpm-erratum; snps,hird-threshold = /bits/ 8 <0x10>; snps,usb3_lpm_capable; + snps,parkmode-disable-ss-quirk; maximum-speed = "super-speed"; dr_mode = "otg"; usb-role-switch; From 1e180614b3608e1cb0f81753b2172af253d58a52 Mon Sep 17 00:00:00 2001 From: Shankari Anand Date: Thu, 14 Aug 2025 16:16:15 +0530 Subject: [PATCH 01001/11391] rust: driver-core: Update ARef and AlwaysRefCounted imports from sync::aref Update call sites in the driver-core files and its related samples to import `ARef` and `AlwaysRefCounted` from `sync::aref` instead of `types`. This aligns with the ongoing effort to move `ARef` and `AlwaysRefCounted` to sync. Suggested-by: Benno Lossin Link: https://github.com/Rust-for-Linux/linux/issues/1173 Signed-off-by: Shankari Anand Link: https://lore.kernel.org/r/20250814104615.355106-1-shankari.ak0208@gmail.com Signed-off-by: Danilo Krummrich --- rust/kernel/auxiliary.rs | 2 +- rust/kernel/device.rs | 7 ++++--- rust/kernel/devres.rs | 4 ++-- rust/kernel/pci.rs | 5 +++-- rust/kernel/platform.rs | 2 +- samples/rust/rust_driver_pci.rs | 2 +- samples/rust/rust_driver_platform.rs | 2 +- 7 files changed, 13 insertions(+), 11 deletions(-) diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs index f73c460665ec..8dc7490a79a4 100644 --- a/rust/kernel/auxiliary.rs +++ b/rust/kernel/auxiliary.rs @@ -245,7 +245,7 @@ extern "C" fn release(dev: *mut bindings::device) { kernel::impl_device_context_into_aref!(Device); // SAFETY: Instances of `Device` are always reference-counted. -unsafe impl crate::types::AlwaysRefCounted for Device { +unsafe impl crate::sync::aref::AlwaysRefCounted for Device { fn inc_ref(&self) { // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero. unsafe { bindings::get_device(self.as_ref().as_raw()) }; diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index b8613289de8e..b860ab389f18 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -6,7 +6,8 @@ use crate::{ bindings, - types::{ARef, ForeignOwnable, Opaque}, + sync::aref::ARef, + types::{ForeignOwnable, Opaque}, }; use core::{fmt, marker::PhantomData, ptr}; @@ -292,7 +293,7 @@ pub fn fwnode(&self) -> Option<&property::FwNode> { kernel::impl_device_context_into_aref!(Device); // SAFETY: Instances of `Device` are always reference-counted. -unsafe impl crate::types::AlwaysRefCounted for Device { +unsafe impl crate::sync::aref::AlwaysRefCounted for Device { fn inc_ref(&self) { // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero. unsafe { bindings::get_device(self.as_raw()) }; @@ -411,7 +412,7 @@ macro_rules! impl_device_context_deref { #[macro_export] macro_rules! __impl_device_context_into_aref { ($src:ty, $device:tt) => { - impl ::core::convert::From<&$device<$src>> for $crate::types::ARef<$device> { + impl ::core::convert::From<&$device<$src>> for $crate::sync::aref::ARef<$device> { fn from(dev: &$device<$src>) -> Self { (&**dev).into() } diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index da18091143a6..99b7520019f0 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -13,8 +13,8 @@ ffi::c_void, prelude::*, revocable::{Revocable, RevocableGuard}, - sync::{rcu, Completion}, - types::{ARef, ForeignOwnable, Opaque, ScopeGuard}, + sync::{aref::ARef, rcu, Completion}, + types::{ForeignOwnable, Opaque, ScopeGuard}, }; use pin_init::Wrapper; diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index 08fb69e5eb97..cae4e274f776 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -13,7 +13,8 @@ io::{Io, IoRaw}, irq::{self, IrqRequest}, str::CStr, - types::{ARef, Opaque}, + sync::aref::ARef, + types::Opaque, ThisModule, }; use core::{ @@ -544,7 +545,7 @@ pub fn set_master(&self) { impl crate::dma::Device for Device {} // SAFETY: Instances of `Device` are always reference-counted. -unsafe impl crate::types::AlwaysRefCounted for Device { +unsafe impl crate::sync::aref::AlwaysRefCounted for Device { fn inc_ref(&self) { // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero. unsafe { bindings::pci_dev_get(self.as_raw()) }; diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index ce2bb4d4e882..7205fe3416d3 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -468,7 +468,7 @@ pub fn optional_irq_by_name(&self, name: &CStr) -> Result> { impl crate::dma::Device for Device {} // SAFETY: Instances of `Device` are always reference-counted. -unsafe impl crate::types::AlwaysRefCounted for Device { +unsafe impl crate::sync::aref::AlwaysRefCounted for Device { fn inc_ref(&self) { // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero. unsafe { bindings::get_device(self.as_ref().as_raw()) }; diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci.rs index 606946ff4d7f..0798019014cd 100644 --- a/samples/rust/rust_driver_pci.rs +++ b/samples/rust/rust_driver_pci.rs @@ -4,7 +4,7 @@ //! //! To make this driver probe, QEMU must be run with `-device pci-testdev`. -use kernel::{bindings, c_str, device::Core, devres::Devres, pci, prelude::*, types::ARef}; +use kernel::{bindings, c_str, device::Core, devres::Devres, pci, prelude::*, sync::aref::ARef}; struct Regs; diff --git a/samples/rust/rust_driver_platform.rs b/samples/rust/rust_driver_platform.rs index 69ed55b7b0fa..6473baf4f120 100644 --- a/samples/rust/rust_driver_platform.rs +++ b/samples/rust/rust_driver_platform.rs @@ -72,7 +72,7 @@ of, platform, prelude::*, str::CString, - types::ARef, + sync::aref::ARef, }; struct SampleDriver { From 7e25d84f460c59322bf01dfeb1fb4745b488f714 Mon Sep 17 00:00:00 2001 From: Shankari Anand Date: Thu, 14 Aug 2025 16:11:33 +0530 Subject: [PATCH 01002/11391] rust: dma: Update ARef and AlwaysRefCounted imports from sync::aref Update call sites in the dma subsystem to import `ARef` and `AlwaysRefCounted` from `sync::aref` instead of `types`. This aligns with the ongoing effort to move `ARef` and `AlwaysRefCounted` to sync. Suggested-by: Benno Lossin Link: https://github.com/Rust-for-Linux/linux/issues/1173 Signed-off-by: Shankari Anand Link: https://lore.kernel.org/r/20250814104133.350093-1-shankari.ak0208@gmail.com Signed-off-by: Danilo Krummrich --- rust/kernel/dma.rs | 2 +- samples/rust/rust_dma.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs index 2bc8ab51ec28..68fe67624424 100644 --- a/rust/kernel/dma.rs +++ b/rust/kernel/dma.rs @@ -9,8 +9,8 @@ device::{Bound, Core}, error::{to_result, Result}, prelude::*, + sync::aref::ARef, transmute::{AsBytes, FromBytes}, - types::ARef, }; /// Trait to be implemented by DMA capable bus devices. diff --git a/samples/rust/rust_dma.rs b/samples/rust/rust_dma.rs index c5e7cce68654..997a9c4cf2b3 100644 --- a/samples/rust/rust_dma.rs +++ b/samples/rust/rust_dma.rs @@ -10,7 +10,7 @@ dma::{CoherentAllocation, Device, DmaMask}, pci, prelude::*, - types::ARef, + sync::aref::ARef, }; struct DmaSampleDriver { From d87208128a3330c0eab18301ab39bdb419647730 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 14 Aug 2025 18:31:38 -0700 Subject: [PATCH 01003/11391] x86/build: Remove cc-option from stack alignment flags '-mpreferred-stack-boundary' (the GCC option) and '-mstack-alignment' (the clang option) have been supported in their respective compilers for some time, so it is unnecessary to check for support for them via cc-option. '-mpreferred-stack-boundary=3' had a restriction on '-mno-sse' until GCC 7.1 but that is irrelevant for most of the kernel, which includes '-mno-sse'. Move to simple Kconfig checks to avoid querying the compiler for the flags that it supports. Signed-off-by: Nathan Chancellor Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/20250814-x86-min-ver-cleanups-v1-2-ff7f19457523@kernel.org --- arch/x86/Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/x86/Makefile b/arch/x86/Makefile index ed5657395d6a..f0aa58d2ec17 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -37,10 +37,11 @@ export RETPOLINE_VDSO_CFLAGS # For gcc stack alignment is specified with -mpreferred-stack-boundary, # clang has the option -mstack-alignment for that purpose. -ifneq ($(call cc-option, -mpreferred-stack-boundary=4),) +ifdef CONFIG_CC_IS_GCC cc_stack_align4 := -mpreferred-stack-boundary=2 cc_stack_align8 := -mpreferred-stack-boundary=3 -else ifneq ($(call cc-option, -mstack-alignment=16),) +endif +ifdef CONFIG_CC_IS_CLANG cc_stack_align4 := -mstack-alignment=4 cc_stack_align8 := -mstack-alignment=8 endif From fb13ae067ad7f07df2bdc374aa911ff58dfd19ce Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 16 Jul 2025 18:06:29 -0700 Subject: [PATCH 01004/11391] EDAC: Add EDAC driver for ARM Cortex A72 cores The driver is designed to support error detection and reporting for Cortex A72 cores, specifically within their L1 and L2 cache systems. The errors are detected by reading CPU/L2 memory error syndrome registers. Unfortunately there is no robust way to inject errors into the caches, so this driver doesn't contain any code to actually test it. It has been tested though with code taken from an older version [1] of this driver. For reasons stated in thread [1], the error injection code is not suitable for mainline, so it is removed from the driver. [1] https://lore.kernel.org/all/1521073067-24348-1-git-send-email-york.sun@nxp.com/#t [ bp: minor touchups. ] Signed-off-by: Sascha Hauer Co-developed-by: Vijay Balakrishna Signed-off-by: Vijay Balakrishna Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/1752714390-27389-2-git-send-email-vijayb@linux.microsoft.com --- MAINTAINERS | 7 ++ drivers/edac/Kconfig | 8 ++ drivers/edac/Makefile | 1 + drivers/edac/a72_edac.c | 225 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 241 insertions(+) create mode 100644 drivers/edac/a72_edac.c diff --git a/MAINTAINERS b/MAINTAINERS index fe168477caa4..ac20587a3e98 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8736,6 +8736,13 @@ F: Documentation/driver-api/edac.rst F: drivers/edac/ F: include/linux/edac.h +EDAC-A72 +M: Vijay Balakrishna +M: Tyler Hicks +L: linux-edac@vger.kernel.org +S: Supported +F: drivers/edac/a72_edac.c + EDAC-DMC520 M: Lei Wang L: linux-edac@vger.kernel.org diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 19ad3c3b675d..b824472208c4 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -576,4 +576,12 @@ config EDAC_LOONGSON errors (CE) only. Loongson-3A5000/3C5000/3D5000/3A6000/3C6000 are compatible. +config EDAC_CORTEX_A72 + tristate "ARM Cortex A72" + depends on ARM64 + help + Support for L1/L2 cache error detection for ARM Cortex A72 processor. + The detected and reported errors are from reading CPU/L2 memory error + syndrome registers. + endif # EDAC diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index a8f2d8f6c894..c1736f264320 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -88,3 +88,4 @@ obj-$(CONFIG_EDAC_NPCM) += npcm_edac.o obj-$(CONFIG_EDAC_ZYNQMP) += zynqmp_edac.o obj-$(CONFIG_EDAC_VERSAL) += versal_edac.o obj-$(CONFIG_EDAC_LOONGSON) += loongson_edac.o +obj-$(CONFIG_EDAC_CORTEX_A72) += a72_edac.o diff --git a/drivers/edac/a72_edac.c b/drivers/edac/a72_edac.c new file mode 100644 index 000000000000..9262d75c3855 --- /dev/null +++ b/drivers/edac/a72_edac.c @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cortex A72 EDAC L1 and L2 cache error detection + * + * Copyright (c) 2020 Pengutronix, Sascha Hauer + * Copyright (c) 2025 Microsoft Corporation, + * + * Based on Code from: + * Copyright (c) 2018, NXP Semiconductor + * Author: York Sun + */ + +#include +#include +#include +#include + +#include "edac_module.h" + +#define DRVNAME "a72-edac" + +#define SYS_CPUMERRSR_EL1 sys_reg(3, 1, 15, 2, 2) +#define SYS_L2MERRSR_EL1 sys_reg(3, 1, 15, 2, 3) + +#define CPUMERRSR_EL1_RAMID GENMASK(30, 24) +#define L2MERRSR_EL1_CPUID_WAY GENMASK(21, 18) + +#define CPUMERRSR_EL1_VALID BIT(31) +#define CPUMERRSR_EL1_FATAL BIT(63) +#define L2MERRSR_EL1_VALID BIT(31) +#define L2MERRSR_EL1_FATAL BIT(63) + +#define L1_I_TAG_RAM 0x00 +#define L1_I_DATA_RAM 0x01 +#define L1_D_TAG_RAM 0x08 +#define L1_D_DATA_RAM 0x09 +#define TLB_RAM 0x18 + +#define MESSAGE_SIZE 64 + +struct mem_err_synd_reg { + u64 cpu_mesr; + u64 l2_mesr; +}; + +static struct cpumask compat_mask; + +static void report_errors(struct edac_device_ctl_info *edac_ctl, int cpu, + struct mem_err_synd_reg *mesr) +{ + u64 cpu_mesr = mesr->cpu_mesr; + u64 l2_mesr = mesr->l2_mesr; + char msg[MESSAGE_SIZE]; + + if (cpu_mesr & CPUMERRSR_EL1_VALID) { + const char *str; + bool fatal = cpu_mesr & CPUMERRSR_EL1_FATAL; + + switch (FIELD_GET(CPUMERRSR_EL1_RAMID, cpu_mesr)) { + case L1_I_TAG_RAM: + str = "L1-I Tag RAM"; + break; + case L1_I_DATA_RAM: + str = "L1-I Data RAM"; + break; + case L1_D_TAG_RAM: + str = "L1-D Tag RAM"; + break; + case L1_D_DATA_RAM: + str = "L1-D Data RAM"; + break; + case TLB_RAM: + str = "TLB RAM"; + break; + default: + str = "Unspecified"; + break; + } + + snprintf(msg, MESSAGE_SIZE, "%s %s error(s) on CPU %d", + str, fatal ? "fatal" : "correctable", cpu); + + if (fatal) + edac_device_handle_ue(edac_ctl, cpu, 0, msg); + else + edac_device_handle_ce(edac_ctl, cpu, 0, msg); + } + + if (l2_mesr & L2MERRSR_EL1_VALID) { + bool fatal = l2_mesr & L2MERRSR_EL1_FATAL; + + snprintf(msg, MESSAGE_SIZE, "L2 %s error(s) on CPU %d CPUID/WAY 0x%lx", + fatal ? "fatal" : "correctable", cpu, + FIELD_GET(L2MERRSR_EL1_CPUID_WAY, l2_mesr)); + if (fatal) + edac_device_handle_ue(edac_ctl, cpu, 1, msg); + else + edac_device_handle_ce(edac_ctl, cpu, 1, msg); + } +} + +static void read_errors(void *data) +{ + struct mem_err_synd_reg *mesr = data; + + mesr->cpu_mesr = read_sysreg_s(SYS_CPUMERRSR_EL1); + if (mesr->cpu_mesr & CPUMERRSR_EL1_VALID) { + write_sysreg_s(0, SYS_CPUMERRSR_EL1); + isb(); + } + mesr->l2_mesr = read_sysreg_s(SYS_L2MERRSR_EL1); + if (mesr->l2_mesr & L2MERRSR_EL1_VALID) { + write_sysreg_s(0, SYS_L2MERRSR_EL1); + isb(); + } +} + +static void a72_edac_check(struct edac_device_ctl_info *edac_ctl) +{ + struct mem_err_synd_reg mesr; + int cpu; + + cpus_read_lock(); + for_each_cpu_and(cpu, cpu_online_mask, &compat_mask) { + smp_call_function_single(cpu, read_errors, &mesr, true); + report_errors(edac_ctl, cpu, &mesr); + } + cpus_read_unlock(); +} + +static int a72_edac_probe(struct platform_device *pdev) +{ + struct edac_device_ctl_info *edac_ctl; + struct device *dev = &pdev->dev; + int rc; + + edac_ctl = edac_device_alloc_ctl_info(0, "cpu", + num_possible_cpus(), "L", 2, 1, + edac_device_alloc_index()); + if (!edac_ctl) + return -ENOMEM; + + edac_ctl->edac_check = a72_edac_check; + edac_ctl->dev = dev; + edac_ctl->mod_name = dev_name(dev); + edac_ctl->dev_name = dev_name(dev); + edac_ctl->ctl_name = DRVNAME; + dev_set_drvdata(dev, edac_ctl); + + rc = edac_device_add_device(edac_ctl); + if (rc) + goto out_dev; + + return 0; + +out_dev: + edac_device_free_ctl_info(edac_ctl); + + return rc; +} + +static void a72_edac_remove(struct platform_device *pdev) +{ + struct edac_device_ctl_info *edac_ctl = dev_get_drvdata(&pdev->dev); + + edac_device_del_device(edac_ctl->dev); + edac_device_free_ctl_info(edac_ctl); +} + +static const struct of_device_id cortex_arm64_edac_of_match[] = { + { .compatible = "arm,cortex-a72" }, + {} +}; +MODULE_DEVICE_TABLE(of, cortex_arm64_edac_of_match); + +static struct platform_driver a72_edac_driver = { + .probe = a72_edac_probe, + .remove = a72_edac_remove, + .driver = { + .name = DRVNAME, + }, +}; + +static struct platform_device *a72_pdev; + +static int __init a72_edac_driver_init(void) +{ + int cpu; + + for_each_possible_cpu(cpu) { + struct device_node *np __free(device_node) = of_cpu_device_node_get(cpu); + if (np) { + if (of_match_node(cortex_arm64_edac_of_match, np) && + of_property_read_bool(np, "edac-enabled")) { + cpumask_set_cpu(cpu, &compat_mask); + } + } else { + pr_warn("failed to find device node for CPU %d\n", cpu); + } + } + + if (cpumask_empty(&compat_mask)) + return 0; + + a72_pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(a72_pdev)) { + pr_err("failed to register A72 EDAC device\n"); + return PTR_ERR(a72_pdev); + } + + return platform_driver_register(&a72_edac_driver); +} + +static void __exit a72_edac_driver_exit(void) +{ + platform_device_unregister(a72_pdev); + platform_driver_unregister(&a72_edac_driver); +} + +module_init(a72_edac_driver_init); +module_exit(a72_edac_driver_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sascha Hauer "); +MODULE_DESCRIPTION("Cortex A72 L1 and L2 cache EDAC driver"); From eb0e3f301d6ee7c813556fa6ca714e436f5235b0 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 16 Jul 2025 18:06:30 -0700 Subject: [PATCH 01005/11391] dt-bindings: arm: cpus: Add edac-enabled property Some ARM Cortex CPUs including A72 have Error Detection And Correction (EDAC) support on their L1 and L2 caches. That functionality is in implementation defined registers, so using it is not safe in virtualized environments or when EL3 already uses these registers. Add a edac-enabled flag which can be explicitly set when EDAC can be used. [ bp: Massage commit message. ] Signed-off-by: Sascha Hauer Signed-off-by: Vijay Balakrishna Signed-off-by: Borislav Petkov (AMD) Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/1752714390-27389-3-git-send-email-vijayb@linux.microsoft.com --- Documentation/devicetree/bindings/arm/cpus.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/cpus.yaml b/Documentation/devicetree/bindings/arm/cpus.yaml index 5bd517befb68..4accf4cbc6c7 100644 --- a/Documentation/devicetree/bindings/arm/cpus.yaml +++ b/Documentation/devicetree/bindings/arm/cpus.yaml @@ -353,6 +353,12 @@ properties: $ref: /schemas/types.yaml#/definitions/phandle description: Link to Mediatek Cache Coherent Interconnect + edac-enabled: + $ref: /schemas/types.yaml#/definitions/flag + description: + A72 CPUs support Error Detection And Correction (EDAC) on their L1 and + L2 caches. This flag marks this function as usable. + qcom,saw: $ref: /schemas/types.yaml#/definitions/phandle description: @@ -399,6 +405,17 @@ properties: allOf: - $ref: /schemas/cpu.yaml# - $ref: /schemas/opp/opp-v1.yaml# + - if: + not: + properties: + compatible: + contains: + const: arm,cortex-a72 + then: + # Allow edac-enabled only for Cortex A72 + properties: + edac-enabled: false + - if: # If the enable-method property contains one of those values properties: From 38f9f4f5f8828e43c549fd07b70fe5bc4c2ef2f6 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Wed, 6 Aug 2025 16:27:32 -0500 Subject: [PATCH 01006/11391] dt-bindings: arm: Convert marvell,berlin to DT schema Reviewed-by: Jisheng Zhang Link: https://lore.kernel.org/r/20250806212733.1633662-1-robh@kernel.org Signed-off-by: Rob Herring (Arm) --- .../bindings/arm/marvell,berlin.yaml | 45 ++++++++++ .../devicetree/bindings/arm/syna.txt | 89 ------------------- 2 files changed, 45 insertions(+), 89 deletions(-) create mode 100644 Documentation/devicetree/bindings/arm/marvell,berlin.yaml delete mode 100644 Documentation/devicetree/bindings/arm/syna.txt diff --git a/Documentation/devicetree/bindings/arm/marvell,berlin.yaml b/Documentation/devicetree/bindings/arm/marvell,berlin.yaml new file mode 100644 index 000000000000..4e8442980dcb --- /dev/null +++ b/Documentation/devicetree/bindings/arm/marvell,berlin.yaml @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/marvell,berlin.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Synaptics/Marvell Berlin SoC + +maintainers: + - Jisheng Zhang + +description: + According to https://www.synaptics.com/company/news/conexant-marvell + Synaptics has acquired the Multimedia Solutions Business of Marvell, so + Berlin SoCs are now Synaptics' SoCs. + +properties: + $nodename: + const: '/' + compatible: + oneOf: + - items: + - enum: + - sony,nsz-gs7 + - const: marvell,berlin2 + - const: marvell,berlin + - items: + - enum: + - google,chromecast + - valve,steamlink + - const: marvell,berlin2cd + - const: marvell,berlin + - items: + - enum: + - marvell,berlin2q-dmp + - const: marvell,berlin2q + - const: marvell,berlin + - items: + - enum: + - marvell,berlin4ct-dmp + - marvell,berlin4ct-stb + - const: marvell,berlin4ct + - const: marvell,berlin + +additionalProperties: true diff --git a/Documentation/devicetree/bindings/arm/syna.txt b/Documentation/devicetree/bindings/arm/syna.txt deleted file mode 100644 index f53c430f648c..000000000000 --- a/Documentation/devicetree/bindings/arm/syna.txt +++ /dev/null @@ -1,89 +0,0 @@ -Synaptics SoC Device Tree Bindings - -According to https://www.synaptics.com/company/news/conexant-marvell -Synaptics has acquired the Multimedia Solutions Business of Marvell, so -berlin SoCs are now Synaptics' SoCs now. - ---------------------------------------------------------------- - -Boards with a SoC of the Marvell Berlin family, e.g. Armada 1500 -shall have the following properties: - -* Required root node properties: -compatible: must contain "marvell,berlin" - -In addition, the above compatible shall be extended with the specific -SoC and board used. Currently known SoC compatibles are: - "marvell,berlin2" for Marvell Armada 1500 (BG2, 88DE3100), - "marvell,berlin2cd" for Marvell Armada 1500-mini (BG2CD, 88DE3005) - "marvell,berlin2ct" for Marvell Armada ? (BG2CT, 88DE????) - "marvell,berlin2q" for Marvell Armada 1500-pro (BG2Q, 88DE3114) - "marvell,berlin3" for Marvell Armada ? (BG3, 88DE????) - -* Example: - -/ { - model = "Sony NSZ-GS7"; - compatible = "sony,nsz-gs7", "marvell,berlin2", "marvell,berlin"; - - ... -} - -* Marvell Berlin CPU control bindings - -CPU control register allows various operations on CPUs, like resetting them -independently. - -Required properties: -- compatible: should be "marvell,berlin-cpu-ctrl" -- reg: address and length of the register set - -Example: - -cpu-ctrl@f7dd0000 { - compatible = "marvell,berlin-cpu-ctrl"; - reg = <0xf7dd0000 0x10000>; -}; - -* Marvell Berlin2 chip control binding - -Marvell Berlin SoCs have a chip control register set providing several -individual registers dealing with pinmux, padmux, clock, reset, and secondary -CPU boot address. Unfortunately, the individual registers are spread among the -chip control registers, so there should be a single DT node only providing the -different functions which are described below. - -Required properties: -- compatible: - * the first and second values must be: - "simple-mfd", "syscon" -- reg: address and length of following register sets for - BG2/BG2CD: chip control register set - BG2Q: chip control register set and cpu pll registers - -* Marvell Berlin2 system control binding - -Marvell Berlin SoCs have a system control register set providing several -individual registers dealing with pinmux, padmux, and reset. - -Required properties: -- compatible: - * the first and second values must be: - "simple-mfd", "syscon" -- reg: address and length of the system control register set - -Example: - -chip: chip-control@ea0000 { - compatible = "simple-mfd", "syscon"; - reg = <0xea0000 0x400>; - - /* sub-device nodes */ -}; - -sysctrl: system-controller@d000 { - compatible = "simple-mfd", "syscon"; - reg = <0xd000 0x100>; - - /* sub-device nodes */ -}; From 47829efa1cf42993e5bea2b4aea7e1cfcf8bd438 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Tue, 12 Aug 2025 13:14:20 -0500 Subject: [PATCH 01007/11391] dt-bindings: perf: Convert apm,xgene-pmu to DT schema Convert the Applied Micro X-Gene PMU binding to DT schema format. It is a straightforward conversion. Link: https://lore.kernel.org/r/20250812181422.68286-1-robh@kernel.org Signed-off-by: Rob Herring (Arm) --- .../bindings/perf/apm,xgene-pmu.yaml | 142 ++++++++++++++++++ .../bindings/perf/apm-xgene-pmu.txt | 112 -------------- MAINTAINERS | 2 +- 3 files changed, 143 insertions(+), 113 deletions(-) create mode 100644 Documentation/devicetree/bindings/perf/apm,xgene-pmu.yaml delete mode 100644 Documentation/devicetree/bindings/perf/apm-xgene-pmu.txt diff --git a/Documentation/devicetree/bindings/perf/apm,xgene-pmu.yaml b/Documentation/devicetree/bindings/perf/apm,xgene-pmu.yaml new file mode 100644 index 000000000000..314048a2a134 --- /dev/null +++ b/Documentation/devicetree/bindings/perf/apm,xgene-pmu.yaml @@ -0,0 +1,142 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/perf/apm,xgene-pmu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: APM X-Gene SoC PMU + +maintainers: + - Khuong Dinh + +description: | + This is APM X-Gene SoC PMU (Performance Monitoring Unit) module. + The following PMU devices are supported: + + L3C - L3 cache controller + IOB - IO bridge + MCB - Memory controller bridge + MC - Memory controller + +properties: + compatible: + enum: + - apm,xgene-pmu + - apm,xgene-pmu-v2 + + "#address-cells": + const: 2 + + "#size-cells": + const: 2 + + ranges: true + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + regmap-csw: + $ref: /schemas/types.yaml#/definitions/phandle + + regmap-mcba: + $ref: /schemas/types.yaml#/definitions/phandle + + regmap-mcbb: + $ref: /schemas/types.yaml#/definitions/phandle + +required: + - compatible + - regmap-csw + - regmap-mcba + - regmap-mcbb + - reg + - interrupts + +additionalProperties: + type: object + additionalProperties: false + + properties: + compatible: + enum: + - apm,xgene-pmu-l3c + - apm,xgene-pmu-iob + - apm,xgene-pmu-mcb + - apm,xgene-pmu-mc + + reg: + maxItems: 1 + + enable-bit-index: + description: + Specifies which bit enables the associated resource in MCB or MC subnodes. + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 31 + +examples: + - | + bus { + #address-cells = <2>; + #size-cells = <2>; + + pmu@78810000 { + compatible = "apm,xgene-pmu-v2"; + reg = <0x0 0x78810000 0x0 0x1000>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + regmap-csw = <&csw>; + regmap-mcba = <&mcba>; + regmap-mcbb = <&mcbb>; + interrupts = <0x0 0x22 0x4>; + + pmul3c@7e610000 { + compatible = "apm,xgene-pmu-l3c"; + reg = <0x0 0x7e610000 0x0 0x1000>; + }; + + pmuiob@7e940000 { + compatible = "apm,xgene-pmu-iob"; + reg = <0x0 0x7e940000 0x0 0x1000>; + }; + + pmucmcb@7e710000 { + compatible = "apm,xgene-pmu-mcb"; + reg = <0x0 0x7e710000 0x0 0x1000>; + enable-bit-index = <0>; + }; + + pmucmcb@7e730000 { + compatible = "apm,xgene-pmu-mcb"; + reg = <0x0 0x7e730000 0x0 0x1000>; + enable-bit-index = <1>; + }; + + pmucmc@7e810000 { + compatible = "apm,xgene-pmu-mc"; + reg = <0x0 0x7e810000 0x0 0x1000>; + enable-bit-index = <0>; + }; + + pmucmc@7e850000 { + compatible = "apm,xgene-pmu-mc"; + reg = <0x0 0x7e850000 0x0 0x1000>; + enable-bit-index = <1>; + }; + + pmucmc@7e890000 { + compatible = "apm,xgene-pmu-mc"; + reg = <0x0 0x7e890000 0x0 0x1000>; + enable-bit-index = <2>; + }; + + pmucmc@7e8d0000 { + compatible = "apm,xgene-pmu-mc"; + reg = <0x0 0x7e8d0000 0x0 0x1000>; + enable-bit-index = <3>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/perf/apm-xgene-pmu.txt b/Documentation/devicetree/bindings/perf/apm-xgene-pmu.txt deleted file mode 100644 index afb11cf693c0..000000000000 --- a/Documentation/devicetree/bindings/perf/apm-xgene-pmu.txt +++ /dev/null @@ -1,112 +0,0 @@ -* APM X-Gene SoC PMU bindings - -This is APM X-Gene SoC PMU (Performance Monitoring Unit) module. -The following PMU devices are supported: - - L3C - L3 cache controller - IOB - IO bridge - MCB - Memory controller bridge - MC - Memory controller - -The following section describes the SoC PMU DT node binding. - -Required properties: -- compatible : Shall be "apm,xgene-pmu" for revision 1 or - "apm,xgene-pmu-v2" for revision 2. -- regmap-csw : Regmap of the CPU switch fabric (CSW) resource. -- regmap-mcba : Regmap of the MCB-A (memory bridge) resource. -- regmap-mcbb : Regmap of the MCB-B (memory bridge) resource. -- reg : First resource shall be the CPU bus PMU resource. -- interrupts : Interrupt-specifier for PMU IRQ. - -Required properties for L3C subnode: -- compatible : Shall be "apm,xgene-pmu-l3c". -- reg : First resource shall be the L3C PMU resource. - -Required properties for IOB subnode: -- compatible : Shall be "apm,xgene-pmu-iob". -- reg : First resource shall be the IOB PMU resource. - -Required properties for MCB subnode: -- compatible : Shall be "apm,xgene-pmu-mcb". -- reg : First resource shall be the MCB PMU resource. -- enable-bit-index : The bit indicates if the according MCB is enabled. - -Required properties for MC subnode: -- compatible : Shall be "apm,xgene-pmu-mc". -- reg : First resource shall be the MC PMU resource. -- enable-bit-index : The bit indicates if the according MC is enabled. - -Example: - csw: csw@7e200000 { - compatible = "apm,xgene-csw", "syscon"; - reg = <0x0 0x7e200000 0x0 0x1000>; - }; - - mcba: mcba@7e700000 { - compatible = "apm,xgene-mcb", "syscon"; - reg = <0x0 0x7e700000 0x0 0x1000>; - }; - - mcbb: mcbb@7e720000 { - compatible = "apm,xgene-mcb", "syscon"; - reg = <0x0 0x7e720000 0x0 0x1000>; - }; - - pmu: pmu@78810000 { - compatible = "apm,xgene-pmu-v2"; - #address-cells = <2>; - #size-cells = <2>; - ranges; - regmap-csw = <&csw>; - regmap-mcba = <&mcba>; - regmap-mcbb = <&mcbb>; - reg = <0x0 0x78810000 0x0 0x1000>; - interrupts = <0x0 0x22 0x4>; - - pmul3c@7e610000 { - compatible = "apm,xgene-pmu-l3c"; - reg = <0x0 0x7e610000 0x0 0x1000>; - }; - - pmuiob@7e940000 { - compatible = "apm,xgene-pmu-iob"; - reg = <0x0 0x7e940000 0x0 0x1000>; - }; - - pmucmcb@7e710000 { - compatible = "apm,xgene-pmu-mcb"; - reg = <0x0 0x7e710000 0x0 0x1000>; - enable-bit-index = <0>; - }; - - pmucmcb@7e730000 { - compatible = "apm,xgene-pmu-mcb"; - reg = <0x0 0x7e730000 0x0 0x1000>; - enable-bit-index = <1>; - }; - - pmucmc@7e810000 { - compatible = "apm,xgene-pmu-mc"; - reg = <0x0 0x7e810000 0x0 0x1000>; - enable-bit-index = <0>; - }; - - pmucmc@7e850000 { - compatible = "apm,xgene-pmu-mc"; - reg = <0x0 0x7e850000 0x0 0x1000>; - enable-bit-index = <1>; - }; - - pmucmc@7e890000 { - compatible = "apm,xgene-pmu-mc"; - reg = <0x0 0x7e890000 0x0 0x1000>; - enable-bit-index = <2>; - }; - - pmucmc@7e8d0000 { - compatible = "apm,xgene-pmu-mc"; - reg = <0x0 0x7e8d0000 0x0 0x1000>; - enable-bit-index = <3>; - }; - }; diff --git a/MAINTAINERS b/MAINTAINERS index 7969d09dff17..4e6fa336ff70 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1895,7 +1895,7 @@ APPLIED MICRO (APM) X-GENE SOC PMU M: Khuong Dinh S: Supported F: Documentation/admin-guide/perf/xgene-pmu.rst -F: Documentation/devicetree/bindings/perf/apm-xgene-pmu.txt +F: Documentation/devicetree/bindings/perf/apm,xgene-pmu.yaml F: drivers/perf/xgene_pmu.c APPLIED MICRO QT2025 PHY DRIVER From 326d2519811200da0e301dce3e93389dadd197a4 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Thu, 14 Aug 2025 08:51:56 -0500 Subject: [PATCH 01008/11391] dt-bindings: powerpc: Drop duplicate fsl/mpic.txt The chrp,open-pic binding schema already supports the "fsl,mpic" compatible. Add a couple of missing properties and support for 4 "#interrupt-cells" to the chrp,open-pic binding, so fsl/mpic.txt can be removed. Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20250814135157.2747346-2-robh@kernel.org Signed-off-by: Rob Herring (Arm) --- .../interrupt-controller/chrp,open-pic.yaml | 17 +- .../devicetree/bindings/powerpc/fsl/mpic.txt | 231 ------------------ 2 files changed, 16 insertions(+), 232 deletions(-) delete mode 100644 Documentation/devicetree/bindings/powerpc/fsl/mpic.txt diff --git a/Documentation/devicetree/bindings/interrupt-controller/chrp,open-pic.yaml b/Documentation/devicetree/bindings/interrupt-controller/chrp,open-pic.yaml index f0d9bbd7d510..642738512f3c 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/chrp,open-pic.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/chrp,open-pic.yaml @@ -36,12 +36,27 @@ properties: const: 0 '#interrupt-cells': - const: 2 + description: + A value of 4 means that interrupt specifiers contain the interrupt-type or + type-specific information cells. + enum: [ 2, 4 ] pic-no-reset: description: Indicates the PIC shall not be reset during runtime initialization. type: boolean + single-cpu-affinity: + description: + If present, non-IPI interrupts will be routed to a single CPU at a time. + type: boolean + + last-interrupt-source: + description: + Some MPICs do not correctly report the number of hardware sources in the + global feature registers. This value, if specified, overrides the value + read from MPIC_GREG_FEATURE_LAST_SRC. + $ref: /schemas/types.yaml#/definitions/uint32 + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt b/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt deleted file mode 100644 index dc5744636a57..000000000000 --- a/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt +++ /dev/null @@ -1,231 +0,0 @@ -===================================================================== -Freescale MPIC Interrupt Controller Node -Copyright (C) 2010,2011 Freescale Semiconductor Inc. -===================================================================== - -The Freescale MPIC interrupt controller is found on all PowerQUICC -and QorIQ processors and is compatible with the Open PIC. The -notable difference from Open PIC binding is the addition of 2 -additional cells in the interrupt specifier defining interrupt type -information. - -PROPERTIES - - - compatible - Usage: required - Value type: - Definition: Shall include "fsl,mpic". Freescale MPIC - controllers compatible with this binding have Block - Revision Registers BRR1 and BRR2 at offset 0x0 and - 0x10 in the MPIC. - - - reg - Usage: required - Value type: - Definition: A standard property. Specifies the physical - offset and length of the device's registers within the - CCSR address space. - - - interrupt-controller - Usage: required - Value type: - Definition: Specifies that this node is an interrupt - controller - - - #interrupt-cells - Usage: required - Value type: - Definition: Shall be 2 or 4. A value of 2 means that interrupt - specifiers do not contain the interrupt-type or type-specific - information cells. - - - #address-cells - Usage: required - Value type: - Definition: Shall be 0. - - - pic-no-reset - Usage: optional - Value type: - Definition: The presence of this property specifies that the - MPIC must not be reset by the client program, and that - the boot program has initialized all interrupt source - configuration registers to a sane state-- masked or - directed at other cores. This ensures that the client - program will not receive interrupts for sources not belonging - to the client. The presence of this property also mandates - that any initialization related to interrupt sources shall - be limited to sources explicitly referenced in the device tree. - - - big-endian - Usage: optional - Value type: - If present the MPIC will be assumed to be big-endian. Some - device-trees omit this property on MPIC nodes even when the MPIC is - in fact big-endian, so certain boards override this property. - - - single-cpu-affinity - Usage: optional - Value type: - If present the MPIC will be assumed to only be able to route - non-IPI interrupts to a single CPU at a time (EG: Freescale MPIC). - - - last-interrupt-source - Usage: optional - Value type: - Some MPICs do not correctly report the number of hardware sources - in the global feature registers. If specified, this field will - override the value read from MPIC_GREG_FEATURE_LAST_SRC. - -INTERRUPT SPECIFIER DEFINITION - - Interrupt specifiers consists of 4 cells encoded as - follows: - - <1st-cell> interrupt-number - - Identifies the interrupt source. The meaning - depends on the type of interrupt. - - Note: If the interrupt-type cell is undefined - (i.e. #interrupt-cells = 2), this cell - should be interpreted the same as for - interrupt-type 0-- i.e. an external or - normal SoC device interrupt. - - <2nd-cell> level-sense information, encoded as follows: - 0 = low-to-high edge triggered - 1 = active low level-sensitive - 2 = active high level-sensitive - 3 = high-to-low edge triggered - - <3rd-cell> interrupt-type - - The following types are supported: - - 0 = external or normal SoC device interrupt - - The interrupt-number cell contains - the SoC device interrupt number. The - type-specific cell is undefined. The - interrupt-number is derived from the - MPIC a block of registers referred to as - the "Interrupt Source Configuration Registers". - Each source has 32-bytes of registers - (vector/priority and destination) in this - region. So interrupt 0 is at offset 0x0, - interrupt 1 is at offset 0x20, and so on. - - 1 = error interrupt - - The interrupt-number cell contains - the SoC device interrupt number for - the error interrupt. The type-specific - cell identifies the specific error - interrupt number. - - 2 = MPIC inter-processor interrupt (IPI) - - The interrupt-number cell identifies - the MPIC IPI number. The type-specific - cell is undefined. - - 3 = MPIC timer interrupt - - The interrupt-number cell identifies - the MPIC timer number. The type-specific - cell is undefined. - - <4th-cell> type-specific information - - The type-specific cell is encoded as follows: - - - For interrupt-type 1 (error interrupt), - the type-specific cell contains the - bit number of the error interrupt in the - Error Interrupt Summary Register. - -EXAMPLE 1 - /* - * mpic interrupt controller with 4 cells per specifier - */ - mpic: pic@40000 { - compatible = "fsl,mpic"; - interrupt-controller; - #interrupt-cells = <4>; - #address-cells = <0>; - reg = <0x40000 0x40000>; - }; - -EXAMPLE 2 - /* - * The MPC8544 I2C controller node has an internal - * interrupt number of 27. As per the reference manual - * this corresponds to interrupt source configuration - * registers at 0x5_0560. - * - * The interrupt source configuration registers begin - * at 0x5_0000. - * - * To compute the interrupt specifier interrupt number - * - * 0x560 >> 5 = 43 - * - * The interrupt source configuration registers begin - * at 0x5_0000, and so the i2c vector/priority registers - * are at 0x5_0560. - */ - i2c@3000 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <0>; - compatible = "fsl-i2c"; - reg = <0x3000 0x100>; - interrupts = <43 2>; - interrupt-parent = <&mpic>; - dfsrr; - }; - - -EXAMPLE 3 - /* - * Definition of a node defining the 4 - * MPIC IPI interrupts. Note the interrupt - * type of 2. - */ - ipi@410a0 { - compatible = "fsl,mpic-ipi"; - reg = <0x40040 0x10>; - interrupts = <0 0 2 0 - 1 0 2 0 - 2 0 2 0 - 3 0 2 0>; - }; - -EXAMPLE 4 - /* - * Definition of a node defining the MPIC - * global timers. Note the interrupt - * type of 3. - */ - timer0: timer@41100 { - compatible = "fsl,mpic-global-timer"; - reg = <0x41100 0x100 0x41300 4>; - interrupts = <0 0 3 0 - 1 0 3 0 - 2 0 3 0 - 3 0 3 0>; - }; - -EXAMPLE 5 - /* - * Definition of an error interrupt (interrupt type 1). - * SoC interrupt number is 16 and the specific error - * interrupt bit in the error interrupt summary register - * is 23. - */ - memory-controller@8000 { - compatible = "fsl,p4080-memory-controller"; - reg = <0x8000 0x1000>; - interrupts = <16 2 1 23>; - }; From abdaf49be5424db74e19d167c10d7dad79a0efc2 Mon Sep 17 00:00:00 2001 From: Tao Chen Date: Thu, 14 Aug 2025 20:14:29 +0800 Subject: [PATCH 01009/11391] bpf: Remove migrate_disable in kprobe_multi_link_prog_run Graph tracer framework ensures we won't migrate, kprobe_multi_link_prog_run called all the way from graph tracer, which disables preemption in function_graph_enter_regs, as Jiri and Yonghong suggested, there is no need to use migrate_disable. As a result, some overhead may will be reduced. And add cant_sleep check for __this_cpu_inc_return. Fixes: 0dcac2725406 ("bpf: Add multi kprobe link") Signed-off-by: Tao Chen Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20250814121430.2347454-1-chen.dylane@linux.dev --- kernel/trace/bpf_trace.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 3ae52978cae6..606007c387c5 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -2728,20 +2728,25 @@ kprobe_multi_link_prog_run(struct bpf_kprobe_multi_link *link, struct pt_regs *regs; int err; + /* + * graph tracer framework ensures we won't migrate, so there is no need + * to use migrate_disable for bpf_prog_run again. The check here just for + * __this_cpu_inc_return. + */ + cant_sleep(); + if (unlikely(__this_cpu_inc_return(bpf_prog_active) != 1)) { bpf_prog_inc_misses_counter(link->link.prog); err = 1; goto out; } - migrate_disable(); rcu_read_lock(); regs = ftrace_partial_regs(fregs, bpf_kprobe_multi_pt_regs_ptr()); old_run_ctx = bpf_set_run_ctx(&run_ctx.session_ctx.run_ctx); err = bpf_prog_run(link->link.prog, regs); bpf_reset_run_ctx(old_run_ctx); rcu_read_unlock(); - migrate_enable(); out: __this_cpu_dec(bpf_prog_active); From 6c6b4146deb12d20f42490d5013f2043df942161 Mon Sep 17 00:00:00 2001 From: Yureka Lilian Date: Thu, 14 Aug 2025 20:01:12 +0200 Subject: [PATCH 01010/11391] libbpf: Fix reuse of DEVMAP Previously, re-using pinned DEVMAP maps would always fail, because get_map_info on a DEVMAP always returns flags with BPF_F_RDONLY_PROG set, but BPF_F_RDONLY_PROG being set on a map during creation is invalid. Thus, ignore the BPF_F_RDONLY_PROG flag in the flags returned from get_map_info when checking for compatibility with an existing DEVMAP. The same problem is handled in a third-party ebpf library: - https://github.com/cilium/ebpf/issues/925 - https://github.com/cilium/ebpf/pull/930 Fixes: 0cdbb4b09a06 ("devmap: Allow map lookups from eBPF") Signed-off-by: Yureka Lilian Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20250814180113.1245565-3-yuka@yuka.dev --- tools/lib/bpf/libbpf.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 8f5a81b672e1..fe4fc5438678 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -5093,6 +5093,16 @@ static bool map_is_reuse_compat(const struct bpf_map *map, int map_fd) return false; } + /* + * bpf_get_map_info_by_fd() for DEVMAP will always return flags with + * BPF_F_RDONLY_PROG set, but it generally is not set at map creation time. + * Thus, ignore the BPF_F_RDONLY_PROG flag in the flags returned from + * bpf_get_map_info_by_fd() when checking for compatibility with an + * existing DEVMAP. + */ + if (map->def.type == BPF_MAP_TYPE_DEVMAP || map->def.type == BPF_MAP_TYPE_DEVMAP_HASH) + map_info.map_flags &= ~BPF_F_RDONLY_PROG; + return (map_info.type == map->def.type && map_info.key_size == map->def.key_size && map_info.value_size == map->def.value_size && From 7f8fa9d370c11ba2fb296598267e14d3bfe4ea11 Mon Sep 17 00:00:00 2001 From: Yureka Lilian Date: Thu, 14 Aug 2025 20:01:13 +0200 Subject: [PATCH 01011/11391] selftests/bpf: Add test for DEVMAP reuse The test covers basic re-use of a pinned DEVMAP map, with both matching and mismatching parameters. Signed-off-by: Yureka Lilian Signed-off-by: Andrii Nakryiko Acked-by: Eduard Zingerman Link: https://lore.kernel.org/bpf/20250814180113.1245565-4-yuka@yuka.dev --- .../bpf/prog_tests/pinning_devmap_reuse.c | 50 +++++++++++++++++++ .../selftests/bpf/progs/test_pinning_devmap.c | 20 ++++++++ 2 files changed, 70 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/pinning_devmap_reuse.c create mode 100644 tools/testing/selftests/bpf/progs/test_pinning_devmap.c diff --git a/tools/testing/selftests/bpf/prog_tests/pinning_devmap_reuse.c b/tools/testing/selftests/bpf/prog_tests/pinning_devmap_reuse.c new file mode 100644 index 000000000000..9ae49b587f3e --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/pinning_devmap_reuse.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include + + +#include "test_pinning_devmap.skel.h" + +void test_pinning_devmap_reuse(void) +{ + const char *pinpath1 = "/sys/fs/bpf/pinmap1"; + const char *pinpath2 = "/sys/fs/bpf/pinmap2"; + struct test_pinning_devmap *skel1 = NULL, *skel2 = NULL; + int err; + DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts); + + /* load the object a first time */ + skel1 = test_pinning_devmap__open_and_load(); + if (!ASSERT_OK_PTR(skel1, "skel_load1")) + goto out; + + /* load the object a second time, re-using the pinned map */ + skel2 = test_pinning_devmap__open_and_load(); + if (!ASSERT_OK_PTR(skel2, "skel_load2")) + goto out; + + /* we can close the reference safely without + * the map's refcount falling to 0 + */ + test_pinning_devmap__destroy(skel1); + skel1 = NULL; + + /* now, swap the pins */ + err = renameat2(0, pinpath1, 0, pinpath2, RENAME_EXCHANGE); + if (!ASSERT_OK(err, "swap pins")) + goto out; + + /* load the object again, this time the re-use should fail */ + skel1 = test_pinning_devmap__open_and_load(); + if (!ASSERT_ERR_PTR(skel1, "skel_load3")) + goto out; + +out: + unlink(pinpath1); + unlink(pinpath2); + test_pinning_devmap__destroy(skel1); + test_pinning_devmap__destroy(skel2); +} diff --git a/tools/testing/selftests/bpf/progs/test_pinning_devmap.c b/tools/testing/selftests/bpf/progs/test_pinning_devmap.c new file mode 100644 index 000000000000..c855f8f87eff --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_pinning_devmap.c @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include + +struct { + __uint(type, BPF_MAP_TYPE_DEVMAP); + __uint(max_entries, 1); + __type(key, __u32); + __type(value, __u32); + __uint(pinning, LIBBPF_PIN_BY_NAME); +} pinmap1 SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_DEVMAP); + __uint(max_entries, 2); + __type(key, __u32); + __type(value, __u32); + __uint(pinning, LIBBPF_PIN_BY_NAME); +} pinmap2 SEC(".maps"); From 5ff74f5f71f83cce3c920cd17940df0fe0401865 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 15 Aug 2025 19:02:40 -0700 Subject: [PATCH 01012/11391] lib/crc: Drop inline from all *_mod_init_arch() functions Drop 'inline' from all the *_mod_init_arch() functions so that the compiler will warn about any bugs where they are unused due to not being wired up properly. (There are no such bugs currently, so this just establishes a more robust convention for the future. Of course, these functions also tend to get inlined anyway, regardless of the keyword.) Link: https://lore.kernel.org/r/20250816020240.431545-1-ebiggers@kernel.org Signed-off-by: Eric Biggers --- lib/crc/arm/crc-t10dif.h | 2 +- lib/crc/arm/crc32.h | 2 +- lib/crc/arm64/crc-t10dif.h | 2 +- lib/crc/loongarch/crc32.h | 2 +- lib/crc/mips/crc32.h | 2 +- lib/crc/powerpc/crc-t10dif.h | 2 +- lib/crc/powerpc/crc32.h | 2 +- lib/crc/sparc/crc32.h | 2 +- lib/crc/x86/crc-t10dif.h | 2 +- lib/crc/x86/crc32.h | 2 +- lib/crc/x86/crc64.h | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/crc/arm/crc-t10dif.h b/lib/crc/arm/crc-t10dif.h index 1a969f4024d4..63441de5e3f1 100644 --- a/lib/crc/arm/crc-t10dif.h +++ b/lib/crc/arm/crc-t10dif.h @@ -43,7 +43,7 @@ static inline u16 crc_t10dif_arch(u16 crc, const u8 *data, size_t length) } #define crc_t10dif_mod_init_arch crc_t10dif_mod_init_arch -static inline void crc_t10dif_mod_init_arch(void) +static void crc_t10dif_mod_init_arch(void) { if (elf_hwcap & HWCAP_NEON) { static_branch_enable(&have_neon); diff --git a/lib/crc/arm/crc32.h b/lib/crc/arm/crc32.h index ae71aa60b7a7..7b76f52f6907 100644 --- a/lib/crc/arm/crc32.h +++ b/lib/crc/arm/crc32.h @@ -83,7 +83,7 @@ static inline u32 crc32c_arch(u32 crc, const u8 *p, size_t len) #define crc32_be_arch crc32_be_base /* not implemented on this arch */ #define crc32_mod_init_arch crc32_mod_init_arch -static inline void crc32_mod_init_arch(void) +static void crc32_mod_init_arch(void) { if (elf_hwcap2 & HWCAP2_CRC32) static_branch_enable(&have_crc32); diff --git a/lib/crc/arm64/crc-t10dif.h b/lib/crc/arm64/crc-t10dif.h index 435a990ec43c..f88db2971805 100644 --- a/lib/crc/arm64/crc-t10dif.h +++ b/lib/crc/arm64/crc-t10dif.h @@ -45,7 +45,7 @@ static inline u16 crc_t10dif_arch(u16 crc, const u8 *data, size_t length) } #define crc_t10dif_mod_init_arch crc_t10dif_mod_init_arch -static inline void crc_t10dif_mod_init_arch(void) +static void crc_t10dif_mod_init_arch(void) { if (cpu_have_named_feature(ASIMD)) { static_branch_enable(&have_asimd); diff --git a/lib/crc/loongarch/crc32.h b/lib/crc/loongarch/crc32.h index 6de5c96594af..d34fa4c68632 100644 --- a/lib/crc/loongarch/crc32.h +++ b/lib/crc/loongarch/crc32.h @@ -101,7 +101,7 @@ static inline u32 crc32c_arch(u32 crc, const u8 *p, size_t len) #define crc32_be_arch crc32_be_base /* not implemented on this arch */ #define crc32_mod_init_arch crc32_mod_init_arch -static inline void crc32_mod_init_arch(void) +static void crc32_mod_init_arch(void) { if (cpu_has_crc32) static_branch_enable(&have_crc32); diff --git a/lib/crc/mips/crc32.h b/lib/crc/mips/crc32.h index 11cb272c63a6..3100354a049e 100644 --- a/lib/crc/mips/crc32.h +++ b/lib/crc/mips/crc32.h @@ -148,7 +148,7 @@ static inline u32 crc32c_arch(u32 crc, const u8 *p, size_t len) #define crc32_be_arch crc32_be_base /* not implemented on this arch */ #define crc32_mod_init_arch crc32_mod_init_arch -static inline void crc32_mod_init_arch(void) +static void crc32_mod_init_arch(void) { if (cpu_have_feature(cpu_feature(MIPS_CRC32))) static_branch_enable(&have_crc32); diff --git a/lib/crc/powerpc/crc-t10dif.h b/lib/crc/powerpc/crc-t10dif.h index e033d5f57bae..8f4592a5323d 100644 --- a/lib/crc/powerpc/crc-t10dif.h +++ b/lib/crc/powerpc/crc-t10dif.h @@ -62,7 +62,7 @@ static inline u16 crc_t10dif_arch(u16 crci, const u8 *p, size_t len) } #define crc_t10dif_mod_init_arch crc_t10dif_mod_init_arch -static inline void crc_t10dif_mod_init_arch(void) +static void crc_t10dif_mod_init_arch(void) { if (cpu_has_feature(CPU_FTR_ARCH_207S) && (cur_cpu_spec->cpu_user_features2 & PPC_FEATURE2_VEC_CRYPTO)) diff --git a/lib/crc/powerpc/crc32.h b/lib/crc/powerpc/crc32.h index cc8fa3913d4e..0c852272a382 100644 --- a/lib/crc/powerpc/crc32.h +++ b/lib/crc/powerpc/crc32.h @@ -55,7 +55,7 @@ static inline u32 crc32c_arch(u32 crc, const u8 *p, size_t len) } #define crc32_mod_init_arch crc32_mod_init_arch -static inline void crc32_mod_init_arch(void) +static void crc32_mod_init_arch(void) { if (cpu_has_feature(CPU_FTR_ARCH_207S) && (cur_cpu_spec->cpu_user_features2 & PPC_FEATURE2_VEC_CRYPTO)) diff --git a/lib/crc/sparc/crc32.h b/lib/crc/sparc/crc32.h index 60f2765ac015..df7c350acd7b 100644 --- a/lib/crc/sparc/crc32.h +++ b/lib/crc/sparc/crc32.h @@ -44,7 +44,7 @@ static inline u32 crc32c_arch(u32 crc, const u8 *data, size_t len) } #define crc32_mod_init_arch crc32_mod_init_arch -static inline void crc32_mod_init_arch(void) +static void crc32_mod_init_arch(void) { unsigned long cfr; diff --git a/lib/crc/x86/crc-t10dif.h b/lib/crc/x86/crc-t10dif.h index 2a02a3026f3f..8ee8824da551 100644 --- a/lib/crc/x86/crc-t10dif.h +++ b/lib/crc/x86/crc-t10dif.h @@ -19,7 +19,7 @@ static inline u16 crc_t10dif_arch(u16 crc, const u8 *p, size_t len) } #define crc_t10dif_mod_init_arch crc_t10dif_mod_init_arch -static inline void crc_t10dif_mod_init_arch(void) +static void crc_t10dif_mod_init_arch(void) { if (boot_cpu_has(X86_FEATURE_PCLMULQDQ)) { static_branch_enable(&have_pclmulqdq); diff --git a/lib/crc/x86/crc32.h b/lib/crc/x86/crc32.h index 2c4a5976654a..19a5e3c6c73b 100644 --- a/lib/crc/x86/crc32.h +++ b/lib/crc/x86/crc32.h @@ -106,7 +106,7 @@ static inline u32 crc32c_arch(u32 crc, const u8 *p, size_t len) #define crc32_be_arch crc32_be_base /* not implemented on this arch */ #define crc32_mod_init_arch crc32_mod_init_arch -static inline void crc32_mod_init_arch(void) +static void crc32_mod_init_arch(void) { if (boot_cpu_has(X86_FEATURE_XMM4_2)) static_branch_enable(&have_crc32); diff --git a/lib/crc/x86/crc64.h b/lib/crc/x86/crc64.h index fde1222c4c58..7d4599319343 100644 --- a/lib/crc/x86/crc64.h +++ b/lib/crc/x86/crc64.h @@ -27,7 +27,7 @@ static inline u64 crc64_nvme_arch(u64 crc, const u8 *p, size_t len) } #define crc64_mod_init_arch crc64_mod_init_arch -static inline void crc64_mod_init_arch(void) +static void crc64_mod_init_arch(void) { if (boot_cpu_has(X86_FEATURE_PCLMULQDQ)) { static_branch_enable(&have_pclmulqdq); From 450bbe43ef90a213d66fac1def64050d9d9ada8e Mon Sep 17 00:00:00 2001 From: Ashish Kalra Date: Mon, 21 Jul 2025 14:12:32 +0000 Subject: [PATCH 01013/11391] 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 01014/11391] 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 01015/11391] 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 01016/11391] 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 01017/11391] 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 01018/11391] 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 01019/11391] 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 01020/11391] 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 01021/11391] 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 01022/11391] 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 01023/11391] 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 01024/11391] 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 01025/11391] 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 01026/11391] 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 01027/11391] 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 01028/11391] 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 01029/11391] 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 01030/11391] 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 01031/11391] 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 01032/11391] 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 01033/11391] 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 @@ static int sx9500_write_event_config(struct iio_dev *indio_dev, 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 01034/11391] 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 01035/11391] 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 01036/11391] 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 01037/11391] 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 01038/11391] 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 01039/11391] 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 01040/11391] 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 01041/11391] 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 01042/11391] 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 01043/11391] 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 @@ static int adc12138_probe(struct spi_device *spi) 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 01044/11391] 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 01045/11391] 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 01046/11391] 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 01047/11391] 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 01048/11391] 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 01049/11391] 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 01050/11391] 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 01051/11391] 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 01052/11391] 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 01053/11391] 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 01054/11391] 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 01055/11391] 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 01056/11391] 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 01057/11391] 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 01058/11391] 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 01059/11391] 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 01060/11391] 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 01061/11391] 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 01062/11391] 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 01063/11391] 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 01064/11391] 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 01065/11391] 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 01066/11391] 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 01067/11391] 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 01068/11391] 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 01069/11391] 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 01070/11391] 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 01071/11391] 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 01072/11391] 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 01073/11391] 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 01074/11391] 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 01075/11391] 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 01076/11391] 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 01077/11391] 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 01078/11391] 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 01079/11391] 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 01080/11391] 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 01081/11391] 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 01082/11391] 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 01083/11391] 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 01084/11391] 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 01085/11391] 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 01086/11391] 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 01087/11391] 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 01088/11391] 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 01089/11391] 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 01090/11391] 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 01091/11391] 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 01092/11391] 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 01093/11391] 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 01094/11391] 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 01095/11391] 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 01096/11391] 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 01097/11391] 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 487fe3a936b0b84ef09fa324b4c01d059886f951 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 14 Aug 2025 18:31:39 -0700 Subject: [PATCH 01098/11391] x86/build: Clean up stack alignment flags in CC_FLAGS_FPU The minimum supported version of GCC to build the x86 kernel was bumped to GCC 8.1 in a3e8fe814ad1 ("x86/build: Raise the minimum GCC version to 8.1"). Prior to GCC 7.1, '-mpreferred-stack-boundary=3' was not allowed with '-msse', so areas of the kernel that needed floating point had a different alignment. Now that GCC > 7.1 is mandatory, there is no need to have a different value of '-mpreferred-stack-boundary' from the rest of the kernel, so remove this handling from CC_FLAGS_FPU. Signed-off-by: Nathan Chancellor Signed-off-by: Borislav Petkov (AMD) Link: https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=34fac449e121be97dd073c5428cc855367b2872c Link: https://lore.kernel.org/20250814-x86-min-ver-cleanups-v1-3-ff7f19457523@kernel.org --- arch/x86/Makefile | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/arch/x86/Makefile b/arch/x86/Makefile index f0aa58d2ec17..0c82a610fb54 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -84,19 +84,7 @@ KBUILD_RUSTFLAGS += -Ctarget-feature=-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-av # CC_FLAGS_FPU := -msse -msse2 ifdef CONFIG_CC_IS_GCC -# Stack alignment mismatch, proceed with caution. -# GCC < 7.1 cannot compile code using `double` and -mpreferred-stack-boundary=3 -# (8B stack alignment). -# See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53383 -# -# The "-msse" in the first argument is there so that the -# -mpreferred-stack-boundary=3 build error: -# -# -mpreferred-stack-boundary=3 is not between 4 and 12 -# -# can be triggered. Otherwise gcc doesn't complain. CC_FLAGS_FPU += -mhard-float -CC_FLAGS_FPU += $(call cc-option,-msse -mpreferred-stack-boundary=3,-mpreferred-stack-boundary=4) endif ifeq ($(CONFIG_X86_KERNEL_IBT),y) From 0a42d732c136d3466cd19fafa7317d3004430318 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 14 Aug 2025 18:31:40 -0700 Subject: [PATCH 01099/11391] x86/build: Remove cc-option from -mno-fp-ret-in-387 This has been supported in GCC for forever and clang gained support for it as an alias of '-mno-x87' in LLVM 14. Now that x86 requires LLVM 15 or newer since 7861640aac52 ("x86/build: Raise the minimum LLVM version to 15.0.0"), this flag can be unconditionally added, saving a compiler invocation. Signed-off-by: Nathan Chancellor Signed-off-by: Borislav Petkov (AMD) Link: https://github.com/llvm/llvm-project/commit/a9fba2be35db674971382e38b99a31403444d9bf Link: https://lore.kernel.org/20250814-x86-min-ver-cleanups-v1-4-ff7f19457523@kernel.org --- arch/x86/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 0c82a610fb54..1bbf943fe9e1 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -148,7 +148,7 @@ else # Don't autogenerate traditional x87 instructions KBUILD_CFLAGS += -mno-80387 - KBUILD_CFLAGS += $(call cc-option,-mno-fp-ret-in-387) + KBUILD_CFLAGS += -mno-fp-ret-in-387 # By default gcc and clang use a stack alignment of 16 bytes for x86. # However the standard kernel entry on x86-64 leaves the stack on an From 1201f6fb5bfdbd10985ac3c8f49ef8f4f88b5c94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Thu, 31 Jul 2025 10:00:31 +0200 Subject: [PATCH 01100/11391] tools/nolibc: fix error return value of clock_nanosleep() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit clock_nanosleep() returns a positive error value. Unlike other libc functions it *does not* return -1 nor set errno. Fix the return value and also adapt nanosleep(). Fixes: 7c02bc4088af ("tools/nolibc: add support for clock_nanosleep() and nanosleep()") Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://lore.kernel.org/r/20250731-nolibc-clock_nanosleep-ret-v1-1-9e4af7855e61@linutronix.de Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/time.h | 5 +++-- tools/testing/selftests/nolibc/nolibc-test.c | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/include/nolibc/time.h b/tools/include/nolibc/time.h index d02bc44d2643..e9c1b976791a 100644 --- a/tools/include/nolibc/time.h +++ b/tools/include/nolibc/time.h @@ -133,7 +133,8 @@ static __attribute__((unused)) int clock_nanosleep(clockid_t clockid, int flags, const struct timespec *rqtp, struct timespec *rmtp) { - return __sysret(sys_clock_nanosleep(clockid, flags, rqtp, rmtp)); + /* Directly return a positive error number */ + return -sys_clock_nanosleep(clockid, flags, rqtp, rmtp); } static __inline__ @@ -145,7 +146,7 @@ double difftime(time_t time1, time_t time2) static __inline__ int nanosleep(const struct timespec *rqtp, struct timespec *rmtp) { - return clock_nanosleep(CLOCK_REALTIME, 0, rqtp, rmtp); + return __sysret(sys_clock_nanosleep(CLOCK_REALTIME, 0, rqtp, rmtp)); } diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index a297ee0d6d07..cc4d730ac465 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1334,6 +1334,7 @@ int run_syscall(int min, int max) CASE_TEST(chroot_root); EXPECT_SYSZR(euid0, chroot("/")); break; CASE_TEST(chroot_blah); EXPECT_SYSER(1, chroot("/proc/self/blah"), -1, ENOENT); break; CASE_TEST(chroot_exe); EXPECT_SYSER(1, chroot(argv0), -1, ENOTDIR); break; + CASE_TEST(clock_nanosleep); ts.tv_nsec = -1; EXPECT_EQ(1, EINVAL, clock_nanosleep(CLOCK_REALTIME, 0, &ts, NULL)); break; CASE_TEST(close_m1); EXPECT_SYSER(1, close(-1), -1, EBADF); break; CASE_TEST(close_dup); EXPECT_SYSZR(1, close(dup(0))); break; CASE_TEST(dup_0); tmp = dup(0); EXPECT_SYSNE(1, tmp, -1); close(tmp); break; From c851b71fd6cdbf3000bf0a2354592a0f09db3ba3 Mon Sep 17 00:00:00 2001 From: Venkat Jayaraman Date: Thu, 14 Aug 2025 09:30:28 -0700 Subject: [PATCH 01101/11391] 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 01102/11391] 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 01103/11391] 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 337927d9895a800a63ffe852616ab05f5d304971 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 14 Aug 2025 18:31:41 -0700 Subject: [PATCH 01104/11391] x86/build: Remove cc-option from -mskip-rax-setup This has been supported in GCC since 5.1 and clang since 14.0. Now that x86 requires LLVM 15 or newer since 7861640aac52 ("x86/build: Raise the minimum LLVM version to 15.0.0"), this flag can be unconditionally added, saving a compiler invocation. Signed-off-by: Nathan Chancellor Signed-off-by: Borislav Petkov (AMD) Link: https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=fbe575b652f5bdcc459f447a0e6f0e059996d4ef Link: https://github.com/llvm/llvm-project/commit/a9fba2be35db674971382e38b99a31403444d9bf Link: https://lore.kernel.org/20250814-x86-min-ver-cleanups-v1-5-ff7f19457523@kernel.org --- arch/x86/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 1bbf943fe9e1..4b4e2a3ac6df 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -160,7 +160,7 @@ else KBUILD_CFLAGS += $(cc_stack_align8) # Use -mskip-rax-setup if supported. - KBUILD_CFLAGS += $(call cc-option,-mskip-rax-setup) + KBUILD_CFLAGS += -mskip-rax-setup ifdef CONFIG_X86_NATIVE_CPU KBUILD_CFLAGS += -march=native From 4847d1187402a5027d9a04393f12d52a5a1d7f98 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Thu, 14 Aug 2025 09:24:41 +0200 Subject: [PATCH 01105/11391] 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 01106/11391] 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 01107/11391] 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 01108/11391] 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 01109/11391] 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 @@ static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty) 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 01110/11391] 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 01111/11391] 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 01112/11391] 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 01113/11391] 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 01114/11391] 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 01115/11391] 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 01116/11391] 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 01117/11391] 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 01118/11391] 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 01119/11391] 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 @@ static int do_con_write(struct tty_struct *tty, const u8 *buf, int count) con_flush(vc, &draw); console_conditional_schedule(); notify_update(vc); - console_unlock(); + return n; } @@ -3199,7 +3195,7 @@ static int do_con_write(struct tty_struct *tty, const u8 *buf, int count) */ 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 01120/11391] 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 2c6a28f3ef729ed2d5b174b4e0f33172fb286bab Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 14 Aug 2025 18:31:42 -0700 Subject: [PATCH 01121/11391] x86/Kconfig: Clean up LLVM version checks in IBT configurations The minimum supported version of LLVM for building the x86 kernel was bumped to 15.0.0 in 7861640aac52 ("x86/build: Raise the minimum LLVM version to 15.0.0"), so the checks for Clang 14.0.0 and ld.lld 14.0.0 or newer will always been true. Clean them up. Signed-off-by: Nathan Chancellor Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/20250814-x86-min-ver-cleanups-v1-6-ff7f19457523@kernel.org --- arch/x86/Kconfig | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 58d890fe2100..85b91267c01c 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1753,11 +1753,7 @@ config X86_UMIP config CC_HAS_IBT # GCC >= 9 and binutils >= 2.29 # Retpoline check to work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93654 - # Clang/LLVM >= 14 - # https://github.com/llvm/llvm-project/commit/e0b89df2e0f0130881bf6c39bf31d7f6aac00e0f - # https://github.com/llvm/llvm-project/commit/dfcf69770bc522b9e411c66454934a37c1f35332 - def_bool ((CC_IS_GCC && $(cc-option, -fcf-protection=branch -mindirect-branch-register)) || \ - (CC_IS_CLANG && CLANG_VERSION >= 140000)) && \ + def_bool ((CC_IS_GCC && $(cc-option, -fcf-protection=branch -mindirect-branch-register)) || CC_IS_CLANG) && \ $(as-instr,endbr64) config X86_CET @@ -1769,8 +1765,6 @@ config X86_KERNEL_IBT prompt "Indirect Branch Tracking" def_bool y depends on X86_64 && CC_HAS_IBT && HAVE_OBJTOOL - # https://github.com/llvm/llvm-project/commit/9d7001eba9c4cb311e03cd8cdc231f9e579f2d0f - depends on !LD_IS_LLD || LLD_VERSION >= 140000 select OBJTOOL select X86_CET help From 292cb391479d50f4379a0abab34324de92c82a92 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 13 Aug 2025 23:03:52 -0700 Subject: [PATCH 01122/11391] software node: Constify node_group in registration functions The software_node_register_node_group() and software_node_unregister_node_group() functions take in essence an array of pointers to software_node structs. Since the functions do not modify the array declare the argument as constant, so that static arrays can be declared as const and annotated as __initconst. Signed-off-by: Dmitry Torokhov Link: https://lore.kernel.org/r/2zny5grbgtwbplynxffxg6dkgjgqf45aigwmgxio5stesdr3wi@gf2zamk5amic Signed-off-by: Greg Kroah-Hartman --- drivers/base/swnode.c | 5 ++--- include/linux/property.h | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c index deda7f35a059..be1e9e61a7bf 100644 --- a/drivers/base/swnode.c +++ b/drivers/base/swnode.c @@ -844,7 +844,7 @@ swnode_register(const struct software_node *node, struct swnode *parent, * of this function or by ordering the array such that parent comes before * child. */ -int software_node_register_node_group(const struct software_node **node_group) +int software_node_register_node_group(const struct software_node * const *node_group) { unsigned int i; int ret; @@ -877,8 +877,7 @@ EXPORT_SYMBOL_GPL(software_node_register_node_group); * remove the nodes individually, in the correct order (child before * parent). */ -void software_node_unregister_node_group( - const struct software_node **node_group) +void software_node_unregister_node_group(const struct software_node * const *node_group) { unsigned int i = 0; diff --git a/include/linux/property.h b/include/linux/property.h index 82f0cb3abd1e..d1e80b3c9918 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -574,8 +574,8 @@ const struct software_node * software_node_find_by_name(const struct software_node *parent, const char *name); -int software_node_register_node_group(const struct software_node **node_group); -void software_node_unregister_node_group(const struct software_node **node_group); +int software_node_register_node_group(const struct software_node * const *node_group); +void software_node_unregister_node_group(const struct software_node * const *node_group); int software_node_register(const struct software_node *node); void software_node_unregister(const struct software_node *node); From 35e3d0cd8e89d811b915593cbd8d9891d21d4a1a Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Sat, 16 Aug 2025 20:05:09 +0800 Subject: [PATCH 01123/11391] 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 01124/11391] 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 287066b295051729fb08c3cff12ae17c6fe66133 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 27 Jun 2025 15:49:48 +0200 Subject: [PATCH 01125/11391] ARM: dts: renesas: porter: Fix CAN pin group According to the schematics, the CAN transceiver is connected to pins GP7_3 and GP7_4, which correspond to CAN0 data group B. Fixes: 0768fbad7fba1d27 ("ARM: shmobile: porter: add CAN0 DT support") Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/70ad9bc44d6cea92197c42eedcad6b3d0641d26a.1751032025.git.geert+renesas@glider.be --- arch/arm/boot/dts/renesas/r8a7791-porter.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/renesas/r8a7791-porter.dts b/arch/arm/boot/dts/renesas/r8a7791-porter.dts index f518eadd8b9c..81b3c5d74e9b 100644 --- a/arch/arm/boot/dts/renesas/r8a7791-porter.dts +++ b/arch/arm/boot/dts/renesas/r8a7791-porter.dts @@ -289,7 +289,7 @@ vin0_pins: vin0 { }; can0_pins: can0 { - groups = "can0_data"; + groups = "can0_data_b"; function = "can0"; }; From c222f860910f82fad2d63d8608f922e9704866c0 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 13 Aug 2025 15:37:03 +0200 Subject: [PATCH 01126/11391] arm64: dts: renesas: rcar-gen3: Increase CANFD clock rates Currently, all R-Car Gen3 .dtsi files configure the CANFD core clocks to 40 MHz, which limits CAN-FD data transfer rates to 4 Mbps. However, all R-Car Gen3 SoCs except for R-Car D3 support CANFD clock rates up to 80 MHz. Now the R-Car CAN-FD driver has gained support for Transceiver Delay Compensation, increase all appropriate CANFD clock rates to the documented maximum, to support data rates up to 8 Mbps. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/d1ca3cd184193084b6de4332d47d0aee1923f6a6.1755090456.git.geert+renesas@glider.be --- arch/arm64/boot/dts/renesas/r8a77951.dtsi | 2 +- arch/arm64/boot/dts/renesas/r8a77960.dtsi | 2 +- arch/arm64/boot/dts/renesas/r8a77961.dtsi | 2 +- arch/arm64/boot/dts/renesas/r8a77965.dtsi | 2 +- arch/arm64/boot/dts/renesas/r8a77970.dtsi | 2 +- arch/arm64/boot/dts/renesas/r8a77980.dtsi | 2 +- arch/arm64/boot/dts/renesas/r8a77990.dtsi | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/arm64/boot/dts/renesas/r8a77951.dtsi b/arch/arm64/boot/dts/renesas/r8a77951.dtsi index 6ee9cdeb5a3a..c389ebc7e6ce 100644 --- a/arch/arm64/boot/dts/renesas/r8a77951.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77951.dtsi @@ -1373,7 +1373,7 @@ canfd: can@e66c0000 { <&can_clk>; clock-names = "fck", "canfd", "can_clk"; assigned-clocks = <&cpg CPG_CORE R8A7795_CLK_CANFD>; - assigned-clock-rates = <40000000>; + assigned-clock-rates = <80000000>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; resets = <&cpg 914>; status = "disabled"; diff --git a/arch/arm64/boot/dts/renesas/r8a77960.dtsi b/arch/arm64/boot/dts/renesas/r8a77960.dtsi index a323ac47ca70..6d039019905d 100644 --- a/arch/arm64/boot/dts/renesas/r8a77960.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77960.dtsi @@ -1245,7 +1245,7 @@ canfd: can@e66c0000 { <&can_clk>; clock-names = "fck", "canfd", "can_clk"; assigned-clocks = <&cpg CPG_CORE R8A7796_CLK_CANFD>; - assigned-clock-rates = <40000000>; + assigned-clock-rates = <80000000>; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; resets = <&cpg 914>; status = "disabled"; diff --git a/arch/arm64/boot/dts/renesas/r8a77961.dtsi b/arch/arm64/boot/dts/renesas/r8a77961.dtsi index 49f6d31c5903..1637b534fc68 100644 --- a/arch/arm64/boot/dts/renesas/r8a77961.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77961.dtsi @@ -1245,7 +1245,7 @@ canfd: can@e66c0000 { <&can_clk>; clock-names = "fck", "canfd", "can_clk"; assigned-clocks = <&cpg CPG_CORE R8A77961_CLK_CANFD>; - assigned-clock-rates = <40000000>; + assigned-clock-rates = <80000000>; power-domains = <&sysc R8A77961_PD_ALWAYS_ON>; resets = <&cpg 914>; status = "disabled"; diff --git a/arch/arm64/boot/dts/renesas/r8a77965.dtsi b/arch/arm64/boot/dts/renesas/r8a77965.dtsi index 136a22ca50b7..353a77187089 100644 --- a/arch/arm64/boot/dts/renesas/r8a77965.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77965.dtsi @@ -1108,7 +1108,7 @@ canfd: can@e66c0000 { <&can_clk>; clock-names = "fck", "canfd", "can_clk"; assigned-clocks = <&cpg CPG_CORE R8A77965_CLK_CANFD>; - assigned-clock-rates = <40000000>; + assigned-clock-rates = <80000000>; power-domains = <&sysc R8A77965_PD_ALWAYS_ON>; resets = <&cpg 914>; status = "disabled"; diff --git a/arch/arm64/boot/dts/renesas/r8a77970.dtsi b/arch/arm64/boot/dts/renesas/r8a77970.dtsi index 01744496805c..e7a5800bf742 100644 --- a/arch/arm64/boot/dts/renesas/r8a77970.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77970.dtsi @@ -568,7 +568,7 @@ canfd: can@e66c0000 { <&can_clk>; clock-names = "fck", "canfd", "can_clk"; assigned-clocks = <&cpg CPG_CORE R8A77970_CLK_CANFD>; - assigned-clock-rates = <40000000>; + assigned-clock-rates = <80000000>; power-domains = <&sysc R8A77970_PD_ALWAYS_ON>; resets = <&cpg 914>; status = "disabled"; diff --git a/arch/arm64/boot/dts/renesas/r8a77980.dtsi b/arch/arm64/boot/dts/renesas/r8a77980.dtsi index f7e506ad7a21..964aa14f3e65 100644 --- a/arch/arm64/boot/dts/renesas/r8a77980.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77980.dtsi @@ -621,7 +621,7 @@ canfd: can@e66c0000 { <&can_clk>; clock-names = "fck", "canfd", "can_clk"; assigned-clocks = <&cpg CPG_CORE R8A77980_CLK_CANFD>; - assigned-clock-rates = <40000000>; + assigned-clock-rates = <80000000>; power-domains = <&sysc R8A77980_PD_ALWAYS_ON>; resets = <&cpg 914>; status = "disabled"; diff --git a/arch/arm64/boot/dts/renesas/r8a77990.dtsi b/arch/arm64/boot/dts/renesas/r8a77990.dtsi index 6b8742045836..e16ede6eb379 100644 --- a/arch/arm64/boot/dts/renesas/r8a77990.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77990.dtsi @@ -1061,7 +1061,7 @@ canfd: can@e66c0000 { <&can_clk>; clock-names = "fck", "canfd", "can_clk"; assigned-clocks = <&cpg CPG_CORE R8A77990_CLK_CANFD>; - assigned-clock-rates = <40000000>; + assigned-clock-rates = <80000000>; power-domains = <&sysc R8A77990_PD_ALWAYS_ON>; resets = <&cpg 914>; status = "disabled"; From 57875e1526987524efe5001ad6d198a4b145f54f Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 13 Aug 2025 15:37:04 +0200 Subject: [PATCH 01127/11391] arm64: dts: renesas: rzg2: Increase CANFD clock rates Currently, all RZ/G2 .dtsi files configure the CANFD core clocks to 40 MHz, which limits CAN-FD data transfer rates to 4 Mbps. However, all RZ/G2 SoCs support CANFD clock rates up to 80 MHz. Now the R-Car CAN-FD driver has gained support for Transceiver Delay Compensation, increase all appropriate CANFD clock rates to the documented maximum, to support data rates up to 8 Mbps. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/0dd1c17135707587e9e9d6d68b2eaa1921fbcb7a.1755090456.git.geert+renesas@glider.be --- arch/arm64/boot/dts/renesas/r8a774a1.dtsi | 2 +- arch/arm64/boot/dts/renesas/r8a774b1.dtsi | 2 +- arch/arm64/boot/dts/renesas/r8a774c0.dtsi | 2 +- arch/arm64/boot/dts/renesas/r8a774e1.dtsi | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/renesas/r8a774a1.dtsi b/arch/arm64/boot/dts/renesas/r8a774a1.dtsi index c8b87aed92a3..6b737d91b320 100644 --- a/arch/arm64/boot/dts/renesas/r8a774a1.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a774a1.dtsi @@ -1186,7 +1186,7 @@ canfd: can@e66c0000 { <&can_clk>; clock-names = "fck", "canfd", "can_clk"; assigned-clocks = <&cpg CPG_CORE R8A774A1_CLK_CANFD>; - assigned-clock-rates = <40000000>; + assigned-clock-rates = <80000000>; power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>; resets = <&cpg 914>; status = "disabled"; diff --git a/arch/arm64/boot/dts/renesas/r8a774b1.dtsi b/arch/arm64/boot/dts/renesas/r8a774b1.dtsi index f2fc2a2035a1..3f15d656215e 100644 --- a/arch/arm64/boot/dts/renesas/r8a774b1.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a774b1.dtsi @@ -1070,7 +1070,7 @@ canfd: can@e66c0000 { <&can_clk>; clock-names = "fck", "canfd", "can_clk"; assigned-clocks = <&cpg CPG_CORE R8A774B1_CLK_CANFD>; - assigned-clock-rates = <40000000>; + assigned-clock-rates = <80000000>; power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>; resets = <&cpg 914>; status = "disabled"; diff --git a/arch/arm64/boot/dts/renesas/r8a774c0.dtsi b/arch/arm64/boot/dts/renesas/r8a774c0.dtsi index 530ffd29cf13..55df063cb323 100644 --- a/arch/arm64/boot/dts/renesas/r8a774c0.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a774c0.dtsi @@ -1029,7 +1029,7 @@ canfd: can@e66c0000 { <&can_clk>; clock-names = "fck", "canfd", "can_clk"; assigned-clocks = <&cpg CPG_CORE R8A774C0_CLK_CANFD>; - assigned-clock-rates = <40000000>; + assigned-clock-rates = <80000000>; power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>; resets = <&cpg 914>; status = "disabled"; diff --git a/arch/arm64/boot/dts/renesas/r8a774e1.dtsi b/arch/arm64/boot/dts/renesas/r8a774e1.dtsi index e4dbda8c34d9..5d730b488d46 100644 --- a/arch/arm64/boot/dts/renesas/r8a774e1.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a774e1.dtsi @@ -1298,7 +1298,7 @@ canfd: can@e66c0000 { <&can_clk>; clock-names = "fck", "canfd", "can_clk"; assigned-clocks = <&cpg CPG_CORE R8A774E1_CLK_CANFD>; - assigned-clock-rates = <40000000>; + assigned-clock-rates = <80000000>; power-domains = <&sysc R8A774E1_PD_ALWAYS_ON>; resets = <&cpg 914>; status = "disabled"; From 9471de64c9cc15a74e11eaa0c6156fe866ec11c3 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 15 Aug 2025 01:34:57 +0200 Subject: [PATCH 01128/11391] arm64: dts: renesas: sparrow-hawk: Update thermal trip points MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the Sparrow Hawk has a smaller PCB than the White Hawk, it tends to generate more heat. To prevent potential damage to the board, adjust the temperature trip points. Add four "passive" trip points which increasingly throttle the CPU to prevent overheating. The first trip point at 68°C disables the 1.8 GHz and 1.7 GHz modes and limits the CPU to 1.5 GHz frequency. The second trip point at 72°C disables the 1.5 GHz mode and limits the CPU to 1.0 GHz frequency. The third trip point at 76°C uses thermal-idle to start inserting idle cycles into the CPU instruction stream to cool the CPU cores down. The fourth and last trip point at 80°C disables the 1.0 GHz mode and limits the CPU to 500 MHz frequency. In case the SoC heats up further, in case either of the thermal sensors readings passes the 100°C, a thermal shutdown is triggered to prevent any damage to the hardware. Reviewed-by: Geert Uytterhoeven Reviewed-by: Niklas Söderlund Signed-off-by: Marek Vasut Link: https://lore.kernel.org/20250814233529.191874-1-marek.vasut+renesas@mailbox.org Signed-off-by: Geert Uytterhoeven --- .../dts/renesas/r8a779g3-sparrow-hawk.dts | 137 ++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts b/arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts index 1f44005e1a11..75b1b789ae1d 100644 --- a/arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts +++ b/arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts @@ -38,6 +38,7 @@ /dts-v1/; #include +#include #include "r8a779g3.dtsi" @@ -189,6 +190,41 @@ vcc_sdhi: regulator-vcc-sdhi { }; }; +/* Use thermal-idle cooling for all SoC cores */ +&a76_0 { + #cooling-cells = <2>; + + a76_0_thermal_idle: thermal-idle { + #cooling-cells = <2>; + duration-us = <10000>; + exit-latency-us = <500>; + }; +}; + +&a76_1 { + a76_1_thermal_idle: thermal-idle { + #cooling-cells = <2>; + duration-us = <10000>; + exit-latency-us = <500>; + }; +}; + +&a76_2 { + a76_2_thermal_idle: thermal-idle { + #cooling-cells = <2>; + duration-us = <10000>; + exit-latency-us = <500>; + }; +}; + +&a76_3 { + a76_3_thermal_idle: thermal-idle { + #cooling-cells = <2>; + duration-us = <10000>; + exit-latency-us = <500>; + }; +}; + &audio_clkin { clock-frequency = <24576000>; }; @@ -801,3 +837,104 @@ &rwdt { &scif_clk { /* X12 */ clock-frequency = <24000000>; }; + +/* THS sensors in SoC, critical temperature trip point is 100C */ +&sensor1_crit { + temperature = <100000>; +}; + +&sensor2_crit { + temperature = <100000>; +}; + +&sensor3_crit { + temperature = <100000>; +}; + +&sensor4_crit { + temperature = <100000>; +}; + +/* THS sensor in SoC near CA76 cores does more progressive cooling. */ +&sensor_thermal_ca76 { + critical-action = "shutdown"; + + cooling-maps { + /* + * The cooling-device minimum and maximum parameters inversely + * match opp-table-0 {} node entries in r8a779g0.dtsi, in other + * words, 0 refers to 1.8 GHz OPP and 4 refers to 500 MHz OPP. + * This is because they refer to cooling levels, where maximum + * cooling level happens at 500 MHz OPP, when the CPU core is + * running slowly and therefore generates least heat. + */ + map0 { + /* At 68C, inhibit 1.7 GHz and 1.8 GHz modes */ + trip = <&sensor3_passive_low>; + cooling-device = <&a76_0 2 4>; + contribution = <128>; + }; + + map1 { + /* At 72C, inhibit 1.5 GHz mode */ + trip = <&sensor3_passive_mid>; + cooling-device = <&a76_0 3 4>; + contribution = <256>; + }; + + map2 { + /* At 76C, start injecting idle states 0..80% of time */ + trip = <&sensor3_passive_hi>; + cooling-device = <&a76_0_thermal_idle 0 80>, + <&a76_1_thermal_idle 0 80>, + <&a76_2_thermal_idle 0 80>, + <&a76_3_thermal_idle 0 80>; + contribution = <512>; + }; + + map3 { + /* At 80C, inhibit 1.0 GHz mode */ + trip = <&sensor3_passive_crit>; + cooling-device = <&a76_0 4 4>; + contribution = <1024>; + }; + }; + + trips { + sensor3_passive_low: sensor3-passive-low { + temperature = <68000>; + hysteresis = <2000>; + type = "passive"; + }; + + sensor3_passive_mid: sensor3-passive-mid { + temperature = <72000>; + hysteresis = <2000>; + type = "passive"; + }; + + sensor3_passive_hi: sensor3-passive-hi { + temperature = <76000>; + hysteresis = <2000>; + type = "passive"; + }; + + sensor3_passive_crit: sensor3-passive-crit { + temperature = <80000>; + hysteresis = <2000>; + type = "passive"; + }; + }; +}; + +&sensor_thermal_cnn { + critical-action = "shutdown"; +}; + +&sensor_thermal_cr52 { + critical-action = "shutdown"; +}; + +&sensor_thermal_ddr1 { + critical-action = "shutdown"; +}; From f63aaf6e71de897954fbde4e4a17a9dcdbe5e7e1 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 13 Aug 2025 10:20:22 +0200 Subject: [PATCH 01129/11391] clk: renesas: mstp: Add genpd OF provider at postcore_initcall() Genpd OF providers must now be registered after genpd bus registration. However, cpg_mstp_add_clk_domain() is only called from CLK_OF_DECLARE(), which is too early. Hence on R-Car M1A, R-Car H1, and RZ/A1, the CPG/MSTP Clock Domain fails to register, and any devices residing in that clock domain fail to probe. Fix this by splitting initialization into two steps: - The first part keeps on registering the PM domain with genpd at CLK_OF_DECLARE(), - The second and new part moves the registration of the genpd OF provider to a postcore_initcall(). See also commit c5ae5a0c61120d0c ("pmdomain: renesas: rcar-sysc: Add genpd OF provider at postcore_initcall"). Fixes: 18a3a510ecfd0e50 ("pmdomain: core: Add the genpd->dev to the genpd provider bus") Signed-off-by: Geert Uytterhoeven Reviewed-by: Ulf Hansson Link: https://lore.kernel.org/81ef5f8d5d31374b7852b05453c52d2f735062a2.1755073087.git.geert+renesas@glider.be --- drivers/clk/renesas/clk-mstp.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/clk/renesas/clk-mstp.c b/drivers/clk/renesas/clk-mstp.c index 5bc473c2adb3..2f65fe2c6bdf 100644 --- a/drivers/clk/renesas/clk-mstp.c +++ b/drivers/clk/renesas/clk-mstp.c @@ -303,6 +303,9 @@ void cpg_mstp_detach_dev(struct generic_pm_domain *unused, struct device *dev) pm_clk_destroy(dev); } +static struct device_node *cpg_mstp_pd_np __initdata = NULL; +static struct generic_pm_domain *cpg_mstp_pd_genpd __initdata = NULL; + void __init cpg_mstp_add_clk_domain(struct device_node *np) { struct generic_pm_domain *pd; @@ -324,5 +327,20 @@ void __init cpg_mstp_add_clk_domain(struct device_node *np) pd->detach_dev = cpg_mstp_detach_dev; pm_genpd_init(pd, &pm_domain_always_on_gov, false); - of_genpd_add_provider_simple(np, pd); + cpg_mstp_pd_np = of_node_get(np); + cpg_mstp_pd_genpd = pd; } + +static int __init cpg_mstp_pd_init_provider(void) +{ + int error; + + if (!cpg_mstp_pd_np) + return -ENODEV; + + error = of_genpd_add_provider_simple(cpg_mstp_pd_np, cpg_mstp_pd_genpd); + + of_node_put(cpg_mstp_pd_np); + return error; +} +postcore_initcall(cpg_mstp_pd_init_provider); From 5576d8098052952a6c95af86ad3dcb341554ac75 Mon Sep 17 00:00:00 2001 From: Inbaraj E Date: Thu, 14 Aug 2025 19:39:32 +0530 Subject: [PATCH 01130/11391] 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 01131/11391] 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 758e743362cdc0cc45d8717431b2eabf29084ef1 Mon Sep 17 00:00:00 2001 From: Pawel Zalewski Date: Wed, 23 Jul 2025 11:02:08 +0100 Subject: [PATCH 01132/11391] leds: leds-is31fl32xx: Add support for is31fl3236a Also add an additional and optional control register for setting the output PWM frequency to 22kHz. The default is 3kHz and this option puts the operational frequency outside of the audible range. Signed-off-by: Pawel Zalewski Link: https://lore.kernel.org/r/20250723-leds-is31fl3236a-v6-3-210328058625@thegoodpenguin.co.uk Signed-off-by: Lee Jones --- drivers/leds/leds-is31fl32xx.c | 47 +++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/drivers/leds/leds-is31fl32xx.c b/drivers/leds/leds-is31fl32xx.c index 8793330dd414..dc9349f9d350 100644 --- a/drivers/leds/leds-is31fl32xx.c +++ b/drivers/leds/leds-is31fl32xx.c @@ -32,6 +32,8 @@ #define IS31FL3216_CONFIG_SSD_ENABLE BIT(7) #define IS31FL3216_CONFIG_SSD_DISABLE 0 +#define IS31FL32XX_PWM_FREQUENCY_22KHZ 0x01 + struct is31fl32xx_priv; struct is31fl32xx_led_data { struct led_classdev cdev; @@ -53,6 +55,7 @@ struct is31fl32xx_priv { * @pwm_update_reg : address of PWM Update register * @global_control_reg : address of Global Control register (optional) * @reset_reg : address of Reset register (optional) + * @output_frequency_setting_reg: address of output frequency register (optional) * @pwm_register_base : address of first PWM register * @pwm_registers_reversed: : true if PWM registers count down instead of up * @led_control_register_base : address of first LED control register (optional) @@ -76,6 +79,7 @@ struct is31fl32xx_chipdef { u8 pwm_update_reg; u8 global_control_reg; u8 reset_reg; + u8 output_frequency_setting_reg; u8 pwm_register_base; bool pwm_registers_reversed; u8 led_control_register_base; @@ -90,6 +94,19 @@ static const struct is31fl32xx_chipdef is31fl3236_cdef = { .pwm_update_reg = 0x25, .global_control_reg = 0x4a, .reset_reg = 0x4f, + .output_frequency_setting_reg = IS31FL32XX_REG_NONE, + .pwm_register_base = 0x01, + .led_control_register_base = 0x26, + .enable_bits_per_led_control_register = 1, +}; + +static const struct is31fl32xx_chipdef is31fl3236a_cdef = { + .channels = 36, + .shutdown_reg = 0x00, + .pwm_update_reg = 0x25, + .global_control_reg = 0x4a, + .reset_reg = 0x4f, + .output_frequency_setting_reg = 0x4b, .pwm_register_base = 0x01, .led_control_register_base = 0x26, .enable_bits_per_led_control_register = 1, @@ -101,6 +118,7 @@ static const struct is31fl32xx_chipdef is31fl3235_cdef = { .pwm_update_reg = 0x25, .global_control_reg = 0x4a, .reset_reg = 0x4f, + .output_frequency_setting_reg = IS31FL32XX_REG_NONE, .pwm_register_base = 0x05, .led_control_register_base = 0x2a, .enable_bits_per_led_control_register = 1, @@ -112,6 +130,7 @@ static const struct is31fl32xx_chipdef is31fl3218_cdef = { .pwm_update_reg = 0x16, .global_control_reg = IS31FL32XX_REG_NONE, .reset_reg = 0x17, + .output_frequency_setting_reg = IS31FL32XX_REG_NONE, .pwm_register_base = 0x01, .led_control_register_base = 0x13, .enable_bits_per_led_control_register = 6, @@ -126,6 +145,7 @@ static const struct is31fl32xx_chipdef is31fl3216_cdef = { .pwm_update_reg = 0xB0, .global_control_reg = IS31FL32XX_REG_NONE, .reset_reg = IS31FL32XX_REG_NONE, + .output_frequency_setting_reg = IS31FL32XX_REG_NONE, .pwm_register_base = 0x10, .pwm_registers_reversed = true, .led_control_register_base = 0x01, @@ -363,8 +383,21 @@ static struct is31fl32xx_led_data *is31fl32xx_find_led_data( static int is31fl32xx_parse_dt(struct device *dev, struct is31fl32xx_priv *priv) { + const struct is31fl32xx_chipdef *cdef = priv->cdef; int ret = 0; + if ((cdef->output_frequency_setting_reg != IS31FL32XX_REG_NONE) && + of_property_read_bool(dev_of_node(dev), "issi,22khz-pwm")) { + + ret = is31fl32xx_write(priv, cdef->output_frequency_setting_reg, + IS31FL32XX_PWM_FREQUENCY_22KHZ); + + if (ret) { + dev_err(dev, "Failed to write output PWM frequency register\n"); + return ret; + } + } + for_each_available_child_of_node_scoped(dev_of_node(dev), child) { struct led_init_data init_data = {}; struct is31fl32xx_led_data *led_data = @@ -404,12 +437,13 @@ static int is31fl32xx_parse_dt(struct device *dev, } static const struct of_device_id of_is31fl32xx_match[] = { - { .compatible = "issi,is31fl3236", .data = &is31fl3236_cdef, }, - { .compatible = "issi,is31fl3235", .data = &is31fl3235_cdef, }, - { .compatible = "issi,is31fl3218", .data = &is31fl3218_cdef, }, - { .compatible = "si-en,sn3218", .data = &is31fl3218_cdef, }, - { .compatible = "issi,is31fl3216", .data = &is31fl3216_cdef, }, - { .compatible = "si-en,sn3216", .data = &is31fl3216_cdef, }, + { .compatible = "issi,is31fl3236", .data = &is31fl3236_cdef, }, + { .compatible = "issi,is31fl3236a", .data = &is31fl3236a_cdef, }, + { .compatible = "issi,is31fl3235", .data = &is31fl3235_cdef, }, + { .compatible = "issi,is31fl3218", .data = &is31fl3218_cdef, }, + { .compatible = "si-en,sn3218", .data = &is31fl3218_cdef, }, + { .compatible = "issi,is31fl3216", .data = &is31fl3216_cdef, }, + { .compatible = "si-en,sn3216", .data = &is31fl3216_cdef, }, {}, }; @@ -466,6 +500,7 @@ static void is31fl32xx_remove(struct i2c_client *client) */ static const struct i2c_device_id is31fl32xx_id[] = { { "is31fl3236" }, + { "is31fl3236a" }, { "is31fl3235" }, { "is31fl3218" }, { "sn3218" }, From f4fc2d87aa167e3da5333c3db6cf702db1f98c05 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 24 Jul 2025 12:20:30 +0100 Subject: [PATCH 01133/11391] leds: Kconfig: Fix spelling mistake "limitiation" -> "limitation" There is a spelling mistake in the LEDS_BD2606MVV config. Fix it. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20250724112030.142121-1-colin.i.king@gmail.com Signed-off-by: Lee Jones --- drivers/leds/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 6e3dce7e35a4..06e6291be11b 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -674,7 +674,7 @@ config LEDS_BD2606MVV help This option enables support for BD2606MVV LED driver chips accessed via the I2C bus. It supports setting brightness, with - the limitiation that there are groups of two channels sharing + the limitation that there are groups of two channels sharing a brightness setting, but not the on/off setting. To compile this driver as a module, choose M here: the module will From 6e3779e3c6f9dcc9267bf98bef70773a0b13dcbb Mon Sep 17 00:00:00 2001 From: Len Bao Date: Sun, 27 Jul 2025 07:56:45 +0000 Subject: [PATCH 01134/11391] leds: max77705: Function return instead of variable assignment Coverity noticed that assigning value -EINVAL to 'ret' in the if statement is useless because 'ret' is overwritten a few lines later. However, after inspect the code, this warning reveals that we need to return -EINVAL instead of the variable assignment. So, fix it. Coverity-id: 1646104 Fixes: aebb5fc9a0d8 ("leds: max77705: Add LEDs support") Signed-off-by: Len Bao Link: https://lore.kernel.org/r/20250727075649.34496-1-len.bao@gmx.us Signed-off-by: Lee Jones --- drivers/leds/leds-max77705.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/leds/leds-max77705.c b/drivers/leds/leds-max77705.c index 933cb4f19be9..b7403b3fcf5e 100644 --- a/drivers/leds/leds-max77705.c +++ b/drivers/leds/leds-max77705.c @@ -180,7 +180,7 @@ static int max77705_add_led(struct device *dev, struct regmap *regmap, struct fw ret = fwnode_property_read_u32(np, "reg", ®); if (ret || reg >= MAX77705_LED_NUM_LEDS) - ret = -EINVAL; + return -EINVAL; info = devm_kcalloc(dev, num_channels, sizeof(*info), GFP_KERNEL); if (!info) From 5974e8f6c3e47ab097c3dd8ece7324d1f88fe739 Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Tue, 29 Jul 2025 12:51:22 +0800 Subject: [PATCH 01135/11391] leds: flash: leds-qcom-flash: Update torch current clamp setting There is a register to clamp the flash current per LED channel when safety timer is disabled. It needs to be updated according to the maximum torch LED current setting to ensure the torch current won't be clamped unexpectedly. Fixes: 96a2e242a5dc ("leds: flash: Add driver to support flash LED module in QCOM PMICs") Signed-off-by: Fenglin Wu Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250729-fix-torch-clamp-issue-v2-1-9b83816437a3@oss.qualcomm.com Signed-off-by: Lee Jones --- drivers/leds/flash/leds-qcom-flash.c | 62 ++++++++++++++++------------ 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/drivers/leds/flash/leds-qcom-flash.c b/drivers/leds/flash/leds-qcom-flash.c index 89cf5120f5d5..db7c2c743adc 100644 --- a/drivers/leds/flash/leds-qcom-flash.c +++ b/drivers/leds/flash/leds-qcom-flash.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022, 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -114,36 +114,39 @@ enum { REG_THERM_THRSH1, REG_THERM_THRSH2, REG_THERM_THRSH3, + REG_TORCH_CLAMP, REG_MAX_COUNT, }; static const struct reg_field mvflash_3ch_regs[REG_MAX_COUNT] = { - REG_FIELD(0x08, 0, 7), /* status1 */ - REG_FIELD(0x09, 0, 7), /* status2 */ - REG_FIELD(0x0a, 0, 7), /* status3 */ - REG_FIELD_ID(0x40, 0, 7, 3, 1), /* chan_timer */ - REG_FIELD_ID(0x43, 0, 6, 3, 1), /* itarget */ - REG_FIELD(0x46, 7, 7), /* module_en */ - REG_FIELD(0x47, 0, 5), /* iresolution */ - REG_FIELD_ID(0x49, 0, 2, 3, 1), /* chan_strobe */ - REG_FIELD(0x4c, 0, 2), /* chan_en */ - REG_FIELD(0x56, 0, 2), /* therm_thrsh1 */ - REG_FIELD(0x57, 0, 2), /* therm_thrsh2 */ - REG_FIELD(0x58, 0, 2), /* therm_thrsh3 */ + [REG_STATUS1] = REG_FIELD(0x08, 0, 7), + [REG_STATUS2] = REG_FIELD(0x09, 0, 7), + [REG_STATUS3] = REG_FIELD(0x0a, 0, 7), + [REG_CHAN_TIMER] = REG_FIELD_ID(0x40, 0, 7, 3, 1), + [REG_ITARGET] = REG_FIELD_ID(0x43, 0, 6, 3, 1), + [REG_MODULE_EN] = REG_FIELD(0x46, 7, 7), + [REG_IRESOLUTION] = REG_FIELD(0x47, 0, 5), + [REG_CHAN_STROBE] = REG_FIELD_ID(0x49, 0, 2, 3, 1), + [REG_CHAN_EN] = REG_FIELD(0x4c, 0, 2), + [REG_THERM_THRSH1] = REG_FIELD(0x56, 0, 2), + [REG_THERM_THRSH2] = REG_FIELD(0x57, 0, 2), + [REG_THERM_THRSH3] = REG_FIELD(0x58, 0, 2), + [REG_TORCH_CLAMP] = REG_FIELD(0xec, 0, 6), }; static const struct reg_field mvflash_4ch_regs[REG_MAX_COUNT] = { - REG_FIELD(0x06, 0, 7), /* status1 */ - REG_FIELD(0x07, 0, 6), /* status2 */ - REG_FIELD(0x09, 0, 7), /* status3 */ - REG_FIELD_ID(0x3e, 0, 7, 4, 1), /* chan_timer */ - REG_FIELD_ID(0x42, 0, 6, 4, 1), /* itarget */ - REG_FIELD(0x46, 7, 7), /* module_en */ - REG_FIELD(0x49, 0, 3), /* iresolution */ - REG_FIELD_ID(0x4a, 0, 6, 4, 1), /* chan_strobe */ - REG_FIELD(0x4e, 0, 3), /* chan_en */ - REG_FIELD(0x7a, 0, 2), /* therm_thrsh1 */ - REG_FIELD(0x78, 0, 2), /* therm_thrsh2 */ + [REG_STATUS1] = REG_FIELD(0x06, 0, 7), + [REG_STATUS2] = REG_FIELD(0x07, 0, 6), + [REG_STATUS3] = REG_FIELD(0x09, 0, 7), + [REG_CHAN_TIMER] = REG_FIELD_ID(0x3e, 0, 7, 4, 1), + [REG_ITARGET] = REG_FIELD_ID(0x42, 0, 6, 4, 1), + [REG_MODULE_EN] = REG_FIELD(0x46, 7, 7), + [REG_IRESOLUTION] = REG_FIELD(0x49, 0, 3), + [REG_CHAN_STROBE] = REG_FIELD_ID(0x4a, 0, 6, 4, 1), + [REG_CHAN_EN] = REG_FIELD(0x4e, 0, 3), + [REG_THERM_THRSH1] = REG_FIELD(0x7a, 0, 2), + [REG_THERM_THRSH2] = REG_FIELD(0x78, 0, 2), + [REG_TORCH_CLAMP] = REG_FIELD(0xed, 0, 6), }; struct qcom_flash_data { @@ -156,6 +159,7 @@ struct qcom_flash_data { u8 max_channels; u8 chan_en_bits; u8 revision; + u8 torch_clamp; }; struct qcom_flash_led { @@ -702,6 +706,7 @@ static int qcom_flash_register_led_device(struct device *dev, u32 current_ua, timeout_us; u32 channels[4]; int i, rc, count; + u8 torch_clamp; count = fwnode_property_count_u32(node, "led-sources"); if (count <= 0) { @@ -751,6 +756,12 @@ static int qcom_flash_register_led_device(struct device *dev, current_ua = min_t(u32, current_ua, TORCH_CURRENT_MAX_UA * led->chan_count); led->max_torch_current_ma = current_ua / UA_PER_MA; + torch_clamp = (current_ua / led->chan_count) / TORCH_IRES_UA; + if (torch_clamp != 0) + torch_clamp--; + + flash_data->torch_clamp = max_t(u8, flash_data->torch_clamp, torch_clamp); + if (fwnode_property_present(node, "flash-max-microamp")) { flash->led_cdev.flags |= LED_DEV_CAP_FLASH; @@ -917,8 +928,7 @@ static int qcom_flash_led_probe(struct platform_device *pdev) flash_data->leds_count++; } - return 0; - + return regmap_field_write(flash_data->r_fields[REG_TORCH_CLAMP], flash_data->torch_clamp); release: while (flash_data->v4l2_flash[flash_data->leds_count] && flash_data->leds_count) v4l2_flash_release(flash_data->v4l2_flash[flash_data->leds_count--]); From 7d5c3cac1f395324673e9ec32b65e4f6ff23fcb9 Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Tue, 29 Jul 2025 12:51:23 +0800 Subject: [PATCH 01136/11391] leds: flash: leds-qcom-flash: Add a separate register map for PMI8998 The 3-channel flash module in PMI8998 has several registers different than the others, such as: torch_clamp. Add different register fields for it. Signed-off-by: Fenglin Wu Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250729-fix-torch-clamp-issue-v2-2-9b83816437a3@oss.qualcomm.com Signed-off-by: Lee Jones --- drivers/leds/flash/leds-qcom-flash.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/leds/flash/leds-qcom-flash.c b/drivers/leds/flash/leds-qcom-flash.c index db7c2c743adc..b03a6833e3e3 100644 --- a/drivers/leds/flash/leds-qcom-flash.c +++ b/drivers/leds/flash/leds-qcom-flash.c @@ -118,6 +118,22 @@ enum { REG_MAX_COUNT, }; +static const struct reg_field mvflash_3ch_pmi8998_regs[REG_MAX_COUNT] = { + [REG_STATUS1] = REG_FIELD(0x08, 0, 5), + [REG_STATUS2] = REG_FIELD(0x09, 0, 7), + [REG_STATUS3] = REG_FIELD(0x0a, 0, 7), + [REG_CHAN_TIMER] = REG_FIELD_ID(0x40, 0, 7, 3, 1), + [REG_ITARGET] = REG_FIELD_ID(0x43, 0, 6, 3, 1), + [REG_MODULE_EN] = REG_FIELD(0x46, 7, 7), + [REG_IRESOLUTION] = REG_FIELD(0x47, 0, 5), + [REG_CHAN_STROBE] = REG_FIELD_ID(0x49, 0, 2, 3, 1), + [REG_CHAN_EN] = REG_FIELD(0x4c, 0, 2), + [REG_THERM_THRSH1] = REG_FIELD(0x56, 0, 2), + [REG_THERM_THRSH2] = REG_FIELD(0x57, 0, 2), + [REG_THERM_THRSH3] = REG_FIELD(0x58, 0, 2), + [REG_TORCH_CLAMP] = REG_FIELD(0xea, 0, 6), +}; + static const struct reg_field mvflash_3ch_regs[REG_MAX_COUNT] = { [REG_STATUS1] = REG_FIELD(0x08, 0, 7), [REG_STATUS2] = REG_FIELD(0x09, 0, 7), @@ -862,13 +878,20 @@ static int qcom_flash_led_probe(struct platform_device *pdev) return rc; } - if (val == FLASH_SUBTYPE_3CH_PM8150_VAL || val == FLASH_SUBTYPE_3CH_PMI8998_VAL) { + if (val == FLASH_SUBTYPE_3CH_PM8150_VAL) { flash_data->hw_type = QCOM_MVFLASH_3CH; flash_data->max_channels = 3; regs = devm_kmemdup(dev, mvflash_3ch_regs, sizeof(mvflash_3ch_regs), GFP_KERNEL); if (!regs) return -ENOMEM; + } else if (val == FLASH_SUBTYPE_3CH_PMI8998_VAL) { + flash_data->hw_type = QCOM_MVFLASH_3CH; + flash_data->max_channels = 3; + regs = devm_kmemdup(dev, mvflash_3ch_pmi8998_regs, + sizeof(mvflash_3ch_pmi8998_regs), GFP_KERNEL); + if (!regs) + return -ENOMEM; } else if (val == FLASH_SUBTYPE_4CH_VAL) { flash_data->hw_type = QCOM_MVFLASH_4CH; flash_data->max_channels = 4; From 5f755ba95ae10fd4fa28d64345056ffc18d12c5a Mon Sep 17 00:00:00 2001 From: Erick Shepherd Date: Thu, 24 Jul 2025 13:53:54 -0500 Subject: [PATCH 01137/11391] mmc: sdhci: Disable SD card clock before changing parameters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per the SD Host Controller Simplified Specification v4.20 §3.2.3, change the SD card clock parameters only after first disabling the external card clock. Doing this fixes a spurious clock pulse on Baytrail and Apollo Lake SD controllers which otherwise breaks voltage switching with a specific Swissbit SD card. This change is limited to Intel host controllers to avoid an issue reported on ARM64 devices. Signed-off-by: Kyle Roeschley Signed-off-by: Brad Mouring Signed-off-by: Erick Shepherd Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20250724185354.815888-1-erick.shepherd@ni.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci-core.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 826958992dfe..47a0a738862b 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -679,8 +679,19 @@ static int intel_start_signal_voltage_switch(struct mmc_host *mmc, return 0; } +static void sdhci_intel_set_clock(struct sdhci_host *host, unsigned int clock) +{ + u16 clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + + /* Stop card clock separately to avoid glitches on clock line */ + if (clk & SDHCI_CLOCK_CARD_EN) + sdhci_writew(host, clk & ~SDHCI_CLOCK_CARD_EN, SDHCI_CLOCK_CONTROL); + + sdhci_set_clock(host, clock); +} + static const struct sdhci_ops sdhci_intel_byt_ops = { - .set_clock = sdhci_set_clock, + .set_clock = sdhci_intel_set_clock, .set_power = sdhci_intel_set_power, .enable_dma = sdhci_pci_enable_dma, .set_bus_width = sdhci_set_bus_width, @@ -690,7 +701,7 @@ static const struct sdhci_ops sdhci_intel_byt_ops = { }; static const struct sdhci_ops sdhci_intel_glk_ops = { - .set_clock = sdhci_set_clock, + .set_clock = sdhci_intel_set_clock, .set_power = sdhci_intel_set_power, .enable_dma = sdhci_pci_enable_dma, .set_bus_width = sdhci_set_bus_width, From d76ae3c79ca9044191f2e2a8c85326869a72fa39 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 24 Jul 2025 12:28:17 +0100 Subject: [PATCH 01138/11391] mmc: Kconfig: Fix spelling mistake "referrered" -> "referred" There are two spelling mistakes in the config. Fix them. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20250724112817.142784-1-colin.i.king@gmail.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 7232de1c0688..4afa0130779d 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -359,7 +359,7 @@ config MMC_SDHCI_S3C depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST help This selects the Secure Digital Host Controller Interface (SDHCI) - often referrered to as the HSMMC block in some of the Samsung + often referred to as the HSMMC block in some of the Samsung S3C6410, S5Pv210 and Exynos (Exynso4210, Exynos4412) SoCs. If you have a controller with this interface (thereforeyou build for @@ -401,7 +401,7 @@ config MMC_SDHCI_SPEAR depends on OF help This selects the Secure Digital Host Controller Interface (SDHCI) - often referrered to as the HSMMC block in some of the ST SPEAR range + often referred to as the HSMMC block in some of the ST SPEAR range of SoC If you have a controller with this interface, say Y or M here. From 4591511daba4e7e9a8452b116c3f7ea5718c60ce Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 31 Jul 2025 10:41:16 +0100 Subject: [PATCH 01139/11391] mmc: davinci: Remove space before newline There is a extraneous space before a newline in a dev_err message. Remove the space. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20250731094116.2163061-1-colin.i.king@gmail.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/davinci_mmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index c691f1b60395..2a3c8058b0fb 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -588,7 +588,7 @@ static void mmc_davinci_request(struct mmc_host *mmc, struct mmc_request *req) cpu_relax(); } if (mmcst1 & MMCST1_BUSY) { - dev_err(mmc_dev(host->mmc), "still BUSY? bad ... \n"); + dev_err(mmc_dev(host->mmc), "still BUSY? bad ...\n"); req->cmd->error = -ETIMEDOUT; mmc_request_done(mmc, req); return; From 0caebd1658bbb3796bec4e3449876742d29701ab Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Fri, 25 Jul 2025 08:01:51 +0200 Subject: [PATCH 01140/11391] dt-bindings: mmc: fsl,esdhc: Add explicit reference to mmc-controller-common Even though it is referenced by mmc/mmc-controller.yaml it still raises the warning: esdhc@1560000 (fsl,ls1021a-esdhc): Unevaluated properties are not allowed ('bus-width' was unexpected) Adding an explicit reference fixes this. Signed-off-by: Alexander Stein Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250725060152.262094-1-alexander.stein@ew.tq-group.com Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/fsl,esdhc.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mmc/fsl,esdhc.yaml b/Documentation/devicetree/bindings/mmc/fsl,esdhc.yaml index 62087cf920df..f45e592901e2 100644 --- a/Documentation/devicetree/bindings/mmc/fsl,esdhc.yaml +++ b/Documentation/devicetree/bindings/mmc/fsl,esdhc.yaml @@ -90,6 +90,7 @@ required: allOf: - $ref: sdhci-common.yaml# + - $ref: mmc-controller-common.yaml# unevaluatedProperties: false From c33aca6c44c081b6aaff8f203d408688859a81fb Mon Sep 17 00:00:00 2001 From: "Borislav Petkov (AMD)" Date: Sun, 22 Jun 2025 18:19:43 +0200 Subject: [PATCH 01141/11391] MAINTAINERS: EDAC: Drop inactive reviewers I know y'all busy with other stuff and don't have time for EDAC review. Signed-off-by: Borislav Petkov (AMD) Acked-by: James Morse Link: https://lore.kernel.org/20250622161943.4700-1-bp@kernel.org --- MAINTAINERS | 3 --- 1 file changed, 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index fe168477caa4..dbbeabfc8a47 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8726,9 +8726,6 @@ F: drivers/edac/thunderx_edac* EDAC-CORE M: Borislav Petkov M: Tony Luck -R: James Morse -R: Mauro Carvalho Chehab -R: Robert Richter L: linux-edac@vger.kernel.org S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/ras/ras.git edac-for-next From 4d2604833e8ea79e77de98aa97a94b94a9733962 Mon Sep 17 00:00:00 2001 From: Carlos Llamas Date: Sun, 17 Aug 2025 13:50:34 +0000 Subject: [PATCH 01142/11391] 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 01143/11391] 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 01144/11391] 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 33bc29123d26f7caa7d11f139e153e39104afc6c Mon Sep 17 00:00:00 2001 From: Shimrra Shai Date: Thu, 14 Aug 2025 23:20:21 -0500 Subject: [PATCH 01145/11391] ASoC: es8323: remove DAC enablement write from es8323_probe Remove initialization of the DAC and mixer enablement bits from the es8323_probe routine. This really should be handled by the DAPM subsystem. Signed-off-by: Shimrra Shai Link: https://patch.msgid.link/20250815042023.115485-2-shimrrashai@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8323.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/es8323.c b/sound/soc/codecs/es8323.c index a9822998199f..194720e4de59 100644 --- a/sound/soc/codecs/es8323.c +++ b/sound/soc/codecs/es8323.c @@ -632,7 +632,6 @@ static int es8323_probe(struct snd_soc_component *component) snd_soc_component_write(component, ES8323_CONTROL2, 0x60); snd_soc_component_write(component, ES8323_CHIPPOWER, 0x00); - snd_soc_component_write(component, ES8323_DACCONTROL17, 0xB8); return 0; } From 7e39ca4056d11fef6b90aedd9eeeb3e070d3ce9f Mon Sep 17 00:00:00 2001 From: Shimrra Shai Date: Thu, 14 Aug 2025 23:20:22 -0500 Subject: [PATCH 01146/11391] ASoC: es8323: add proper left/right mixer controls via DAPM Add proper DAC and mixer controls to DAPM; no initialization in es8323_probe. Signed-off-by: Shimrra Shai Link: https://patch.msgid.link/20250815042023.115485-3-shimrrashai@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8323.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/es8323.c b/sound/soc/codecs/es8323.c index 194720e4de59..79f1fa96778d 100644 --- a/sound/soc/codecs/es8323.c +++ b/sound/soc/codecs/es8323.c @@ -182,13 +182,13 @@ static const struct snd_kcontrol_new es8323_mono_adc_mux_controls = /* Left Mixer */ static const struct snd_kcontrol_new es8323_left_mixer_controls[] = { - SOC_DAPM_SINGLE("Left Playback Switch", SND_SOC_NOPM, 7, 1, 1), + SOC_DAPM_SINGLE("Left Playback Switch", ES8323_DACCONTROL17, 7, 1, 0), SOC_DAPM_SINGLE("Left Bypass Switch", ES8323_DACCONTROL17, 6, 1, 0), }; /* Right Mixer */ static const struct snd_kcontrol_new es8323_right_mixer_controls[] = { - SOC_DAPM_SINGLE("Right Playback Switch", SND_SOC_NOPM, 6, 1, 1), + SOC_DAPM_SINGLE("Right Playback Switch", ES8323_DACCONTROL20, 7, 1, 0), SOC_DAPM_SINGLE("Right Bypass Switch", ES8323_DACCONTROL20, 6, 1, 0), }; From daf855f76a1210ceed9541f71ac5dd9be02018a6 Mon Sep 17 00:00:00 2001 From: Shimrra Shai Date: Thu, 14 Aug 2025 23:20:23 -0500 Subject: [PATCH 01147/11391] ASoC: es8323: enable DAPM power widgets for playback DAC This part might not be needed for resubmission as it was already accepted on the previous submission of this patch, but since the whole series was not accepted due to that I had retained and expanded the initialization in the probe routine I'm not sure if I should submit it again. Signed-off-by: Shimrra Shai Link: https://patch.msgid.link/20250815042023.115485-4-shimrrashai@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8323.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/es8323.c b/sound/soc/codecs/es8323.c index 79f1fa96778d..eb85b71e87f3 100644 --- a/sound/soc/codecs/es8323.c +++ b/sound/soc/codecs/es8323.c @@ -211,8 +211,8 @@ static const struct snd_soc_dapm_widget es8323_dapm_widgets[] = { SND_SOC_DAPM_ADC("Right ADC", "Right Capture", SND_SOC_NOPM, 4, 1), SND_SOC_DAPM_ADC("Left ADC", "Left Capture", SND_SOC_NOPM, 5, 1), - SND_SOC_DAPM_DAC("Right DAC", "Right Playback", SND_SOC_NOPM, 6, 1), - SND_SOC_DAPM_DAC("Left DAC", "Left Playback", SND_SOC_NOPM, 7, 1), + SND_SOC_DAPM_DAC("Right DAC", "Right Playback", ES8323_DACPOWER, 6, 1), + SND_SOC_DAPM_DAC("Left DAC", "Left Playback", ES8323_DACPOWER, 7, 1), SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0, &es8323_left_mixer_controls[0], @@ -223,10 +223,10 @@ static const struct snd_soc_dapm_widget es8323_dapm_widgets[] = { SND_SOC_DAPM_PGA("Right ADC Power", SND_SOC_NOPM, 6, 1, NULL, 0), SND_SOC_DAPM_PGA("Left ADC Power", SND_SOC_NOPM, 7, 1, NULL, 0), - SND_SOC_DAPM_PGA("Right Out 2", SND_SOC_NOPM, 2, 0, NULL, 0), - SND_SOC_DAPM_PGA("Left Out 2", SND_SOC_NOPM, 3, 0, NULL, 0), - SND_SOC_DAPM_PGA("Right Out 1", SND_SOC_NOPM, 4, 0, NULL, 0), - SND_SOC_DAPM_PGA("Left Out 1", SND_SOC_NOPM, 5, 0, NULL, 0), + SND_SOC_DAPM_PGA("Right Out 2", ES8323_DACPOWER, 2, 0, NULL, 0), + SND_SOC_DAPM_PGA("Left Out 2", ES8323_DACPOWER, 3, 0, NULL, 0), + SND_SOC_DAPM_PGA("Right Out 1", ES8323_DACPOWER, 4, 0, NULL, 0), + SND_SOC_DAPM_PGA("Left Out 1", ES8323_DACPOWER, 5, 0, NULL, 0), SND_SOC_DAPM_PGA("LAMP", ES8323_ADCCONTROL1, 4, 0, NULL, 0), SND_SOC_DAPM_PGA("RAMP", ES8323_ADCCONTROL1, 0, 0, NULL, 0), From 62dc545be11d956419a21724de3810930db20d43 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Mon, 18 Aug 2025 12:41:23 +0200 Subject: [PATCH 01148/11391] ASoC: Intel: avs: Separate debug symbols MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make it clear what is part of debug functionality and what is not by separating debug symbols away from the common header file. Apart from changing avs_probe_platform_register() to return -ENOTSUPP when CONFIG_DEBUG_FS is disabled, status quo is achieved. Reviewed-by: Amadeusz Sławiński Signed-off-by: Cezary Rojewski Link: https://patch.msgid.link/20250818104126.526442-2-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/apl.c | 1 + sound/soc/intel/avs/avs.h | 75 +--------------------- sound/soc/intel/avs/board_selection.c | 1 + sound/soc/intel/avs/cnl.c | 1 + sound/soc/intel/avs/core.c | 1 + sound/soc/intel/avs/debug.h | 91 +++++++++++++++++++++++++++ sound/soc/intel/avs/debugfs.c | 1 + sound/soc/intel/avs/icl.c | 1 + sound/soc/intel/avs/ipc.c | 1 + sound/soc/intel/avs/lnl.c | 1 + sound/soc/intel/avs/mtl.c | 1 + sound/soc/intel/avs/probes.c | 1 + sound/soc/intel/avs/ptl.c | 1 + sound/soc/intel/avs/skl.c | 1 + sound/soc/intel/avs/tgl.c | 1 + 15 files changed, 105 insertions(+), 74 deletions(-) create mode 100644 sound/soc/intel/avs/debug.h diff --git a/sound/soc/intel/avs/apl.c b/sound/soc/intel/avs/apl.c index 3dccf0a57a3a..b922eeaba843 100644 --- a/sound/soc/intel/avs/apl.c +++ b/sound/soc/intel/avs/apl.c @@ -10,6 +10,7 @@ #include #include #include "avs.h" +#include "debug.h" #include "messages.h" #include "path.h" #include "registers.h" diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h index 4c096afc5848..2be35c19d6ee 100644 --- a/sound/soc/intel/avs/avs.h +++ b/sound/soc/intel/avs/avs.h @@ -359,80 +359,7 @@ int avs_hda_platform_register(struct avs_dev *adev, const char *name); int avs_register_all_boards(struct avs_dev *adev); void avs_unregister_all_boards(struct avs_dev *adev); -/* Firmware tracing helpers */ - -#define avs_log_buffer_size(adev) \ - ((adev)->fw_cfg.trace_log_bytes / (adev)->hw_cfg.dsp_cores) - -#define avs_log_buffer_addr(adev, core) \ -({ \ - s32 __offset = avs_dsp_op(adev, log_buffer_offset, core); \ - (__offset < 0) ? NULL : \ - (avs_sram_addr(adev, AVS_DEBUG_WINDOW) + __offset); \ -}) - -static inline int avs_log_buffer_status_locked(struct avs_dev *adev, union avs_notify_msg *msg) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&adev->trace_lock, flags); - ret = avs_dsp_op(adev, log_buffer_status, msg); - spin_unlock_irqrestore(&adev->trace_lock, flags); - - return ret; -} - -struct avs_apl_log_buffer_layout { - u32 read_ptr; - u32 write_ptr; - u8 buffer[]; -} __packed; -static_assert(sizeof(struct avs_apl_log_buffer_layout) == 8); - -#define avs_apl_log_payload_size(adev) \ - (avs_log_buffer_size(adev) - sizeof(struct avs_apl_log_buffer_layout)) - -#define avs_apl_log_payload_addr(addr) \ - (addr + sizeof(struct avs_apl_log_buffer_layout)) - -#ifdef CONFIG_DEBUG_FS -#define AVS_SET_ENABLE_LOGS_OP(name) \ - .enable_logs = avs_##name##_enable_logs - -bool avs_logging_fw(struct avs_dev *adev); -void avs_dump_fw_log(struct avs_dev *adev, const void __iomem *src, unsigned int len); -void avs_dump_fw_log_wakeup(struct avs_dev *adev, const void __iomem *src, unsigned int len); - -int avs_probe_platform_register(struct avs_dev *adev, const char *name); - -void avs_debugfs_init(struct avs_dev *adev); -void avs_debugfs_exit(struct avs_dev *adev); -#else -#define AVS_SET_ENABLE_LOGS_OP(name) - -static inline bool avs_logging_fw(struct avs_dev *adev) -{ - return false; -} - -static inline void avs_dump_fw_log(struct avs_dev *adev, const void __iomem *src, unsigned int len) -{ -} - -static inline void -avs_dump_fw_log_wakeup(struct avs_dev *adev, const void __iomem *src, unsigned int len) -{ -} - -static inline int avs_probe_platform_register(struct avs_dev *adev, const char *name) -{ - return 0; -} - -static inline void avs_debugfs_init(struct avs_dev *adev) { } -static inline void avs_debugfs_exit(struct avs_dev *adev) { } -#endif +int avs_parse_sched_cfg(struct avs_dev *adev, const char *buf, size_t len); /* Filesystems integration */ diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c index fb49167f5fc4..9eb59d5a73f7 100644 --- a/sound/soc/intel/avs/board_selection.c +++ b/sound/soc/intel/avs/board_selection.c @@ -17,6 +17,7 @@ #include #include #include "avs.h" +#include "debug.h" #include "utils.h" static char *i2s_test; diff --git a/sound/soc/intel/avs/cnl.c b/sound/soc/intel/avs/cnl.c index 03f8fb0dc187..5b5359e9128b 100644 --- a/sound/soc/intel/avs/cnl.c +++ b/sound/soc/intel/avs/cnl.c @@ -8,6 +8,7 @@ #include #include "avs.h" +#include "debug.h" #include "messages.h" #include "registers.h" diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c index 5ebadba07ecc..6e0e65584c7f 100644 --- a/sound/soc/intel/avs/core.c +++ b/sound/soc/intel/avs/core.c @@ -27,6 +27,7 @@ #include "../../codecs/hda.h" #include "avs.h" #include "cldma.h" +#include "debug.h" #include "messages.h" #include "pcm.h" diff --git a/sound/soc/intel/avs/debug.h b/sound/soc/intel/avs/debug.h new file mode 100644 index 000000000000..9f0f6f3b2bde --- /dev/null +++ b/sound/soc/intel/avs/debug.h @@ -0,0 +1,91 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright(c) 2024-2025 Intel Corporation + * + * Authors: Cezary Rojewski + * Amadeusz Slawinski + */ + +#ifndef __SOUND_SOC_INTEL_AVS_DEBUG_H +#define __SOUND_SOC_INTEL_AVS_DEBUG_H + +#include "messages.h" +#include "registers.h" + +struct avs_dev; + +#define avs_log_buffer_size(adev) \ + ((adev)->fw_cfg.trace_log_bytes / (adev)->hw_cfg.dsp_cores) + +#define avs_log_buffer_addr(adev, core) \ +({ \ + s32 __offset = avs_dsp_op(adev, log_buffer_offset, core); \ + (__offset < 0) ? NULL : \ + (avs_sram_addr(adev, AVS_DEBUG_WINDOW) + __offset); \ +}) + +static inline int avs_log_buffer_status_locked(struct avs_dev *adev, union avs_notify_msg *msg) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&adev->trace_lock, flags); + ret = avs_dsp_op(adev, log_buffer_status, msg); + spin_unlock_irqrestore(&adev->trace_lock, flags); + + return ret; +} + +struct avs_apl_log_buffer_layout { + u32 read_ptr; + u32 write_ptr; + u8 buffer[]; +} __packed; +static_assert(sizeof(struct avs_apl_log_buffer_layout) == 8); + +#define avs_apl_log_payload_size(adev) \ + (avs_log_buffer_size(adev) - sizeof(struct avs_apl_log_buffer_layout)) + +#define avs_apl_log_payload_addr(addr) \ + (addr + sizeof(struct avs_apl_log_buffer_layout)) + +#ifdef CONFIG_DEBUG_FS +int avs_probe_platform_register(struct avs_dev *adev, const char *name); + +#define AVS_SET_ENABLE_LOGS_OP(name) \ + .enable_logs = avs_##name##_enable_logs + +bool avs_logging_fw(struct avs_dev *adev); +void avs_dump_fw_log(struct avs_dev *adev, const void __iomem *src, unsigned int len); +void avs_dump_fw_log_wakeup(struct avs_dev *adev, const void __iomem *src, unsigned int len); + +void avs_debugfs_init(struct avs_dev *adev); +void avs_debugfs_exit(struct avs_dev *adev); + +#else +static inline int avs_probe_platform_register(struct avs_dev *adev, const char *name) +{ + return -EOPNOTSUPP; +} + +#define AVS_SET_ENABLE_LOGS_OP(name) + +static inline bool avs_logging_fw(struct avs_dev *adev) +{ + return false; +} + +static inline void avs_dump_fw_log(struct avs_dev *adev, const void __iomem *src, unsigned int len) +{ +} + +static inline void avs_dump_fw_log_wakeup(struct avs_dev *adev, const void __iomem *src, + unsigned int len) +{ +} + +static inline void avs_debugfs_init(struct avs_dev *adev) { } +static inline void avs_debugfs_exit(struct avs_dev *adev) { } +#endif + +#endif diff --git a/sound/soc/intel/avs/debugfs.c b/sound/soc/intel/avs/debugfs.c index f508f215ecd2..3534de46f9e4 100644 --- a/sound/soc/intel/avs/debugfs.c +++ b/sound/soc/intel/avs/debugfs.c @@ -13,6 +13,7 @@ #include #include #include "avs.h" +#include "debug.h" #include "messages.h" static unsigned int __kfifo_fromio(struct kfifo *fifo, const void __iomem *src, unsigned int len) diff --git a/sound/soc/intel/avs/icl.c b/sound/soc/intel/avs/icl.c index f8d327ea2656..d655e727bebd 100644 --- a/sound/soc/intel/avs/icl.c +++ b/sound/soc/intel/avs/icl.c @@ -10,6 +10,7 @@ #include #include #include "avs.h" +#include "debug.h" #include "messages.h" #define ICL_VS_LTRP_GB_ICCMAX 95 diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c index 6bfb9d1a1ca8..c0feb9edd7f6 100644 --- a/sound/soc/intel/avs/ipc.c +++ b/sound/soc/intel/avs/ipc.c @@ -10,6 +10,7 @@ #include #include #include "avs.h" +#include "debug.h" #include "messages.h" #include "registers.h" #include "trace.h" diff --git a/sound/soc/intel/avs/lnl.c b/sound/soc/intel/avs/lnl.c index 03208596dfb1..4fbc62bfd6c5 100644 --- a/sound/soc/intel/avs/lnl.c +++ b/sound/soc/intel/avs/lnl.c @@ -8,6 +8,7 @@ #include #include "avs.h" +#include "debug.h" #include "registers.h" int avs_lnl_core_stall(struct avs_dev *adev, u32 core_mask, bool stall) diff --git a/sound/soc/intel/avs/mtl.c b/sound/soc/intel/avs/mtl.c index e7b7915b2a82..d8bdd03275d7 100644 --- a/sound/soc/intel/avs/mtl.c +++ b/sound/soc/intel/avs/mtl.c @@ -8,6 +8,7 @@ #include #include "avs.h" +#include "debug.h" #include "registers.h" #include "trace.h" diff --git a/sound/soc/intel/avs/probes.c b/sound/soc/intel/avs/probes.c index a42736b9aa55..505ca4975e61 100644 --- a/sound/soc/intel/avs/probes.c +++ b/sound/soc/intel/avs/probes.c @@ -11,6 +11,7 @@ #include #include #include "avs.h" +#include "debug.h" #include "messages.h" static int avs_dsp_init_probe(struct avs_dev *adev, union avs_connector_node_id node_id, diff --git a/sound/soc/intel/avs/ptl.c b/sound/soc/intel/avs/ptl.c index 2be4b545c91d..07da9b0aa2b8 100644 --- a/sound/soc/intel/avs/ptl.c +++ b/sound/soc/intel/avs/ptl.c @@ -8,6 +8,7 @@ #include #include "avs.h" +#include "debug.h" #include "registers.h" #include "trace.h" diff --git a/sound/soc/intel/avs/skl.c b/sound/soc/intel/avs/skl.c index d66ef000de9e..8fb86f364ff3 100644 --- a/sound/soc/intel/avs/skl.c +++ b/sound/soc/intel/avs/skl.c @@ -11,6 +11,7 @@ #include #include "avs.h" #include "cldma.h" +#include "debug.h" #include "messages.h" #include "registers.h" diff --git a/sound/soc/intel/avs/tgl.c b/sound/soc/intel/avs/tgl.c index 9dbb3ad0954a..afb066516101 100644 --- a/sound/soc/intel/avs/tgl.c +++ b/sound/soc/intel/avs/tgl.c @@ -8,6 +8,7 @@ #include #include "avs.h" +#include "debug.h" #include "messages.h" #define CPUID_TSC_LEAF 0x15 From df36e5c197f31a105b8c8a70f13ebdf3a4c019d5 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Mon, 18 Aug 2025 12:41:24 +0200 Subject: [PATCH 01149/11391] ASoC: Intel: avs: Drop pcm.h dependency for probes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'probe' machine board is not a typical one, it serves debug purpose only and does not expect any kind of topology. The topology descriptor pointer (acomp->tplg) is the only reason an avs-driver component would utilize the pcm.c helpers and be described by a 'struct avs_soc_component' instance rather than 'struct snd_soc_component' one. Cut the line linking probes.c with pcm.h to avoid confusing readers. And with that link gone, constify the component-driver again. Reviewed-by: Amadeusz Sławiński Signed-off-by: Cezary Rojewski Link: https://patch.msgid.link/20250818104126.526442-3-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/probes.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/avs/probes.c b/sound/soc/intel/avs/probes.c index 505ca4975e61..88c6d385c73c 100644 --- a/sound/soc/intel/avs/probes.c +++ b/sound/soc/intel/avs/probes.c @@ -285,7 +285,7 @@ static struct snd_soc_dai_driver probe_cpu_dais[] = { }, }; -static struct snd_soc_component_driver avs_probe_component_driver = { +static const struct snd_soc_component_driver avs_probe_component_driver = { .name = "avs-probe-compr", .compress_ops = &avs_probe_compress_ops, .module_get_upon_open = 1, /* increment refcount when a stream is opened */ @@ -293,6 +293,20 @@ static struct snd_soc_component_driver avs_probe_component_driver = { int avs_probe_platform_register(struct avs_dev *adev, const char *name) { - return avs_soc_component_register(adev->dev, name, &avs_probe_component_driver, - probe_cpu_dais, ARRAY_SIZE(probe_cpu_dais)); + struct snd_soc_component *component; + int ret; + + component = devm_kzalloc(adev->dev, sizeof(*component), GFP_KERNEL); + if (!component) + return -ENOMEM; + + component->name = devm_kstrdup(adev->dev, name, GFP_KERNEL); + if (!component->name) + return -ENOMEM; + + ret = snd_soc_component_initialize(component, &avs_probe_component_driver, adev->dev); + if (ret) + return ret; + + return snd_soc_add_component(component, probe_cpu_dais, ARRAY_SIZE(probe_cpu_dais)); } From 4dee5c1cc439b0d5ef87f741518268ad6a95b23d Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Mon, 18 Aug 2025 12:41:25 +0200 Subject: [PATCH 01150/11391] ASoC: Intel: avs: Do not share the name pointer between components MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By sharing 'name' directly, tearing down components may lead to use-after-free errors. Duplicate the name to avoid that. At the same time, update the order of operations - since commit cee28113db17 ("ASoC: dmaengine_pcm: Allow passing component name via config") the framework does not override component->name if set before invoking the initializer. Reviewed-by: Amadeusz Sławiński Signed-off-by: Cezary Rojewski Link: https://patch.msgid.link/20250818104126.526442-4-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/pcm.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c index 67ce6675eea7..e738deb2d314 100644 --- a/sound/soc/intel/avs/pcm.c +++ b/sound/soc/intel/avs/pcm.c @@ -1390,16 +1390,18 @@ int avs_soc_component_register(struct device *dev, const char *name, if (!acomp) return -ENOMEM; - ret = snd_soc_component_initialize(&acomp->base, drv, dev); - if (ret < 0) - return ret; + acomp->base.name = devm_kstrdup(dev, name, GFP_KERNEL); + if (!acomp->base.name) + return -ENOMEM; - /* force name change after ASoC is done with its init */ - acomp->base.name = name; INIT_LIST_HEAD(&acomp->node); drv->use_dai_pcm_id = !obsolete_card_names; + ret = snd_soc_component_initialize(&acomp->base, drv, dev); + if (ret < 0) + return ret; + return snd_soc_add_component(&acomp->base, cpu_dais, num_cpu_dais); } From 2a55135201d5e24b80b7624880ff42eafd8e320c Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Mon, 18 Aug 2025 12:41:26 +0200 Subject: [PATCH 01151/11391] ASoC: Intel: avs: Streamline register-component function names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Word 'component' is commonly used in ASoC when referring to any component, regardless if it is a platform-type or codec-type component. Reword all avs_xxx_platform_register() to match the scheme present in ASoC's core. In case of avs_soc_component_register(), the name is simplified. Summary: - avs_xxx_platform_register() -> avs_register_xxx_component() - avs_soc_component_register() -> avs_register_component() Reviewed-by: Amadeusz Sławiński Signed-off-by: Cezary Rojewski Link: https://patch.msgid.link/20250818104126.526442-5-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/avs.h | 14 +++++++------- sound/soc/intel/avs/board_selection.c | 9 +++++---- sound/soc/intel/avs/debug.h | 4 ++-- sound/soc/intel/avs/pcm.c | 23 +++++++++++------------ sound/soc/intel/avs/probes.c | 2 +- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h index 2be35c19d6ee..95f9ac2683c0 100644 --- a/sound/soc/intel/avs/avs.h +++ b/sound/soc/intel/avs/avs.h @@ -348,13 +348,13 @@ struct avs_soc_component { extern const struct snd_soc_dai_ops avs_dai_fe_ops; -int avs_soc_component_register(struct device *dev, const char *name, - struct snd_soc_component_driver *drv, - struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais); -int avs_dmic_platform_register(struct avs_dev *adev, const char *name); -int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned long port_mask, - unsigned long *tdms); -int avs_hda_platform_register(struct avs_dev *adev, const char *name); +int avs_register_dmic_component(struct avs_dev *adev, const char *name); +int avs_register_i2s_component(struct avs_dev *adev, const char *name, unsigned long port_mask, + unsigned long *tdms); +int avs_register_hda_component(struct avs_dev *adev, const char *name); +int avs_register_component(struct device *dev, const char *name, + struct snd_soc_component_driver *drv, + struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais); int avs_register_all_boards(struct avs_dev *adev); void avs_unregister_all_boards(struct avs_dev *adev); diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c index 9eb59d5a73f7..e1d6fa344aa1 100644 --- a/sound/soc/intel/avs/board_selection.c +++ b/sound/soc/intel/avs/board_selection.c @@ -18,6 +18,7 @@ #include #include "avs.h" #include "debug.h" +#include "pcm.h" #include "utils.h" static char *i2s_test; @@ -410,7 +411,7 @@ static int __maybe_unused avs_register_probe_board(struct avs_dev *adev) struct snd_soc_acpi_mach mach = {{0}}; int ret; - ret = avs_probe_platform_register(adev, "probe-platform"); + ret = avs_register_probe_component(adev, "probe-platform"); if (ret < 0) return ret; @@ -455,7 +456,7 @@ static int avs_register_dmic_board(struct avs_dev *adev) return ret; } - ret = avs_dmic_platform_register(adev, "dmic-platform"); + ret = avs_register_dmic_component(adev, "dmic-platform"); if (ret < 0) return ret; @@ -516,7 +517,7 @@ static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach if (!name) return -ENOMEM; - ret = avs_i2s_platform_register(adev, name, mach->mach_params.i2s_link_mask, pdata->tdms); + ret = avs_register_i2s_component(adev, name, mach->mach_params.i2s_link_mask, pdata->tdms); if (ret < 0) return ret; @@ -655,7 +656,7 @@ static int avs_register_hda_board(struct avs_dev *adev, struct hda_codec *codec) pdata->obsolete_card_names = obsolete_card_names; pdata->codec = codec; - ret = avs_hda_platform_register(adev, pname); + ret = avs_register_hda_component(adev, pname); if (ret < 0) return ret; diff --git a/sound/soc/intel/avs/debug.h b/sound/soc/intel/avs/debug.h index 9f0f6f3b2bde..94fe8729a5c1 100644 --- a/sound/soc/intel/avs/debug.h +++ b/sound/soc/intel/avs/debug.h @@ -50,7 +50,7 @@ static_assert(sizeof(struct avs_apl_log_buffer_layout) == 8); (addr + sizeof(struct avs_apl_log_buffer_layout)) #ifdef CONFIG_DEBUG_FS -int avs_probe_platform_register(struct avs_dev *adev, const char *name); +int avs_register_probe_component(struct avs_dev *adev, const char *name); #define AVS_SET_ENABLE_LOGS_OP(name) \ .enable_logs = avs_##name##_enable_logs @@ -63,7 +63,7 @@ void avs_debugfs_init(struct avs_dev *adev); void avs_debugfs_exit(struct avs_dev *adev); #else -static inline int avs_probe_platform_register(struct avs_dev *adev, const char *name) +static inline int avs_register_probe_component(struct avs_dev *adev, const char *name) { return -EOPNOTSUPP; } diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c index e738deb2d314..d31058e2de5b 100644 --- a/sound/soc/intel/avs/pcm.c +++ b/sound/soc/intel/avs/pcm.c @@ -1379,9 +1379,9 @@ static struct snd_soc_component_driver avs_component_driver = { .topology_name_prefix = "intel/avs", }; -int avs_soc_component_register(struct device *dev, const char *name, - struct snd_soc_component_driver *drv, - struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais) +int avs_register_component(struct device *dev, const char *name, + struct snd_soc_component_driver *drv, + struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais) { struct avs_soc_component *acomp; int ret; @@ -1428,7 +1428,7 @@ static struct snd_soc_dai_driver dmic_cpu_dais[] = { }, }; -int avs_dmic_platform_register(struct avs_dev *adev, const char *name) +int avs_register_dmic_component(struct avs_dev *adev, const char *name) { const struct snd_soc_dai_ops *ops; @@ -1439,8 +1439,8 @@ int avs_dmic_platform_register(struct avs_dev *adev, const char *name) dmic_cpu_dais[0].ops = ops; dmic_cpu_dais[1].ops = ops; - return avs_soc_component_register(adev->dev, name, &avs_component_driver, dmic_cpu_dais, - ARRAY_SIZE(dmic_cpu_dais)); + return avs_register_component(adev->dev, name, &avs_component_driver, dmic_cpu_dais, + ARRAY_SIZE(dmic_cpu_dais)); } static const struct snd_soc_dai_driver i2s_dai_template = { @@ -1472,8 +1472,8 @@ static const struct snd_soc_dai_driver i2s_dai_template = { }, }; -int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned long port_mask, - unsigned long *tdms) +int avs_register_i2s_component(struct avs_dev *adev, const char *name, unsigned long port_mask, + unsigned long *tdms) { struct snd_soc_dai_driver *cpus, *dai; const struct snd_soc_dai_ops *ops; @@ -1539,7 +1539,7 @@ int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned l } plat_register: - return avs_soc_component_register(adev->dev, name, &avs_component_driver, cpus, cpu_count); + return avs_register_component(adev->dev, name, &avs_component_driver, cpus, cpu_count); } /* HD-Audio CPU DAI template */ @@ -1764,8 +1764,7 @@ static struct snd_soc_component_driver avs_hda_component_driver = { .topology_name_prefix = "intel/avs", }; -int avs_hda_platform_register(struct avs_dev *adev, const char *name) +int avs_register_hda_component(struct avs_dev *adev, const char *name) { - return avs_soc_component_register(adev->dev, name, - &avs_hda_component_driver, NULL, 0); + return avs_register_component(adev->dev, name, &avs_hda_component_driver, NULL, 0); } diff --git a/sound/soc/intel/avs/probes.c b/sound/soc/intel/avs/probes.c index 88c6d385c73c..c7b70006354a 100644 --- a/sound/soc/intel/avs/probes.c +++ b/sound/soc/intel/avs/probes.c @@ -291,7 +291,7 @@ static const struct snd_soc_component_driver avs_probe_component_driver = { .module_get_upon_open = 1, /* increment refcount when a stream is opened */ }; -int avs_probe_platform_register(struct avs_dev *adev, const char *name) +int avs_register_probe_component(struct avs_dev *adev, const char *name) { struct snd_soc_component *component; int ret; From 550bc517e59347b3b1af7d290eac4fb1411a3d4e Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Sun, 17 Aug 2025 22:23:27 +0800 Subject: [PATCH 01152/11391] regulator: bd718x7: Use kcalloc() instead of kzalloc() Replace calls of 'devm_kzalloc(dev, count * sizeof([type]), flags)' with 'devm_kcalloc(dev, count, sizeof([type]), flags)' in setup_feedback_loop() for safer memory allocation with built-in overflow protection. Signed-off-by: Qianfeng Rong Reviewed-by: Matti Vaittinen Link: https://patch.msgid.link/20250817142327.174531-1-rongqianfeng@vivo.com Signed-off-by: Mark Brown --- drivers/regulator/bd718x7-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/bd718x7-regulator.c b/drivers/regulator/bd718x7-regulator.c index e803cc59d68a..022d98f3c32a 100644 --- a/drivers/regulator/bd718x7-regulator.c +++ b/drivers/regulator/bd718x7-regulator.c @@ -1598,7 +1598,7 @@ static int setup_feedback_loop(struct device *dev, struct device_node *np, if (desc->n_linear_ranges && desc->linear_ranges) { struct linear_range *new; - new = devm_kzalloc(dev, desc->n_linear_ranges * + new = devm_kcalloc(dev, desc->n_linear_ranges, sizeof(struct linear_range), GFP_KERNEL); if (!new) From 07826c02eda9da406524bd50cd3fd321be8c9447 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 15 Aug 2025 11:44:00 -0500 Subject: [PATCH 01153/11391] MAINTAINERS: merge TRIGGER SOURCE sections Merge all of Documentation/devicetree/bindings/trigger-source/* as a single entry. In the previous merge cycle, there was a merge conflict between the IIO and SPI trees and we ended up with the current state, but the intention was to have a single entry for all trigger-source bindings. Signed-off-by: David Lechner Link: https://patch.msgid.link/20250815-spi-offload-trigger-followup-v1-1-8ec5413a8383@baylibre.com Signed-off-by: Mark Brown --- MAINTAINERS | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index daf520a13bdf..eb3f98f512ad 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -25601,16 +25601,10 @@ W: https://github.com/srcres258/linux-doc T: git https://github.com/srcres258/linux-doc.git doc-zh-tw F: Documentation/translations/zh_TW/ -TRIGGER SOURCE - ADI UTIL SIGMA DELTA SPI -M: David Lechner -S: Maintained -F: Documentation/devicetree/bindings/trigger-source/adi,util-sigma-delta-spi.yaml - TRIGGER SOURCE M: David Lechner S: Maintained -F: Documentation/devicetree/bindings/trigger-source/gpio-trigger.yaml -F: Documentation/devicetree/bindings/trigger-source/pwm-trigger.yaml +F: Documentation/devicetree/bindings/trigger-source/* TRUSTED SECURITY MODULE (TSM) INFRASTRUCTURE M: Dan Williams From 0056b410355713556d8a10306f82e55b28d33ba8 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 15 Aug 2025 11:44:01 -0500 Subject: [PATCH 01154/11391] spi: offload trigger: adi-util-sigma-delta: clean up imports Clean up imports using include-what-you-use principles. Suggested-by: Andy Shevchenko Signed-off-by: David Lechner Link: https://patch.msgid.link/20250815-spi-offload-trigger-followup-v1-2-8ec5413a8383@baylibre.com Signed-off-by: Mark Brown --- drivers/spi/spi-offload-trigger-adi-util-sigma-delta.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-offload-trigger-adi-util-sigma-delta.c b/drivers/spi/spi-offload-trigger-adi-util-sigma-delta.c index 035d088d4d33..8468c773713a 100644 --- a/drivers/spi/spi-offload-trigger-adi-util-sigma-delta.c +++ b/drivers/spi/spi-offload-trigger-adi-util-sigma-delta.c @@ -5,12 +5,15 @@ */ #include -#include +#include +#include #include #include #include #include #include +#include +#include static bool adi_util_sigma_delta_match(struct spi_offload_trigger *trigger, enum spi_offload_trigger_type type, From a750050349ea138e3e86c66a8a41de736619b9de Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Fri, 15 Aug 2025 16:21:15 +0800 Subject: [PATCH 01155/11391] spi: spi-fsl-lpspi: use min_t() to improve code Use min_t() to reduce the code in fsl_lpspi_setup_transfer() and improve its readability. Signed-off-by: Qianfeng Rong Link: https://patch.msgid.link/20250815082118.586422-2-rongqianfeng@vivo.com Reviewed-by: Frank Li Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index 67d4000c3cef..f5595e2ba2d5 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -25,6 +25,7 @@ #include #include #include +#include #define DRIVER_NAME "fsl_lpspi" @@ -475,10 +476,9 @@ static int fsl_lpspi_setup_transfer(struct spi_controller *controller, fsl_lpspi->tx = fsl_lpspi_buf_tx_u32; } - if (t->len <= fsl_lpspi->txfifosize) - fsl_lpspi->watermark = t->len; - else - fsl_lpspi->watermark = fsl_lpspi->txfifosize; + fsl_lpspi->watermark = min_t(typeof(fsl_lpspi->watermark), + fsl_lpspi->txfifosize, + t->len); if (fsl_lpspi_can_dma(controller, spi, t)) fsl_lpspi->usedma = true; From 1bdc716023a78c2c41fdcb3fc37f09da1be4b7df Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Fri, 15 Aug 2025 16:21:16 +0800 Subject: [PATCH 01156/11391] spi: npcm-fiu: use min_t() to improve code Use min_t() to reduce the code in npcm_fiu_read() and improve its readability. Signed-off-by: Qianfeng Rong Link: https://patch.msgid.link/20250815082118.586422-3-rongqianfeng@vivo.com Signed-off-by: Mark Brown --- drivers/spi/spi-npcm-fiu.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-npcm-fiu.c b/drivers/spi/spi-npcm-fiu.c index 67cc1d86de42..cccd17f24775 100644 --- a/drivers/spi/spi-npcm-fiu.c +++ b/drivers/spi/spi-npcm-fiu.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -498,10 +499,7 @@ static int npcm_fiu_read(struct spi_mem *mem, const struct spi_mem_op *op) do { addr = ((u32)op->addr.val + i); - if (currlen < 16) - readlen = currlen; - else - readlen = 16; + readlen = min_t(int, currlen, 16); buf_ptr = data + i; ret = npcm_fiu_uma_read(mem, op, addr, true, buf_ptr, From 90179609efa421b1ccc7d8eafbc078bafb25777c Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Fri, 15 Aug 2025 16:21:17 +0800 Subject: [PATCH 01157/11391] spi: spl022: use min_t() to improve code Use min_t() to reduce the code in setup_dma_scatter() and improve its readability. Signed-off-by: Qianfeng Rong Link: https://patch.msgid.link/20250815082118.586422-4-rongqianfeng@vivo.com Signed-off-by: Mark Brown --- drivers/spi/spi-pl022.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index dd87cf4f70dd..9e56e8774614 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -33,6 +33,7 @@ #include #include #include +#include /* * This macro is used to define some register default values. @@ -760,10 +761,9 @@ static void setup_dma_scatter(struct pl022 *pl022, * we just feed in this, else we stuff in as much * as we can. */ - if (bytesleft < (PAGE_SIZE - offset_in_page(bufp))) - mapbytes = bytesleft; - else - mapbytes = PAGE_SIZE - offset_in_page(bufp); + mapbytes = min_t(int, bytesleft, + PAGE_SIZE - offset_in_page(bufp)); + sg_set_page(sg, virt_to_page(bufp), mapbytes, offset_in_page(bufp)); bufp += mapbytes; @@ -775,10 +775,7 @@ static void setup_dma_scatter(struct pl022 *pl022, } else { /* Map the dummy buffer on every page */ for_each_sg(sgtab->sgl, sg, sgtab->nents, i) { - if (bytesleft < PAGE_SIZE) - mapbytes = bytesleft; - else - mapbytes = PAGE_SIZE; + mapbytes = min_t(int, bytesleft, PAGE_SIZE); sg_set_page(sg, virt_to_page(pl022->dummypage), mapbytes, 0); bytesleft -= mapbytes; From 0cb6f1e436accba7882bb3115408d1474c1e14af Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 1 Dec 2023 18:53:40 +0100 Subject: [PATCH 01158/11391] 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 01159/11391] 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 01160/11391] 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 01161/11391] 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 01162/11391] 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 01163/11391] 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 01164/11391] 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 01165/11391] 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 01166/11391] 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 01167/11391] 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 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) 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 01168/11391] 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 01169/11391] 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 01170/11391] 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 01171/11391] 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 01172/11391] 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 01173/11391] 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 eada40e057fc1842358d9daca3abe5cacb21e8a1 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Wed, 13 Aug 2025 14:06:28 +0200 Subject: [PATCH 01174/11391] s390/bpf: Do not write tail call counter into helper and kfunc frames Only BPF functions make use of the tail call counter; helpers and kfuncs ignore and most likely also clobber it. Writing it into these functions' frames is pointless and misleading, so do not do it. Fixes: dd691e847d28 ("s390/bpf: Implement bpf_jit_supports_subprog_tailcalls()") Signed-off-by: Ilya Leoshkevich Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20250813121016.163375-2-iii@linux.ibm.com --- arch/s390/net/bpf_jit_comp.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c index bb17efe29d65..bfac1ddf3447 100644 --- a/arch/s390/net/bpf_jit_comp.c +++ b/arch/s390/net/bpf_jit_comp.c @@ -1790,6 +1790,7 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, REG_SET_SEEN(BPF_REG_5); jit->seen |= SEEN_FUNC; + /* * Copy the tail call counter to where the callee expects it. * @@ -1800,10 +1801,17 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, * Note 2: We assume that the verifier does not let us call the * main program, which clears the tail call counter on entry. */ - /* mvc tail_call_cnt(4,%r15),frame_off+tail_call_cnt(%r15) */ - _EMIT6(0xd203f000 | offsetof(struct prog_frame, tail_call_cnt), - 0xf000 | (jit->frame_off + - offsetof(struct prog_frame, tail_call_cnt))); + + if (insn->src_reg == BPF_PSEUDO_CALL) + /* + * mvc tail_call_cnt(4,%r15), + * frame_off+tail_call_cnt(%r15) + */ + _EMIT6(0xd203f000 | offsetof(struct prog_frame, + tail_call_cnt), + 0xf000 | (jit->frame_off + + offsetof(struct prog_frame, + tail_call_cnt))); /* Sign-extend the kfunc arguments. */ if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL) { From c861a6b147137d10b5ff88a2c492ba376cd1b8b0 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Wed, 13 Aug 2025 14:06:29 +0200 Subject: [PATCH 01175/11391] s390/bpf: Write back tail call counter for BPF_PSEUDO_CALL The tailcall_bpf2bpf_hierarchy_1 test hangs on s390. Its call graph is as follows: entry() subprog_tail() bpf_tail_call_static(0) -> entry + tail_call_start subprog_tail() bpf_tail_call_static(0) -> entry + tail_call_start entry() copies its tail call counter to the subprog_tail()'s frame, which then increments it. However, the incremented result is discarded, leading to an astronomically large number of tail calls. Fix by writing the incremented counter back to the entry()'s frame. Fixes: dd691e847d28 ("s390/bpf: Implement bpf_jit_supports_subprog_tailcalls()") Signed-off-by: Ilya Leoshkevich Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20250813121016.163375-3-iii@linux.ibm.com --- arch/s390/net/bpf_jit_comp.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c index bfac1ddf3447..ccb83ac3e6f3 100644 --- a/arch/s390/net/bpf_jit_comp.c +++ b/arch/s390/net/bpf_jit_comp.c @@ -1793,13 +1793,6 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, /* * Copy the tail call counter to where the callee expects it. - * - * Note 1: The callee can increment the tail call counter, but - * we do not load it back, since the x86 JIT does not do this - * either. - * - * Note 2: We assume that the verifier does not let us call the - * main program, which clears the tail call counter on entry. */ if (insn->src_reg == BPF_PSEUDO_CALL) @@ -1833,6 +1826,22 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, call_r1(jit); /* lgr %b0,%r2: load return value into %b0 */ EMIT4(0xb9040000, BPF_REG_0, REG_2); + + /* + * Copy the potentially updated tail call counter back. + */ + + if (insn->src_reg == BPF_PSEUDO_CALL) + /* + * mvc frame_off+tail_call_cnt(%r15), + * tail_call_cnt(4,%r15) + */ + _EMIT6(0xd203f000 | (jit->frame_off + + offsetof(struct prog_frame, + tail_call_cnt)), + 0xf000 | offsetof(struct prog_frame, + tail_call_cnt)); + break; } case BPF_JMP | BPF_TAIL_CALL: { From bc3905a71f02511607d3ccf732360580209cac4c Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Wed, 13 Aug 2025 14:06:30 +0200 Subject: [PATCH 01176/11391] s390/bpf: Write back tail call counter for BPF_TRAMP_F_CALL_ORIG The tailcall_bpf2bpf_hierarchy_fentry test hangs on s390. Its call graph is as follows: entry() subprog_tail() trampoline() fentry() the rest of subprog_tail() # via BPF_TRAMP_F_CALL_ORIG return to entry() The problem is that the rest of subprog_tail() increments the tail call counter, but the trampoline discards the incremented value. This results in an astronomically large number of tail calls. Fix by making the trampoline write the incremented tail call counter back. Fixes: 528eb2cb87bc ("s390/bpf: Implement arch_prepare_bpf_trampoline()") Signed-off-by: Ilya Leoshkevich Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20250813121016.163375-4-iii@linux.ibm.com --- arch/s390/net/bpf_jit_comp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c index ccb83ac3e6f3..b2b8eb62b82e 100644 --- a/arch/s390/net/bpf_jit_comp.c +++ b/arch/s390/net/bpf_jit_comp.c @@ -2839,6 +2839,9 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, /* stg %r2,retval_off(%r15) */ EMIT6_DISP_LH(0xe3000000, 0x0024, REG_2, REG_0, REG_15, tjit->retval_off); + /* mvc tccnt_off(%r15),tail_call_cnt(4,%r15) */ + _EMIT6(0xd203f000 | tjit->tccnt_off, + 0xf000 | offsetof(struct prog_frame, tail_call_cnt)); im->ip_after_call = jit->prg_buf + jit->prg; From 12741630350c6ba250ffd480dbb0bbab7e8ac80a Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Wed, 13 Aug 2025 14:06:31 +0200 Subject: [PATCH 01177/11391] selftests/bpf: Clobber a lot of registers in tailcall_bpf2bpf_hierarchy tests Clobbering a lot of registers and stack slots helps exposing tail call counter overwrite bugs in JITs. Signed-off-by: Ilya Leoshkevich Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20250813121016.163375-5-iii@linux.ibm.com --- .../selftests/bpf/progs/bpf_test_utils.h | 18 ++++++++++++++++++ .../bpf/progs/tailcall_bpf2bpf_hierarchy1.c | 3 +++ .../bpf/progs/tailcall_bpf2bpf_hierarchy2.c | 3 +++ .../bpf/progs/tailcall_bpf2bpf_hierarchy3.c | 3 +++ .../progs/tailcall_bpf2bpf_hierarchy_fentry.c | 3 +++ 5 files changed, 30 insertions(+) create mode 100644 tools/testing/selftests/bpf/progs/bpf_test_utils.h diff --git a/tools/testing/selftests/bpf/progs/bpf_test_utils.h b/tools/testing/selftests/bpf/progs/bpf_test_utils.h new file mode 100644 index 000000000000..f4e67b492dd2 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/bpf_test_utils.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __BPF_TEST_UTILS_H__ +#define __BPF_TEST_UTILS_H__ + +#include +#include "bpf_misc.h" + +/* Clobber as many native registers and stack slots as possible. */ +static __always_inline void clobber_regs_stack(void) +{ + char tmp_str[] = "123456789"; + unsigned long tmp; + + bpf_strtoul(tmp_str, sizeof(tmp_str), 0, &tmp); + __sink(tmp); +} + +#endif diff --git a/tools/testing/selftests/bpf/progs/tailcall_bpf2bpf_hierarchy1.c b/tools/testing/selftests/bpf/progs/tailcall_bpf2bpf_hierarchy1.c index 327ca395e860..d556b19413d7 100644 --- a/tools/testing/selftests/bpf/progs/tailcall_bpf2bpf_hierarchy1.c +++ b/tools/testing/selftests/bpf/progs/tailcall_bpf2bpf_hierarchy1.c @@ -2,6 +2,7 @@ #include #include #include "bpf_legacy.h" +#include "bpf_test_utils.h" struct { __uint(type, BPF_MAP_TYPE_PROG_ARRAY); @@ -24,6 +25,8 @@ int entry(struct __sk_buff *skb) { int ret = 1; + clobber_regs_stack(); + count++; subprog_tail(skb); subprog_tail(skb); diff --git a/tools/testing/selftests/bpf/progs/tailcall_bpf2bpf_hierarchy2.c b/tools/testing/selftests/bpf/progs/tailcall_bpf2bpf_hierarchy2.c index 72fd0d577506..ae94c9c70ab7 100644 --- a/tools/testing/selftests/bpf/progs/tailcall_bpf2bpf_hierarchy2.c +++ b/tools/testing/selftests/bpf/progs/tailcall_bpf2bpf_hierarchy2.c @@ -2,6 +2,7 @@ #include #include #include "bpf_misc.h" +#include "bpf_test_utils.h" int classifier_0(struct __sk_buff *skb); int classifier_1(struct __sk_buff *skb); @@ -60,6 +61,8 @@ int tailcall_bpf2bpf_hierarchy_2(struct __sk_buff *skb) { int ret = 0; + clobber_regs_stack(); + subprog_tail0(skb); subprog_tail1(skb); diff --git a/tools/testing/selftests/bpf/progs/tailcall_bpf2bpf_hierarchy3.c b/tools/testing/selftests/bpf/progs/tailcall_bpf2bpf_hierarchy3.c index a7fb91cb05b7..56b6b0099840 100644 --- a/tools/testing/selftests/bpf/progs/tailcall_bpf2bpf_hierarchy3.c +++ b/tools/testing/selftests/bpf/progs/tailcall_bpf2bpf_hierarchy3.c @@ -2,6 +2,7 @@ #include #include #include "bpf_misc.h" +#include "bpf_test_utils.h" int classifier_0(struct __sk_buff *skb); @@ -53,6 +54,8 @@ int tailcall_bpf2bpf_hierarchy_3(struct __sk_buff *skb) { int ret = 0; + clobber_regs_stack(); + bpf_tail_call_static(skb, &jmp_table0, 0); __sink(ret); diff --git a/tools/testing/selftests/bpf/progs/tailcall_bpf2bpf_hierarchy_fentry.c b/tools/testing/selftests/bpf/progs/tailcall_bpf2bpf_hierarchy_fentry.c index c87f9ca982d3..5261395713cd 100644 --- a/tools/testing/selftests/bpf/progs/tailcall_bpf2bpf_hierarchy_fentry.c +++ b/tools/testing/selftests/bpf/progs/tailcall_bpf2bpf_hierarchy_fentry.c @@ -4,6 +4,7 @@ #include "vmlinux.h" #include #include +#include "bpf_test_utils.h" struct { __uint(type, BPF_MAP_TYPE_PROG_ARRAY); @@ -24,6 +25,8 @@ int subprog_tail(void *ctx) SEC("fentry/dummy") int BPF_PROG(fentry, struct sk_buff *skb) { + clobber_regs_stack(); + count++; subprog_tail(ctx); subprog_tail(ctx); From d87fdb1f27d7b1f3309bba00955f0aa1cd19b33e Mon Sep 17 00:00:00 2001 From: Fushuai Wang Date: Mon, 18 Aug 2025 11:23:44 +0800 Subject: [PATCH 01178/11391] bpf: Replace get_next_cpu() with cpumask_next_wrap() The get_next_cpu() function was only used in one place to find the next possible CPU, which can be replaced by cpumask_next_wrap(). Signed-off-by: Fushuai Wang Signed-off-by: Daniel Borkmann Acked-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20250818032344.23229-1-wangfushuai@baidu.com --- kernel/bpf/bpf_lru_list.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/kernel/bpf/bpf_lru_list.c b/kernel/bpf/bpf_lru_list.c index 2d6e1c98d8ad..e7a2fc60523f 100644 --- a/kernel/bpf/bpf_lru_list.c +++ b/kernel/bpf/bpf_lru_list.c @@ -19,14 +19,6 @@ #define LOCAL_PENDING_LIST_IDX LOCAL_LIST_IDX(BPF_LRU_LOCAL_LIST_T_PENDING) #define IS_LOCAL_LIST_TYPE(t) ((t) >= BPF_LOCAL_LIST_T_OFFSET) -static int get_next_cpu(int cpu) -{ - cpu = cpumask_next(cpu, cpu_possible_mask); - if (cpu >= nr_cpu_ids) - cpu = cpumask_first(cpu_possible_mask); - return cpu; -} - /* Local list helpers */ static struct list_head *local_free_list(struct bpf_lru_locallist *loc_l) { @@ -482,7 +474,7 @@ static struct bpf_lru_node *bpf_common_lru_pop_free(struct bpf_lru *lru, raw_spin_unlock_irqrestore(&steal_loc_l->lock, flags); - steal = get_next_cpu(steal); + steal = cpumask_next_wrap(steal, cpu_possible_mask); } while (!node && steal != first_steal); loc_l->next_steal = steal; From 5ae2da6bddebcb2e0331d1cea0db81dd812babe2 Mon Sep 17 00:00:00 2001 From: Raphael Gallais-Pou Date: Sun, 13 Jul 2025 16:24:24 +0200 Subject: [PATCH 01179/11391] ARM: dts: sti: rename SATA phy-names Stick to the documentation and rename both SATA phy-names properties to what is expected. Signed-off-by: Raphael Gallais-Pou Reviewed-by: Patrice Chotard Signed-off-by: Patrice Chotard --- arch/arm/boot/dts/st/stih407-family.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/st/stih407-family.dtsi b/arch/arm/boot/dts/st/stih407-family.dtsi index 35a55aef7f4b..3e6a0542e3ae 100644 --- a/arch/arm/boot/dts/st/stih407-family.dtsi +++ b/arch/arm/boot/dts/st/stih407-family.dtsi @@ -669,7 +669,7 @@ sata0: sata@9b20000 { interrupt-names = "hostc"; phys = <&phy_port0 PHY_TYPE_SATA>; - phy-names = "ahci_phy"; + phy-names = "sata-phy"; resets = <&powerdown STIH407_SATA0_POWERDOWN>, <&softreset STIH407_SATA0_SOFTRESET>, @@ -692,7 +692,7 @@ sata1: sata@9b28000 { interrupt-names = "hostc"; phys = <&phy_port1 PHY_TYPE_SATA>; - phy-names = "ahci_phy"; + phy-names = "sata-phy"; resets = <&powerdown STIH407_SATA1_POWERDOWN>, <&softreset STIH407_SATA1_SOFTRESET>, From cefbc3109932d7a34040b4d87746af1d36567358 Mon Sep 17 00:00:00 2001 From: Raphael Gallais-Pou Date: Sun, 13 Jul 2025 15:27:28 +0200 Subject: [PATCH 01180/11391] dt-bindings: arm: sti: drop B2120 board support B2120 boards are internal boards which never were commercialised. Remove them from bindings. Signed-off-by: Raphael Gallais-Pou Acked-by: Krzysztof Kozlowski Signed-off-by: Patrice Chotard --- Documentation/devicetree/bindings/arm/sti.yaml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/sti.yaml b/Documentation/devicetree/bindings/arm/sti.yaml index 842def3e3f2b..177358895fe1 100644 --- a/Documentation/devicetree/bindings/arm/sti.yaml +++ b/Documentation/devicetree/bindings/arm/sti.yaml @@ -14,12 +14,8 @@ properties: const: '/' compatible: oneOf: - - items: - - const: st,stih407-b2120 - - const: st,stih407 - items: - enum: - - st,stih410-b2120 - st,stih410-b2260 - const: st,stih410 - items: From 6bbe133ee8327c0a8faa0673fee839e814bb7672 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Sun, 13 Jul 2025 15:27:29 +0200 Subject: [PATCH 01181/11391] ARM: sti: removal of stih415/stih416 related entries ST's STiH415 and STiH416 platforms have already been removed since a while. Remove some remaining bits within the mach-sti. Signed-off-by: Alain Volmat Reviewed-by: Patrice Chotard Signed-off-by: Raphael Gallais-Pou Signed-off-by: Patrice Chotard --- arch/arm/mach-sti/Kconfig | 20 +------------------- arch/arm/mach-sti/board-dt.c | 2 -- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/arch/arm/mach-sti/Kconfig b/arch/arm/mach-sti/Kconfig index b3842c971d31..e58699e13e1a 100644 --- a/arch/arm/mach-sti/Kconfig +++ b/arch/arm/mach-sti/Kconfig @@ -19,31 +19,13 @@ menuconfig ARCH_STI select PL310_ERRATA_769419 if CACHE_L2X0 select RESET_CONTROLLER help - Include support for STMicroelectronics' STiH415/416, STiH407/10 and + Include support for STMicroelectronics' STiH407/10 and STiH418 family SoCs using the Device Tree for discovery. More information can be found in Documentation/arch/arm/sti/ and Documentation/devicetree. if ARCH_STI -config SOC_STIH415 - bool "STiH415 STMicroelectronics Consumer Electronics family" - default y - help - This enables support for STMicroelectronics Digital Consumer - Electronics family StiH415 parts, primarily targeted at set-top-box - and other digital audio/video applications using Flattned Device - Trees. - -config SOC_STIH416 - bool "STiH416 STMicroelectronics Consumer Electronics family" - default y - help - This enables support for STMicroelectronics Digital Consumer - Electronics family StiH416 parts, primarily targeted at set-top-box - and other digital audio/video applications using Flattened Device - Trees. - config SOC_STIH407 bool "STiH407 STMicroelectronics Consumer Electronics family" default y diff --git a/arch/arm/mach-sti/board-dt.c b/arch/arm/mach-sti/board-dt.c index 488084b61b4a..1aaf61184685 100644 --- a/arch/arm/mach-sti/board-dt.c +++ b/arch/arm/mach-sti/board-dt.c @@ -10,8 +10,6 @@ #include "smp.h" static const char *const stih41x_dt_match[] __initconst = { - "st,stih415", - "st,stih416", "st,stih407", "st,stih410", "st,stih418", From dee546e1adefd75acf0d69ddc04dc9627d745986 Mon Sep 17 00:00:00 2001 From: Raphael Gallais-Pou Date: Sun, 13 Jul 2025 15:27:30 +0200 Subject: [PATCH 01182/11391] ARM: sti: drop B2120 board support B2120 boards are internal boards which never were commercialised. Drop them. Signed-off-by: Raphael Gallais-Pou Signed-off-by: Patrice Chotard --- arch/arm/boot/dts/st/Makefile | 2 - arch/arm/boot/dts/st/stih407-b2120.dts | 27 ---- arch/arm/boot/dts/st/stih407.dtsi | 145 ----------------- arch/arm/boot/dts/st/stih410-b2120.dts | 66 -------- arch/arm/boot/dts/st/stihxxx-b2120.dtsi | 206 ------------------------ 5 files changed, 446 deletions(-) delete mode 100644 arch/arm/boot/dts/st/stih407-b2120.dts delete mode 100644 arch/arm/boot/dts/st/stih407.dtsi delete mode 100644 arch/arm/boot/dts/st/stih410-b2120.dts delete mode 100644 arch/arm/boot/dts/st/stihxxx-b2120.dtsi diff --git a/arch/arm/boot/dts/st/Makefile b/arch/arm/boot/dts/st/Makefile index 66d4f96da5dd..e906bf6ba004 100644 --- a/arch/arm/boot/dts/st/Makefile +++ b/arch/arm/boot/dts/st/Makefile @@ -13,8 +13,6 @@ dtb-$(CONFIG_ARCH_SPEAR3XX) += \ dtb-$(CONFIG_ARCH_SPEAR6XX) += \ spear600-evb.dtb dtb-$(CONFIG_ARCH_STI) += \ - stih407-b2120.dtb \ - stih410-b2120.dtb \ stih410-b2260.dtb \ stih418-b2199.dtb \ stih418-b2264.dtb diff --git a/arch/arm/boot/dts/st/stih407-b2120.dts b/arch/arm/boot/dts/st/stih407-b2120.dts deleted file mode 100644 index 9c79982ee7ba..000000000000 --- a/arch/arm/boot/dts/st/stih407-b2120.dts +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2014 STMicroelectronics (R&D) Limited. - * Author: Giuseppe Cavallaro - */ -/dts-v1/; -#include "stih407.dtsi" -#include "stihxxx-b2120.dtsi" -/ { - model = "STiH407 B2120"; - compatible = "st,stih407-b2120", "st,stih407"; - - chosen { - stdout-path = &sbc_serial0; - }; - - memory@40000000 { - device_type = "memory"; - reg = <0x40000000 0x80000000>; - }; - - aliases { - serial0 = &sbc_serial0; - ethernet0 = ðernet0; - }; - -}; diff --git a/arch/arm/boot/dts/st/stih407.dtsi b/arch/arm/boot/dts/st/stih407.dtsi deleted file mode 100644 index aca43d2bdaad..000000000000 --- a/arch/arm/boot/dts/st/stih407.dtsi +++ /dev/null @@ -1,145 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2015 STMicroelectronics Limited. - * Author: Gabriel Fernandez - */ -#include "stih407-clock.dtsi" -#include "stih407-family.dtsi" -#include -/ { - soc { - sti-display-subsystem@0 { - compatible = "st,sti-display-subsystem"; - #address-cells = <1>; - #size-cells = <1>; - reg = <0 0>; - assigned-clocks = <&clk_s_d2_quadfs 0>, - <&clk_s_d2_quadfs 1>, - <&clk_s_c0_pll1 0>, - <&clk_s_c0_flexgen CLK_COMPO_DVP>, - <&clk_s_c0_flexgen CLK_MAIN_DISP>, - <&clk_s_d2_flexgen CLK_PIX_MAIN_DISP>, - <&clk_s_d2_flexgen CLK_PIX_AUX_DISP>, - <&clk_s_d2_flexgen CLK_PIX_GDP1>, - <&clk_s_d2_flexgen CLK_PIX_GDP2>, - <&clk_s_d2_flexgen CLK_PIX_GDP3>, - <&clk_s_d2_flexgen CLK_PIX_GDP4>; - - assigned-clock-parents = <0>, - <0>, - <0>, - <&clk_s_c0_pll1 0>, - <&clk_s_c0_pll1 0>, - <&clk_s_d2_quadfs 0>, - <&clk_s_d2_quadfs 1>, - <&clk_s_d2_quadfs 0>, - <&clk_s_d2_quadfs 0>, - <&clk_s_d2_quadfs 0>, - <&clk_s_d2_quadfs 0>; - - assigned-clock-rates = <297000000>, - <108000000>, - <0>, - <400000000>, - <400000000>; - - ranges; - - sti-compositor@9d11000 { - compatible = "st,stih407-compositor"; - reg = <0x9d11000 0x1000>; - - clock-names = "compo_main", - "compo_aux", - "pix_main", - "pix_aux", - "pix_gdp1", - "pix_gdp2", - "pix_gdp3", - "pix_gdp4", - "main_parent", - "aux_parent"; - - clocks = <&clk_s_c0_flexgen CLK_COMPO_DVP>, - <&clk_s_c0_flexgen CLK_COMPO_DVP>, - <&clk_s_d2_flexgen CLK_PIX_MAIN_DISP>, - <&clk_s_d2_flexgen CLK_PIX_AUX_DISP>, - <&clk_s_d2_flexgen CLK_PIX_GDP1>, - <&clk_s_d2_flexgen CLK_PIX_GDP2>, - <&clk_s_d2_flexgen CLK_PIX_GDP3>, - <&clk_s_d2_flexgen CLK_PIX_GDP4>, - <&clk_s_d2_quadfs 0>, - <&clk_s_d2_quadfs 1>; - - reset-names = "compo-main", "compo-aux"; - resets = <&softreset STIH407_COMPO_SOFTRESET>, - <&softreset STIH407_COMPO_SOFTRESET>; - st,vtg = <&vtg_main>, <&vtg_aux>; - }; - - sti-tvout@8d08000 { - compatible = "st,stih407-tvout"; - reg = <0x8d08000 0x1000>; - reg-names = "tvout-reg"; - reset-names = "tvout"; - resets = <&softreset STIH407_HDTVOUT_SOFTRESET>; - #address-cells = <1>; - #size-cells = <1>; - assigned-clocks = <&clk_s_d2_flexgen CLK_PIX_HDMI>, - <&clk_s_d2_flexgen CLK_TMDS_HDMI>, - <&clk_s_d2_flexgen CLK_REF_HDMIPHY>, - <&clk_s_d0_flexgen CLK_PCM_0>, - <&clk_s_d2_flexgen CLK_PIX_HDDAC>, - <&clk_s_d2_flexgen CLK_HDDAC>; - - assigned-clock-parents = <&clk_s_d2_quadfs 0>, - <&clk_tmdsout_hdmi>, - <&clk_s_d2_quadfs 0>, - <&clk_s_d0_quadfs 0>, - <&clk_s_d2_quadfs 0>, - <&clk_s_d2_quadfs 0>; - }; - - sti_hdmi: sti-hdmi@8d04000 { - compatible = "st,stih407-hdmi"; - reg = <0x8d04000 0x1000>; - reg-names = "hdmi-reg"; - #sound-dai-cells = <0>; - interrupts = ; - interrupt-names = "irq"; - clock-names = "pix", - "tmds", - "phy", - "audio", - "main_parent", - "aux_parent"; - - clocks = <&clk_s_d2_flexgen CLK_PIX_HDMI>, - <&clk_s_d2_flexgen CLK_TMDS_HDMI>, - <&clk_s_d2_flexgen CLK_REF_HDMIPHY>, - <&clk_s_d0_flexgen CLK_PCM_0>, - <&clk_s_d2_quadfs 0>, - <&clk_s_d2_quadfs 1>; - - hdmi,hpd-gpio = <&pio5 3 GPIO_ACTIVE_LOW>; - reset-names = "hdmi"; - resets = <&softreset STIH407_HDMI_TX_PHY_SOFTRESET>; - ddc = <&hdmiddc>; - }; - - sti-hda@8d02000 { - compatible = "st,stih407-hda"; - reg = <0x8d02000 0x400>, <0x92b0120 0x4>; - reg-names = "hda-reg", "video-dacs-ctrl"; - clock-names = "pix", - "hddac", - "main_parent", - "aux_parent"; - clocks = <&clk_s_d2_flexgen CLK_PIX_HDDAC>, - <&clk_s_d2_flexgen CLK_HDDAC>, - <&clk_s_d2_quadfs 0>, - <&clk_s_d2_quadfs 1>; - }; - }; - }; -}; diff --git a/arch/arm/boot/dts/st/stih410-b2120.dts b/arch/arm/boot/dts/st/stih410-b2120.dts deleted file mode 100644 index 538ff98ca1b1..000000000000 --- a/arch/arm/boot/dts/st/stih410-b2120.dts +++ /dev/null @@ -1,66 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2014 STMicroelectronics (R&D) Limited. - * Author: Peter Griffin - */ -/dts-v1/; -#include "stih410.dtsi" -#include "stihxxx-b2120.dtsi" -/ { - model = "STiH410 B2120"; - compatible = "st,stih410-b2120", "st,stih410"; - - chosen { - stdout-path = &sbc_serial0; - }; - - memory@40000000 { - device_type = "memory"; - reg = <0x40000000 0x80000000>; - }; - - aliases { - serial0 = &sbc_serial0; - ethernet0 = ðernet0; - }; - - usb2_picophy1: phy2 { - status = "okay"; - }; - - usb2_picophy2: phy3 { - status = "okay"; - }; - - soc { - - mmc0: sdhci@9060000 { - max-frequency = <200000000>; - sd-uhs-sdr50; - sd-uhs-sdr104; - sd-uhs-ddr50; - }; - - ohci0: usb@9a03c00 { - status = "okay"; - }; - - ehci0: usb@9a03e00 { - status = "okay"; - }; - - ohci1: usb@9a83c00 { - status = "okay"; - }; - - ehci1: usb@9a83e00 { - status = "okay"; - }; - - sti-display-subsystem@0 { - sti-hda@8d02000 { - status = "okay"; - }; - }; - }; -}; diff --git a/arch/arm/boot/dts/st/stihxxx-b2120.dtsi b/arch/arm/boot/dts/st/stihxxx-b2120.dtsi deleted file mode 100644 index 8d9a2dfa76f1..000000000000 --- a/arch/arm/boot/dts/st/stihxxx-b2120.dtsi +++ /dev/null @@ -1,206 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2014 STMicroelectronics (R&D) Limited. - * Author: Giuseppe Cavallaro - */ -#include -#include -#include -/ { - leds { - compatible = "gpio-leds"; - led-red { - label = "Front Panel LED"; - gpios = <&pio4 1 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "heartbeat"; - }; - led-green { - gpios = <&pio1 3 GPIO_ACTIVE_HIGH>; - default-state = "off"; - }; - }; - - sound: sound { - compatible = "simple-audio-card"; - simple-audio-card,name = "STI-B2120"; - status = "okay"; - #address-cells = <1>; - #size-cells = <0>; - - simple-audio-card,dai-link@0 { - reg = <0>; - /* HDMI */ - format = "i2s"; - mclk-fs = <128>; - cpu { - sound-dai = <&sti_uni_player0>; - }; - - codec { - sound-dai = <&sti_hdmi>; - }; - }; - - simple-audio-card,dai-link@1 { - reg = <1>; - /* DAC */ - format = "i2s"; - mclk-fs = <256>; - frame-inversion; - cpu { - sound-dai = <&sti_uni_player2>; - }; - - codec { - sound-dai = <&sti_sasg_codec 1>; - }; - }; - - simple-audio-card,dai-link@2 { - reg = <2>; - /* SPDIF */ - format = "left_j"; - mclk-fs = <128>; - cpu { - sound-dai = <&sti_uni_player3>; - }; - - codec { - sound-dai = <&sti_sasg_codec 0>; - }; - }; - }; - - miphy28lp_phy: miphy28lp { - - phy_port0: port@9b22000 { - st,osc-rdy; - }; - - phy_port1: port@9b2a000 { - st,osc-force-ext; - }; - }; - - soc { - sbc_serial0: serial@9530000 { - status = "okay"; - }; - - pwm0: pwm@9810000 { - status = "okay"; - }; - - pwm1: pwm@9510000 { - status = "okay"; - }; - - ssc2: i2c@9842000 { - status = "okay"; - clock-frequency = <100000>; - st,i2c-min-scl-pulse-width-us = <0>; - st,i2c-min-sda-pulse-width-us = <5>; - }; - - ssc3: i2c@9843000 { - status = "okay"; - clock-frequency = <100000>; - st,i2c-min-scl-pulse-width-us = <0>; - st,i2c-min-sda-pulse-width-us = <5>; - }; - - i2c@9844000 { - status = "okay"; - }; - - i2c@9845000 { - status = "okay"; - }; - - i2c@9540000 { - status = "okay"; - }; - - mmc0: sdhci@9060000 { - non-removable; - status = "okay"; - }; - - mmc1: sdhci@9080000 { - status = "okay"; - }; - - /* SSC11 to HDMI */ - hdmiddc: i2c@9541000 { - status = "okay"; - /* HDMI V1.3a supports Standard mode only */ - clock-frequency = <100000>; - st,i2c-min-scl-pulse-width-us = <0>; - st,i2c-min-sda-pulse-width-us = <5>; - }; - - st_dwc3: dwc3@8f94000 { - status = "okay"; - }; - - ethernet0: dwmac@9630000 { - st,tx-retime-src = "clkgen"; - status = "okay"; - phy-mode = "rgmii"; - fixed-link = <0 1 1000 0 0>; - }; - - demux@8a20000 { - compatible = "st,stih407-c8sectpfe"; - status = "okay"; - reg = <0x08a20000 0x10000>, - <0x08a00000 0x4000>; - reg-names = "c8sectpfe", "c8sectpfe-ram"; - interrupts = , - ; - interrupt-names = "c8sectpfe-error-irq", - "c8sectpfe-idle-irq"; - pinctrl-0 = <&pinctrl_tsin0_serial>; - pinctrl-1 = <&pinctrl_tsin0_parallel>; - pinctrl-2 = <&pinctrl_tsin3_serial>; - pinctrl-3 = <&pinctrl_tsin4_serial_alt3>; - pinctrl-4 = <&pinctrl_tsin5_serial_alt1>; - pinctrl-names = "tsin0-serial", - "tsin0-parallel", - "tsin3-serial", - "tsin4-serial", - "tsin5-serial"; - clocks = <&clk_s_c0_flexgen CLK_PROC_STFE>; - clock-names = "c8sectpfe"; - - /* tsin0 is TSA on NIMA */ - tsin0: port { - tsin-num = <0>; - serial-not-parallel; - i2c-bus = <&ssc2>; - reset-gpios = <&pio15 4 GPIO_ACTIVE_LOW>; - dvb-card = ; - }; - }; - - sti_uni_player0: sti-uni-player@8d80000 { - status = "okay"; - }; - - sti_uni_player2: sti-uni-player@8d82000 { - status = "okay"; - }; - - sti_uni_player3: sti-uni-player@8d85000 { - status = "okay"; - }; - - syscfg_core: core-syscfg@92b0000 { - sti_sasg_codec: sti-sasg-codec { - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_spdif_out>; - }; - }; - }; -}; From 2be3fd903a6775ce21b2a138950aab09d0998427 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Mon, 18 Aug 2025 16:02:04 +0200 Subject: [PATCH 01183/11391] selftests/nolibc: be more specific about variables affecting nolibc-test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only one of these variables is used. $CC is preferred over $CROSS_COMPILE. Make this clear in the help message. Suggested-by: Willy Tarreau Link: https://lore.kernel.org/lkml/20250817093905.GA14213@1wt.eu/ Signed-off-by: Thomas Weißschuh --- tools/testing/selftests/nolibc/Makefile.nolibc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/nolibc/Makefile.nolibc b/tools/testing/selftests/nolibc/Makefile.nolibc index 0fb759ba992e..b013a5d724c9 100644 --- a/tools/testing/selftests/nolibc/Makefile.nolibc +++ b/tools/testing/selftests/nolibc/Makefile.nolibc @@ -267,7 +267,7 @@ help: @echo " all call the \"run\" target below" @echo " help this help" @echo " sysroot create the nolibc sysroot here (uses \$$ARCH)" - @echo " nolibc-test build the executable (uses \$$CC and \$$CROSS_COMPILE)" + @echo " nolibc-test build the executable (uses \$$CC or \$$CROSS_COMPILE)" @echo " libc-test build an executable using the compiler's default libc instead" @echo " run-user runs the executable under QEMU (uses \$$XARCH, \$$TEST)" @echo " initramfs.cpio prepare the initramfs archive with nolibc-test" From 32042f638cb839b4eb4a76b5dfc7c0a412327a6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sat, 19 Jul 2025 17:38:27 +0200 Subject: [PATCH 01184/11391] selftests/nolibc: deduplicate invocations of toplevel Makefile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Various targets of the testsuite call back into the toplevel kernel Makefile. These calls use various parameters and are quite long. Introduce a common variable to make future changes smaller and the lines shorter. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://lore.kernel.org/r/20250719-nolibc-llvm-system-v1-1-1730216ce171@weissschuh.net --- tools/testing/selftests/nolibc/Makefile.nolibc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/nolibc/Makefile.nolibc b/tools/testing/selftests/nolibc/Makefile.nolibc index b013a5d724c9..d8dbb63fe4f7 100644 --- a/tools/testing/selftests/nolibc/Makefile.nolibc +++ b/tools/testing/selftests/nolibc/Makefile.nolibc @@ -262,6 +262,9 @@ REPORT ?= awk '/\[OK\][\r]*$$/{p++} /\[FAIL\][\r]*$$/{if (!f) printf("\n"); f++ if (f || !p || !done) printf("failure\n"); else if (s) printf("warning\n"); else printf("success\n");; \ printf("\nSee all results in %s\n", ARGV[1]); }' +# Execute the toplevel kernel Makefile +KBUILD_MAKE = $(MAKE) -C $(srctree) ARCH=$(ARCH) CC=$(CC) CROSS_COMPILE=$(CROSS_COMPILE) + help: @echo "Supported targets under selftests/nolibc:" @echo " all call the \"run\" target below" @@ -340,17 +343,17 @@ initramfs: nolibc-test $(Q)cp nolibc-test initramfs/init defconfig: - $(Q)$(MAKE) -C $(srctree) ARCH=$(ARCH) CC=$(CC) CROSS_COMPILE=$(CROSS_COMPILE) $(DEFCONFIG) + $(Q)$(KBUILD_MAKE) $(DEFCONFIG) $(Q)if [ -n "$(EXTRACONFIG)" ]; then \ $(srctree)/scripts/config --file $(objtree)/.config $(EXTRACONFIG); \ - $(MAKE) -C $(srctree) ARCH=$(ARCH) CC=$(CC) CROSS_COMPILE=$(CROSS_COMPILE) olddefconfig < /dev/null; \ + $(KBUILD_MAKE) olddefconfig < /dev/null; \ fi kernel: - $(Q)$(MAKE) -C $(srctree) ARCH=$(ARCH) CC=$(CC) CROSS_COMPILE=$(CROSS_COMPILE) $(IMAGE_NAME) < /dev/null + $(Q)$(KBUILD_MAKE) $(IMAGE_NAME) < /dev/null kernel-standalone: initramfs - $(Q)$(MAKE) -C $(srctree) ARCH=$(ARCH) CC=$(CC) CROSS_COMPILE=$(CROSS_COMPILE) $(IMAGE_NAME) CONFIG_INITRAMFS_SOURCE=$(CURDIR)/initramfs < /dev/null + $(Q)$(KBUILD_MAKE) $(IMAGE_NAME) CONFIG_INITRAMFS_SOURCE=$(CURDIR)/initramfs < /dev/null # run the tests after building the kernel run: kernel initramfs.cpio From 1a5b40317dcbcd5e498cc8d2b3e5f48755bab322 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sat, 19 Jul 2025 17:38:28 +0200 Subject: [PATCH 01185/11391] selftests/nolibc: don't pass CC to toplevel Makefile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The toplevel Makefile is capable of calculating CC from CROSS_COMPILE and/or ARCH. Stop passing the unnecessary variable. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://lore.kernel.org/r/20250719-nolibc-llvm-system-v1-2-1730216ce171@weissschuh.net --- tools/testing/selftests/nolibc/Makefile.nolibc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/nolibc/Makefile.nolibc b/tools/testing/selftests/nolibc/Makefile.nolibc index d8dbb63fe4f7..ebb097d228b9 100644 --- a/tools/testing/selftests/nolibc/Makefile.nolibc +++ b/tools/testing/selftests/nolibc/Makefile.nolibc @@ -263,7 +263,7 @@ REPORT ?= awk '/\[OK\][\r]*$$/{p++} /\[FAIL\][\r]*$$/{if (!f) printf("\n"); f++ printf("\nSee all results in %s\n", ARGV[1]); }' # Execute the toplevel kernel Makefile -KBUILD_MAKE = $(MAKE) -C $(srctree) ARCH=$(ARCH) CC=$(CC) CROSS_COMPILE=$(CROSS_COMPILE) +KBUILD_MAKE = $(MAKE) -C $(srctree) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) help: @echo "Supported targets under selftests/nolibc:" From 850047b19741490631855a475ccaa3ed29316039 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sat, 19 Jul 2025 17:38:29 +0200 Subject: [PATCH 01186/11391] selftests/nolibc: always compile the kernel with GCC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LLVM/clang can not build the kernel for all architectures supported by nolibc. The current setup uses the same compiler to build the kernel as is used for nolibc-test. This prevents using the full qemu-system tests for LLVM builds. Instead always build the kernel with GCC. For the nolibc testsuite the kernel does not need to be built with LLVM. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://lore.kernel.org/r/20250719-nolibc-llvm-system-v1-3-1730216ce171@weissschuh.net --- tools/testing/selftests/nolibc/Makefile.nolibc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/nolibc/Makefile.nolibc b/tools/testing/selftests/nolibc/Makefile.nolibc index ebb097d228b9..330e000baeb1 100644 --- a/tools/testing/selftests/nolibc/Makefile.nolibc +++ b/tools/testing/selftests/nolibc/Makefile.nolibc @@ -263,7 +263,7 @@ REPORT ?= awk '/\[OK\][\r]*$$/{p++} /\[FAIL\][\r]*$$/{if (!f) printf("\n"); f++ printf("\nSee all results in %s\n", ARGV[1]); }' # Execute the toplevel kernel Makefile -KBUILD_MAKE = $(MAKE) -C $(srctree) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) +KBUILD_MAKE = $(MAKE) -C $(srctree) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) LLVM= help: @echo "Supported targets under selftests/nolibc:" @@ -276,8 +276,8 @@ help: @echo " initramfs.cpio prepare the initramfs archive with nolibc-test" @echo " initramfs prepare the initramfs tree with nolibc-test" @echo " defconfig create a fresh new default config (uses \$$XARCH)" - @echo " kernel (re)build the kernel (uses \$$XARCH)" - @echo " kernel-standalone (re)build the kernel with the initramfs (uses \$$XARCH)" + @echo " kernel (re)build the kernel (uses \$$XARCH, \$$CROSS_COMPILE)" + @echo " kernel-standalone (re)build the kernel with the initramfs (uses \$$XARCH, \$$CROSS_COMPILE)" @echo " run runs the kernel in QEMU after building it (uses \$$XARCH, \$$TEST)" @echo " rerun runs a previously prebuilt kernel in QEMU (uses \$$XARCH, \$$TEST)" @echo " clean clean the sysroot, initramfs, build and output files" From 52ff2b840bc723f3be1f096f8017c78e0515858c Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Sun, 17 Aug 2025 20:13:50 +0300 Subject: [PATCH 01187/11391] 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 26178b713f2b3f5bc411ed8316d1635615896111 Mon Sep 17 00:00:00 2001 From: "Masami Hiramatsu (Google)" Date: Wed, 30 Jul 2025 16:46:52 +0900 Subject: [PATCH 01188/11391] x86/insn: Add XOP prefix instructions decoder support Support decoding AMD's XOP prefix encoded instructions. These instructions are introduced for Bulldozer micro architecture, and not supported on Intel's processors. But when compiling kernel with CONFIG_X86_NATIVE_CPU on some AMD processor (e.g. -march=bdver2), these instructions can be used. Closes: https://lore.kernel.org/all/871pq06728.fsf@wylie.me.uk/ Reported-by: Alan J. Wylie Signed-off-by: Masami Hiramatsu (Google) Signed-off-by: Borislav Petkov (AMD) Tested-by: Alan J. Wylie Link: https://lore.kernel.org/175386161199.564247.597496379413236944.stgit@devnote2 --- arch/x86/include/asm/inat.h | 15 +++ arch/x86/include/asm/insn.h | 51 +++++++- arch/x86/lib/inat.c | 13 ++ arch/x86/lib/insn.c | 35 ++++-- arch/x86/lib/x86-opcode-map.txt | 111 +++++++++++++++++- arch/x86/tools/gen-insn-attr-x86.awk | 44 +++++++ tools/arch/x86/include/asm/inat.h | 15 +++ tools/arch/x86/include/asm/insn.h | 51 +++++++- tools/arch/x86/lib/inat.c | 13 ++ tools/arch/x86/lib/insn.c | 35 ++++-- tools/arch/x86/lib/x86-opcode-map.txt | 111 +++++++++++++++++- tools/arch/x86/tools/gen-insn-attr-x86.awk | 44 +++++++ .../intel-pt-decoder/intel-pt-insn-decoder.c | 2 +- 13 files changed, 513 insertions(+), 27 deletions(-) diff --git a/arch/x86/include/asm/inat.h b/arch/x86/include/asm/inat.h index 97f341777db5..1b3060a3425c 100644 --- a/arch/x86/include/asm/inat.h +++ b/arch/x86/include/asm/inat.h @@ -37,6 +37,8 @@ #define INAT_PFX_EVEX 15 /* EVEX prefix */ /* x86-64 REX2 prefix */ #define INAT_PFX_REX2 16 /* 0xD5 */ +/* AMD XOP prefix */ +#define INAT_PFX_XOP 17 /* 0x8F */ #define INAT_LSTPFX_MAX 3 #define INAT_LGCPFX_MAX 11 @@ -77,6 +79,7 @@ #define INAT_MOFFSET (1 << (INAT_FLAG_OFFS + 3)) #define INAT_VARIANT (1 << (INAT_FLAG_OFFS + 4)) #define INAT_VEXOK (1 << (INAT_FLAG_OFFS + 5)) +#define INAT_XOPOK INAT_VEXOK #define INAT_VEXONLY (1 << (INAT_FLAG_OFFS + 6)) #define INAT_EVEXONLY (1 << (INAT_FLAG_OFFS + 7)) #define INAT_NO_REX2 (1 << (INAT_FLAG_OFFS + 8)) @@ -111,6 +114,8 @@ extern insn_attr_t inat_get_group_attribute(insn_byte_t modrm, extern insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, insn_byte_t vex_m, insn_byte_t vex_pp); +extern insn_attr_t inat_get_xop_attribute(insn_byte_t opcode, + insn_byte_t map_select); /* Attribute checking functions */ static inline int inat_is_legacy_prefix(insn_attr_t attr) @@ -164,6 +169,11 @@ static inline int inat_is_vex3_prefix(insn_attr_t attr) return (attr & INAT_PFX_MASK) == INAT_PFX_VEX3; } +static inline int inat_is_xop_prefix(insn_attr_t attr) +{ + return (attr & INAT_PFX_MASK) == INAT_PFX_XOP; +} + static inline int inat_is_escape(insn_attr_t attr) { return attr & INAT_ESC_MASK; @@ -229,6 +239,11 @@ static inline int inat_accept_vex(insn_attr_t attr) return attr & INAT_VEXOK; } +static inline int inat_accept_xop(insn_attr_t attr) +{ + return attr & INAT_XOPOK; +} + static inline int inat_must_vex(insn_attr_t attr) { return attr & (INAT_VEXONLY | INAT_EVEXONLY); diff --git a/arch/x86/include/asm/insn.h b/arch/x86/include/asm/insn.h index 7152ea809e6a..091f88c8254d 100644 --- a/arch/x86/include/asm/insn.h +++ b/arch/x86/include/asm/insn.h @@ -71,7 +71,10 @@ struct insn { * prefixes.bytes[3]: last prefix */ struct insn_field rex_prefix; /* REX prefix */ - struct insn_field vex_prefix; /* VEX prefix */ + union { + struct insn_field vex_prefix; /* VEX prefix */ + struct insn_field xop_prefix; /* XOP prefix */ + }; struct insn_field opcode; /* * opcode.bytes[0]: opcode1 * opcode.bytes[1]: opcode2 @@ -135,6 +138,17 @@ struct insn { #define X86_VEX_V(vex) (((vex) & 0x78) >> 3) /* VEX3 Byte2, VEX2 Byte1 */ #define X86_VEX_P(vex) ((vex) & 0x03) /* VEX3 Byte2, VEX2 Byte1 */ #define X86_VEX_M_MAX 0x1f /* VEX3.M Maximum value */ +/* XOP bit fields */ +#define X86_XOP_R(xop) ((xop) & 0x80) /* XOP Byte2 */ +#define X86_XOP_X(xop) ((xop) & 0x40) /* XOP Byte2 */ +#define X86_XOP_B(xop) ((xop) & 0x20) /* XOP Byte2 */ +#define X86_XOP_M(xop) ((xop) & 0x1f) /* XOP Byte2 */ +#define X86_XOP_W(xop) ((xop) & 0x80) /* XOP Byte3 */ +#define X86_XOP_V(xop) ((xop) & 0x78) /* XOP Byte3 */ +#define X86_XOP_L(xop) ((xop) & 0x04) /* XOP Byte3 */ +#define X86_XOP_P(xop) ((xop) & 0x03) /* XOP Byte3 */ +#define X86_XOP_M_MIN 0x08 /* Min of XOP.M */ +#define X86_XOP_M_MAX 0x1f /* Max of XOP.M */ extern void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64); extern int insn_get_prefixes(struct insn *insn); @@ -178,7 +192,7 @@ static inline insn_byte_t insn_rex2_m_bit(struct insn *insn) return X86_REX2_M(insn->rex_prefix.bytes[1]); } -static inline int insn_is_avx(struct insn *insn) +static inline int insn_is_avx_or_xop(struct insn *insn) { if (!insn->prefixes.got) insn_get_prefixes(insn); @@ -192,6 +206,22 @@ static inline int insn_is_evex(struct insn *insn) return (insn->vex_prefix.nbytes == 4); } +/* If we already know this is AVX/XOP encoded */ +static inline int avx_insn_is_xop(struct insn *insn) +{ + insn_attr_t attr = inat_get_opcode_attribute(insn->vex_prefix.bytes[0]); + + return inat_is_xop_prefix(attr); +} + +static inline int insn_is_xop(struct insn *insn) +{ + if (!insn_is_avx_or_xop(insn)) + return 0; + + return avx_insn_is_xop(insn); +} + static inline int insn_has_emulate_prefix(struct insn *insn) { return !!insn->emulate_prefix_size; @@ -222,11 +252,26 @@ static inline insn_byte_t insn_vex_w_bit(struct insn *insn) return X86_VEX_W(insn->vex_prefix.bytes[2]); } +static inline insn_byte_t insn_xop_map_bits(struct insn *insn) +{ + if (insn->xop_prefix.nbytes < 3) /* XOP is 3 bytes */ + return 0; + return X86_XOP_M(insn->xop_prefix.bytes[1]); +} + +static inline insn_byte_t insn_xop_p_bits(struct insn *insn) +{ + return X86_XOP_P(insn->vex_prefix.bytes[2]); +} + /* Get the last prefix id from last prefix or VEX prefix */ static inline int insn_last_prefix_id(struct insn *insn) { - if (insn_is_avx(insn)) + if (insn_is_avx_or_xop(insn)) { + if (avx_insn_is_xop(insn)) + return insn_xop_p_bits(insn); return insn_vex_p_bits(insn); /* VEX_p is a SIMD prefix id */ + } if (insn->prefixes.bytes[3]) return inat_get_last_prefix_id(insn->prefixes.bytes[3]); diff --git a/arch/x86/lib/inat.c b/arch/x86/lib/inat.c index b0f3b2a62ae2..a5cafd402cfd 100644 --- a/arch/x86/lib/inat.c +++ b/arch/x86/lib/inat.c @@ -81,3 +81,16 @@ insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, insn_byte_t vex_m, return table[opcode]; } +insn_attr_t inat_get_xop_attribute(insn_byte_t opcode, insn_byte_t map_select) +{ + const insn_attr_t *table; + + if (map_select < X86_XOP_M_MIN || map_select > X86_XOP_M_MAX) + return 0; + map_select -= X86_XOP_M_MIN; + /* At first, this checks the master table */ + table = inat_xop_tables[map_select]; + if (!table) + return 0; + return table[opcode]; +} diff --git a/arch/x86/lib/insn.c b/arch/x86/lib/insn.c index 149a57e334ab..225af1399c9d 100644 --- a/arch/x86/lib/insn.c +++ b/arch/x86/lib/insn.c @@ -200,12 +200,15 @@ int insn_get_prefixes(struct insn *insn) } insn->rex_prefix.got = 1; - /* Decode VEX prefix */ + /* Decode VEX/XOP prefix */ b = peek_next(insn_byte_t, insn); - attr = inat_get_opcode_attribute(b); - if (inat_is_vex_prefix(attr)) { + if (inat_is_vex_prefix(attr) || inat_is_xop_prefix(attr)) { insn_byte_t b2 = peek_nbyte_next(insn_byte_t, insn, 1); - if (!insn->x86_64) { + + if (inat_is_xop_prefix(attr) && X86_MODRM_REG(b2) == 0) { + /* Grp1A.0 is always POP Ev */ + goto vex_end; + } else if (!insn->x86_64) { /* * In 32-bits mode, if the [7:6] bits (mod bits of * ModRM) on the second byte are not 11b, it is @@ -226,13 +229,13 @@ int insn_get_prefixes(struct insn *insn) if (insn->x86_64 && X86_VEX_W(b2)) /* VEX.W overrides opnd_size */ insn->opnd_bytes = 8; - } else if (inat_is_vex3_prefix(attr)) { + } else if (inat_is_vex3_prefix(attr) || inat_is_xop_prefix(attr)) { b2 = peek_nbyte_next(insn_byte_t, insn, 2); insn_set_byte(&insn->vex_prefix, 2, b2); insn->vex_prefix.nbytes = 3; insn->next_byte += 3; if (insn->x86_64 && X86_VEX_W(b2)) - /* VEX.W overrides opnd_size */ + /* VEX.W/XOP.W overrides opnd_size */ insn->opnd_bytes = 8; } else { /* @@ -288,9 +291,22 @@ int insn_get_opcode(struct insn *insn) insn_set_byte(opcode, 0, op); opcode->nbytes = 1; - /* Check if there is VEX prefix or not */ - if (insn_is_avx(insn)) { + /* Check if there is VEX/XOP prefix or not */ + if (insn_is_avx_or_xop(insn)) { insn_byte_t m, p; + + /* XOP prefix has different encoding */ + if (unlikely(avx_insn_is_xop(insn))) { + m = insn_xop_map_bits(insn); + insn->attr = inat_get_xop_attribute(op, m); + if (!inat_accept_xop(insn->attr)) { + insn->attr = 0; + return -EINVAL; + } + /* XOP has only 1 byte for opcode */ + goto end; + } + m = insn_vex_m_bits(insn); p = insn_vex_p_bits(insn); insn->attr = inat_get_avx_attribute(op, m, p); @@ -383,7 +399,8 @@ int insn_get_modrm(struct insn *insn) pfx_id = insn_last_prefix_id(insn); insn->attr = inat_get_group_attribute(mod, pfx_id, insn->attr); - if (insn_is_avx(insn) && !inat_accept_vex(insn->attr)) { + if (insn_is_avx_or_xop(insn) && !inat_accept_vex(insn->attr) && + !inat_accept_xop(insn->attr)) { /* Bad insn */ insn->attr = 0; return -EINVAL; diff --git a/arch/x86/lib/x86-opcode-map.txt b/arch/x86/lib/x86-opcode-map.txt index 262f7ca1fb95..2a4e69ecc2de 100644 --- a/arch/x86/lib/x86-opcode-map.txt +++ b/arch/x86/lib/x86-opcode-map.txt @@ -27,6 +27,11 @@ # (evo): this opcode is changed by EVEX prefix (EVEX opcode) # (v): this opcode requires VEX prefix. # (v1): this opcode only supports 128bit VEX. +# (xop): this opcode accepts XOP prefix. +# +# XOP Superscripts +# (W=0): this opcode requires XOP.W == 0 +# (W=1): this opcode requires XOP.W == 1 # # Last Prefix Superscripts # - (66): the last prefix is 0x66 @@ -194,7 +199,7 @@ AVXcode: 8c: MOV Ev,Sw 8d: LEA Gv,M 8e: MOV Sw,Ew -8f: Grp1A (1A) | POP Ev (d64) +8f: Grp1A (1A) | POP Ev (d64) | XOP (Prefix) # 0x90 - 0x9f 90: NOP | PAUSE (F3) | XCHG r8,rAX 91: XCHG rCX/r9,rAX @@ -1106,6 +1111,84 @@ AVXcode: 7 f8: URDMSR Rq,Id (F2),(v1),(11B) | UWRMSR Id,Rq (F3),(v1),(11B) EndTable +# From AMD64 Architecture Programmer's Manual Vol3, Appendix A.1.5 +Table: XOP map 8h +Referrer: +XOPcode: 0 +85: VPMACSSWW Vo,Ho,Wo,Lo +86: VPMACSSWD Vo,Ho,Wo,Lo +87: VPMACSSDQL Vo,Ho,Wo,Lo +8e: VPMACSSDD Vo,Ho,Wo,Lo +8f: VPMACSSDQH Vo,Ho,Wo,Lo +95: VPMACSWW Vo,Ho,Wo,Lo +96: VPMACSWD Vo,Ho,Wo,Lo +97: VPMACSDQL Vo,Ho,Wo,Lo +9e: VPMACSDD Vo,Ho,Wo,Lo +9f: VPMACSDQH Vo,Ho,Wo,Lo +a2: VPCMOV Vx,Hx,Wx,Lx (W=0) | VPCMOV Vx,Hx,Lx,Wx (W=1) +a3: VPPERM Vo,Ho,Wo,Lo (W=0) | VPPERM Vo,Ho,Lo,Wo (W=1) +a6: VPMADCSSWD Vo,Ho,Wo,Lo +b6: VPMADCSWD Vo,Ho,Wo,Lo +c0: VPROTB Vo,Wo,Ib +c1: VPROTW Vo,Wo,Ib +c2: VPROTD Vo,Wo,Ib +c3: VPROTQ Vo,Wo,Ib +cc: VPCOMccB Vo,Ho,Wo,Ib +cd: VPCOMccW Vo,Ho,Wo,Ib +ce: VPCOMccD Vo,Ho,Wo,Ib +cf: VPCOMccQ Vo,Ho,Wo,Ib +ec: VPCOMccUB Vo,Ho,Wo,Ib +ed: VPCOMccUW Vo,Ho,Wo,Ib +ee: VPCOMccUD Vo,Ho,Wo,Ib +ef: VPCOMccUQ Vo,Ho,Wo,Ib +EndTable + +Table: XOP map 9h +Referrer: +XOPcode: 1 +01: GrpXOP1 +02: GrpXOP2 +12: GrpXOP3 +80: VFRCZPS Vx,Wx +81: VFRCZPD Vx,Wx +82: VFRCZSS Vq,Wss +83: VFRCZSD Vq,Wsd +90: VPROTB Vo,Wo,Ho (W=0) | VPROTB Vo,Ho,Wo (W=1) +91: VPROTW Vo,Wo,Ho (W=0) | VPROTB Vo,Ho,Wo (W=1) +92: VPROTD Vo,Wo,Ho (W=0) | VPROTB Vo,Ho,Wo (W=1) +93: VPROTQ Vo,Wo,Ho (W=0) | VPROTB Vo,Ho,Wo (W=1) +94: VPSHLB Vo,Wo,Ho (W=0) | VPSHLB Vo,Ho,Wo (W=1) +95: VPSHLW Vo,Wo,Ho (W=0) | VPSHLW Vo,Ho,Wo (W=1) +96: VPSHLD Vo,Wo,Ho (W=0) | VPSHLD Vo,Ho,Wo (W=1) +97: VPSHLQ Vo,Wo,Ho (W=0) | VPSHLQ Vo,Ho,Wo (W=1) +98: VPSHAB Vo,Wo,Ho (W=0) | VPSHAB Vo,Ho,Wo (W=1) +99: VPSHAW Vo,Wo,Ho (W=0) | VPSHAW Vo,Ho,Wo (W=1) +9a: VPSHAD Vo,Wo,Ho (W=0) | VPSHAD Vo,Ho,Wo (W=1) +9b: VPSHAQ Vo,Wo,Ho (W=0) | VPSHAQ Vo,Ho,Wo (W=1) +c1: VPHADDBW Vo,Wo +c2: VPHADDBD Vo,Wo +c3: VPHADDBQ Vo,Wo +c6: VPHADDWD Vo,Wo +c7: VPHADDWQ Vo,Wo +cb: VPHADDDQ Vo,Wo +d1: VPHADDUBWD Vo,Wo +d2: VPHADDUBD Vo,Wo +d3: VPHADDUBQ Vo,Wo +d6: VPHADDUWD Vo,Wo +d7: VPHADDUWQ Vo,Wo +db: VPHADDUDQ Vo,Wo +e1: VPHSUBBW Vo,Wo +e2: VPHSUBWD Vo,Wo +e3: VPHSUBDQ Vo,Wo +EndTable + +Table: XOP map Ah +Referrer: +XOPcode: 2 +10: BEXTR Gy,Ey,Id +12: GrpXOP4 +EndTable + GrpTable: Grp1 0: ADD 1: OR @@ -1320,3 +1403,29 @@ GrpTable: GrpRNG 4: xcrypt-cfb 5: xcrypt-ofb EndTable + +# GrpXOP1-4 is shown in AMD APM Vol.3 Appendix A as XOP group #1-4 +GrpTable: GrpXOP1 +1: BLCFILL By,Ey (xop) +2: BLSFILL By,Ey (xop) +3: BLCS By,Ey (xop) +4: TZMSK By,Ey (xop) +5: BLCIC By,Ey (xop) +6: BLSIC By,Ey (xop) +7: T1MSKC By,Ey (xop) +EndTable + +GrpTable: GrpXOP2 +1: BLCMSK By,Ey (xop) +6: BLCI By,Ey (xop) +EndTable + +GrpTable: GrpXOP3 +0: LLWPCB Ry (xop) +1: SLWPCB Ry (xop) +EndTable + +GrpTable: GrpXOP4 +0: LWPINS By,Ed,Id (xop) +1: LWPVAL By,Ed,Id (xop) +EndTable diff --git a/arch/x86/tools/gen-insn-attr-x86.awk b/arch/x86/tools/gen-insn-attr-x86.awk index 2c19d7fc8a85..7ea1b75e59b7 100644 --- a/arch/x86/tools/gen-insn-attr-x86.awk +++ b/arch/x86/tools/gen-insn-attr-x86.awk @@ -21,6 +21,7 @@ function clear_vars() { eid = -1 # escape id gid = -1 # group id aid = -1 # AVX id + xopid = -1 # XOP id tname = "" } @@ -39,9 +40,11 @@ BEGIN { ggid = 1 geid = 1 gaid = 0 + gxopid = 0 delete etable delete gtable delete atable + delete xoptable opnd_expr = "^[A-Za-z/]" ext_expr = "^\\(" @@ -61,6 +64,7 @@ BEGIN { imm_flag["Ob"] = "INAT_MOFFSET" imm_flag["Ov"] = "INAT_MOFFSET" imm_flag["Lx"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" + imm_flag["Lo"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" modrm_expr = "^([CDEGMNPQRSUVW/][a-z]+|NTA|T[012])" force64_expr = "\\([df]64\\)" @@ -87,6 +91,8 @@ BEGIN { evexonly_expr = "\\(ev\\)" # (es) is the same as (ev) but also "SCALABLE" i.e. W and pp determine operand size evex_scalable_expr = "\\(es\\)" + # All opcodes in XOP table or with (xop) superscript accept XOP prefix + xopok_expr = "\\(xop\\)" prefix_expr = "\\(Prefix\\)" prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ" @@ -106,6 +112,7 @@ BEGIN { prefix_num["VEX+2byte"] = "INAT_PFX_VEX3" prefix_num["EVEX"] = "INAT_PFX_EVEX" prefix_num["REX2"] = "INAT_PFX_REX2" + prefix_num["XOP"] = "INAT_PFX_XOP" clear_vars() } @@ -147,6 +154,7 @@ function array_size(arr, i,c) { if (NF != 1) { # AVX/escape opcode table aid = $2 + xopid = -1 if (gaid <= aid) gaid = aid + 1 if (tname == "") # AVX only opcode table @@ -156,6 +164,20 @@ function array_size(arr, i,c) { tname = "inat_primary_table" } +/^XOPcode:/ { + if (NF != 1) { + # XOP opcode table + xopid = $2 + aid = -1 + if (gxopid <= xopid) + gxopid = xopid + 1 + if (tname == "") # XOP only opcode table + tname = sprintf("inat_xop_table_%d", $2) + } + if (xopid == -1 && eid == -1) # primary opcode table + tname = "inat_primary_table" +} + /^GrpTable:/ { print "/* " $0 " */" if (!($2 in group)) @@ -206,6 +228,8 @@ function print_table(tbl,name,fmt,n) etable[eid,0] = tname if (aid >= 0) atable[aid,0] = tname + else if (xopid >= 0) + xoptable[xopid] = tname } if (array_size(lptable1) != 0) { print_table(lptable1,tname "_1[INAT_OPCODE_TABLE_SIZE]", @@ -347,6 +371,8 @@ function convert_operands(count,opnd, i,j,imm,mod) flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY") else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr)) flags = add_flags(flags, "INAT_VEXOK") + else if (match(ext, xopok_expr) || xopid >= 0) + flags = add_flags(flags, "INAT_XOPOK") # check prefixes if (match(ext, prefix_expr)) { @@ -413,6 +439,14 @@ END { print " ["i"]["j"] = "atable[i,j]"," print "};\n" + print "/* XOP opcode map array */" + print "const insn_attr_t * const inat_xop_tables[X86_XOP_M_MAX - X86_XOP_M_MIN + 1]" \ + " = {" + for (i = 0; i < gxopid; i++) + if (xoptable[i]) + print " ["i"] = "xoptable[i]"," + print "};" + print "#else /* !__BOOT_COMPRESSED */\n" print "/* Escape opcode map array */" @@ -430,6 +464,10 @@ END { "[INAT_LSTPFX_MAX + 1];" print "" + print "/* XOP opcode map array */" + print "static const insn_attr_t *inat_xop_tables[X86_XOP_M_MAX - X86_XOP_M_MIN + 1];" + print "" + print "static void inat_init_tables(void)" print "{" @@ -455,6 +493,12 @@ END { if (atable[i,j]) print "\tinat_avx_tables["i"]["j"] = "atable[i,j]";" + print "" + print "\t/* Print XOP opcode map array */" + for (i = 0; i < gxopid; i++) + if (xoptable[i]) + print "\tinat_xop_tables["i"] = "xoptable[i]";" + print "}" print "#endif" } diff --git a/tools/arch/x86/include/asm/inat.h b/tools/arch/x86/include/asm/inat.h index 183aa662b165..099e926595bd 100644 --- a/tools/arch/x86/include/asm/inat.h +++ b/tools/arch/x86/include/asm/inat.h @@ -37,6 +37,8 @@ #define INAT_PFX_EVEX 15 /* EVEX prefix */ /* x86-64 REX2 prefix */ #define INAT_PFX_REX2 16 /* 0xD5 */ +/* AMD XOP prefix */ +#define INAT_PFX_XOP 17 /* 0x8F */ #define INAT_LSTPFX_MAX 3 #define INAT_LGCPFX_MAX 11 @@ -77,6 +79,7 @@ #define INAT_MOFFSET (1 << (INAT_FLAG_OFFS + 3)) #define INAT_VARIANT (1 << (INAT_FLAG_OFFS + 4)) #define INAT_VEXOK (1 << (INAT_FLAG_OFFS + 5)) +#define INAT_XOPOK INAT_VEXOK #define INAT_VEXONLY (1 << (INAT_FLAG_OFFS + 6)) #define INAT_EVEXONLY (1 << (INAT_FLAG_OFFS + 7)) #define INAT_NO_REX2 (1 << (INAT_FLAG_OFFS + 8)) @@ -111,6 +114,8 @@ extern insn_attr_t inat_get_group_attribute(insn_byte_t modrm, extern insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, insn_byte_t vex_m, insn_byte_t vex_pp); +extern insn_attr_t inat_get_xop_attribute(insn_byte_t opcode, + insn_byte_t map_select); /* Attribute checking functions */ static inline int inat_is_legacy_prefix(insn_attr_t attr) @@ -164,6 +169,11 @@ static inline int inat_is_vex3_prefix(insn_attr_t attr) return (attr & INAT_PFX_MASK) == INAT_PFX_VEX3; } +static inline int inat_is_xop_prefix(insn_attr_t attr) +{ + return (attr & INAT_PFX_MASK) == INAT_PFX_XOP; +} + static inline int inat_is_escape(insn_attr_t attr) { return attr & INAT_ESC_MASK; @@ -229,6 +239,11 @@ static inline int inat_accept_vex(insn_attr_t attr) return attr & INAT_VEXOK; } +static inline int inat_accept_xop(insn_attr_t attr) +{ + return attr & INAT_XOPOK; +} + static inline int inat_must_vex(insn_attr_t attr) { return attr & (INAT_VEXONLY | INAT_EVEXONLY); diff --git a/tools/arch/x86/include/asm/insn.h b/tools/arch/x86/include/asm/insn.h index 0e5abd896ad4..c683d609934b 100644 --- a/tools/arch/x86/include/asm/insn.h +++ b/tools/arch/x86/include/asm/insn.h @@ -71,7 +71,10 @@ struct insn { * prefixes.bytes[3]: last prefix */ struct insn_field rex_prefix; /* REX prefix */ - struct insn_field vex_prefix; /* VEX prefix */ + union { + struct insn_field vex_prefix; /* VEX prefix */ + struct insn_field xop_prefix; /* XOP prefix */ + }; struct insn_field opcode; /* * opcode.bytes[0]: opcode1 * opcode.bytes[1]: opcode2 @@ -135,6 +138,17 @@ struct insn { #define X86_VEX_V(vex) (((vex) & 0x78) >> 3) /* VEX3 Byte2, VEX2 Byte1 */ #define X86_VEX_P(vex) ((vex) & 0x03) /* VEX3 Byte2, VEX2 Byte1 */ #define X86_VEX_M_MAX 0x1f /* VEX3.M Maximum value */ +/* XOP bit fields */ +#define X86_XOP_R(xop) ((xop) & 0x80) /* XOP Byte2 */ +#define X86_XOP_X(xop) ((xop) & 0x40) /* XOP Byte2 */ +#define X86_XOP_B(xop) ((xop) & 0x20) /* XOP Byte2 */ +#define X86_XOP_M(xop) ((xop) & 0x1f) /* XOP Byte2 */ +#define X86_XOP_W(xop) ((xop) & 0x80) /* XOP Byte3 */ +#define X86_XOP_V(xop) ((xop) & 0x78) /* XOP Byte3 */ +#define X86_XOP_L(xop) ((xop) & 0x04) /* XOP Byte3 */ +#define X86_XOP_P(xop) ((xop) & 0x03) /* XOP Byte3 */ +#define X86_XOP_M_MIN 0x08 /* Min of XOP.M */ +#define X86_XOP_M_MAX 0x1f /* Max of XOP.M */ extern void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64); extern int insn_get_prefixes(struct insn *insn); @@ -178,7 +192,7 @@ static inline insn_byte_t insn_rex2_m_bit(struct insn *insn) return X86_REX2_M(insn->rex_prefix.bytes[1]); } -static inline int insn_is_avx(struct insn *insn) +static inline int insn_is_avx_or_xop(struct insn *insn) { if (!insn->prefixes.got) insn_get_prefixes(insn); @@ -192,6 +206,22 @@ static inline int insn_is_evex(struct insn *insn) return (insn->vex_prefix.nbytes == 4); } +/* If we already know this is AVX/XOP encoded */ +static inline int avx_insn_is_xop(struct insn *insn) +{ + insn_attr_t attr = inat_get_opcode_attribute(insn->vex_prefix.bytes[0]); + + return inat_is_xop_prefix(attr); +} + +static inline int insn_is_xop(struct insn *insn) +{ + if (!insn_is_avx_or_xop(insn)) + return 0; + + return avx_insn_is_xop(insn); +} + static inline int insn_has_emulate_prefix(struct insn *insn) { return !!insn->emulate_prefix_size; @@ -222,11 +252,26 @@ static inline insn_byte_t insn_vex_w_bit(struct insn *insn) return X86_VEX_W(insn->vex_prefix.bytes[2]); } +static inline insn_byte_t insn_xop_map_bits(struct insn *insn) +{ + if (insn->xop_prefix.nbytes < 3) /* XOP is 3 bytes */ + return 0; + return X86_XOP_M(insn->xop_prefix.bytes[1]); +} + +static inline insn_byte_t insn_xop_p_bits(struct insn *insn) +{ + return X86_XOP_P(insn->vex_prefix.bytes[2]); +} + /* Get the last prefix id from last prefix or VEX prefix */ static inline int insn_last_prefix_id(struct insn *insn) { - if (insn_is_avx(insn)) + if (insn_is_avx_or_xop(insn)) { + if (avx_insn_is_xop(insn)) + return insn_xop_p_bits(insn); return insn_vex_p_bits(insn); /* VEX_p is a SIMD prefix id */ + } if (insn->prefixes.bytes[3]) return inat_get_last_prefix_id(insn->prefixes.bytes[3]); diff --git a/tools/arch/x86/lib/inat.c b/tools/arch/x86/lib/inat.c index dfbcc6405941..ffcb0e27453b 100644 --- a/tools/arch/x86/lib/inat.c +++ b/tools/arch/x86/lib/inat.c @@ -81,3 +81,16 @@ insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, insn_byte_t vex_m, return table[opcode]; } +insn_attr_t inat_get_xop_attribute(insn_byte_t opcode, insn_byte_t map_select) +{ + const insn_attr_t *table; + + if (map_select < X86_XOP_M_MIN || map_select > X86_XOP_M_MAX) + return 0; + map_select -= X86_XOP_M_MIN; + /* At first, this checks the master table */ + table = inat_xop_tables[map_select]; + if (!table) + return 0; + return table[opcode]; +} diff --git a/tools/arch/x86/lib/insn.c b/tools/arch/x86/lib/insn.c index bce69c6bfa69..1d1c57c74d1f 100644 --- a/tools/arch/x86/lib/insn.c +++ b/tools/arch/x86/lib/insn.c @@ -200,12 +200,15 @@ int insn_get_prefixes(struct insn *insn) } insn->rex_prefix.got = 1; - /* Decode VEX prefix */ + /* Decode VEX/XOP prefix */ b = peek_next(insn_byte_t, insn); - attr = inat_get_opcode_attribute(b); - if (inat_is_vex_prefix(attr)) { + if (inat_is_vex_prefix(attr) || inat_is_xop_prefix(attr)) { insn_byte_t b2 = peek_nbyte_next(insn_byte_t, insn, 1); - if (!insn->x86_64) { + + if (inat_is_xop_prefix(attr) && X86_MODRM_REG(b2) == 0) { + /* Grp1A.0 is always POP Ev */ + goto vex_end; + } else if (!insn->x86_64) { /* * In 32-bits mode, if the [7:6] bits (mod bits of * ModRM) on the second byte are not 11b, it is @@ -226,13 +229,13 @@ int insn_get_prefixes(struct insn *insn) if (insn->x86_64 && X86_VEX_W(b2)) /* VEX.W overrides opnd_size */ insn->opnd_bytes = 8; - } else if (inat_is_vex3_prefix(attr)) { + } else if (inat_is_vex3_prefix(attr) || inat_is_xop_prefix(attr)) { b2 = peek_nbyte_next(insn_byte_t, insn, 2); insn_set_byte(&insn->vex_prefix, 2, b2); insn->vex_prefix.nbytes = 3; insn->next_byte += 3; if (insn->x86_64 && X86_VEX_W(b2)) - /* VEX.W overrides opnd_size */ + /* VEX.W/XOP.W overrides opnd_size */ insn->opnd_bytes = 8; } else { /* @@ -288,9 +291,22 @@ int insn_get_opcode(struct insn *insn) insn_set_byte(opcode, 0, op); opcode->nbytes = 1; - /* Check if there is VEX prefix or not */ - if (insn_is_avx(insn)) { + /* Check if there is VEX/XOP prefix or not */ + if (insn_is_avx_or_xop(insn)) { insn_byte_t m, p; + + /* XOP prefix has different encoding */ + if (unlikely(avx_insn_is_xop(insn))) { + m = insn_xop_map_bits(insn); + insn->attr = inat_get_xop_attribute(op, m); + if (!inat_accept_xop(insn->attr)) { + insn->attr = 0; + return -EINVAL; + } + /* XOP has only 1 byte for opcode */ + goto end; + } + m = insn_vex_m_bits(insn); p = insn_vex_p_bits(insn); insn->attr = inat_get_avx_attribute(op, m, p); @@ -383,7 +399,8 @@ int insn_get_modrm(struct insn *insn) pfx_id = insn_last_prefix_id(insn); insn->attr = inat_get_group_attribute(mod, pfx_id, insn->attr); - if (insn_is_avx(insn) && !inat_accept_vex(insn->attr)) { + if (insn_is_avx_or_xop(insn) && !inat_accept_vex(insn->attr) && + !inat_accept_xop(insn->attr)) { /* Bad insn */ insn->attr = 0; return -EINVAL; diff --git a/tools/arch/x86/lib/x86-opcode-map.txt b/tools/arch/x86/lib/x86-opcode-map.txt index 262f7ca1fb95..2a4e69ecc2de 100644 --- a/tools/arch/x86/lib/x86-opcode-map.txt +++ b/tools/arch/x86/lib/x86-opcode-map.txt @@ -27,6 +27,11 @@ # (evo): this opcode is changed by EVEX prefix (EVEX opcode) # (v): this opcode requires VEX prefix. # (v1): this opcode only supports 128bit VEX. +# (xop): this opcode accepts XOP prefix. +# +# XOP Superscripts +# (W=0): this opcode requires XOP.W == 0 +# (W=1): this opcode requires XOP.W == 1 # # Last Prefix Superscripts # - (66): the last prefix is 0x66 @@ -194,7 +199,7 @@ AVXcode: 8c: MOV Ev,Sw 8d: LEA Gv,M 8e: MOV Sw,Ew -8f: Grp1A (1A) | POP Ev (d64) +8f: Grp1A (1A) | POP Ev (d64) | XOP (Prefix) # 0x90 - 0x9f 90: NOP | PAUSE (F3) | XCHG r8,rAX 91: XCHG rCX/r9,rAX @@ -1106,6 +1111,84 @@ AVXcode: 7 f8: URDMSR Rq,Id (F2),(v1),(11B) | UWRMSR Id,Rq (F3),(v1),(11B) EndTable +# From AMD64 Architecture Programmer's Manual Vol3, Appendix A.1.5 +Table: XOP map 8h +Referrer: +XOPcode: 0 +85: VPMACSSWW Vo,Ho,Wo,Lo +86: VPMACSSWD Vo,Ho,Wo,Lo +87: VPMACSSDQL Vo,Ho,Wo,Lo +8e: VPMACSSDD Vo,Ho,Wo,Lo +8f: VPMACSSDQH Vo,Ho,Wo,Lo +95: VPMACSWW Vo,Ho,Wo,Lo +96: VPMACSWD Vo,Ho,Wo,Lo +97: VPMACSDQL Vo,Ho,Wo,Lo +9e: VPMACSDD Vo,Ho,Wo,Lo +9f: VPMACSDQH Vo,Ho,Wo,Lo +a2: VPCMOV Vx,Hx,Wx,Lx (W=0) | VPCMOV Vx,Hx,Lx,Wx (W=1) +a3: VPPERM Vo,Ho,Wo,Lo (W=0) | VPPERM Vo,Ho,Lo,Wo (W=1) +a6: VPMADCSSWD Vo,Ho,Wo,Lo +b6: VPMADCSWD Vo,Ho,Wo,Lo +c0: VPROTB Vo,Wo,Ib +c1: VPROTW Vo,Wo,Ib +c2: VPROTD Vo,Wo,Ib +c3: VPROTQ Vo,Wo,Ib +cc: VPCOMccB Vo,Ho,Wo,Ib +cd: VPCOMccW Vo,Ho,Wo,Ib +ce: VPCOMccD Vo,Ho,Wo,Ib +cf: VPCOMccQ Vo,Ho,Wo,Ib +ec: VPCOMccUB Vo,Ho,Wo,Ib +ed: VPCOMccUW Vo,Ho,Wo,Ib +ee: VPCOMccUD Vo,Ho,Wo,Ib +ef: VPCOMccUQ Vo,Ho,Wo,Ib +EndTable + +Table: XOP map 9h +Referrer: +XOPcode: 1 +01: GrpXOP1 +02: GrpXOP2 +12: GrpXOP3 +80: VFRCZPS Vx,Wx +81: VFRCZPD Vx,Wx +82: VFRCZSS Vq,Wss +83: VFRCZSD Vq,Wsd +90: VPROTB Vo,Wo,Ho (W=0) | VPROTB Vo,Ho,Wo (W=1) +91: VPROTW Vo,Wo,Ho (W=0) | VPROTB Vo,Ho,Wo (W=1) +92: VPROTD Vo,Wo,Ho (W=0) | VPROTB Vo,Ho,Wo (W=1) +93: VPROTQ Vo,Wo,Ho (W=0) | VPROTB Vo,Ho,Wo (W=1) +94: VPSHLB Vo,Wo,Ho (W=0) | VPSHLB Vo,Ho,Wo (W=1) +95: VPSHLW Vo,Wo,Ho (W=0) | VPSHLW Vo,Ho,Wo (W=1) +96: VPSHLD Vo,Wo,Ho (W=0) | VPSHLD Vo,Ho,Wo (W=1) +97: VPSHLQ Vo,Wo,Ho (W=0) | VPSHLQ Vo,Ho,Wo (W=1) +98: VPSHAB Vo,Wo,Ho (W=0) | VPSHAB Vo,Ho,Wo (W=1) +99: VPSHAW Vo,Wo,Ho (W=0) | VPSHAW Vo,Ho,Wo (W=1) +9a: VPSHAD Vo,Wo,Ho (W=0) | VPSHAD Vo,Ho,Wo (W=1) +9b: VPSHAQ Vo,Wo,Ho (W=0) | VPSHAQ Vo,Ho,Wo (W=1) +c1: VPHADDBW Vo,Wo +c2: VPHADDBD Vo,Wo +c3: VPHADDBQ Vo,Wo +c6: VPHADDWD Vo,Wo +c7: VPHADDWQ Vo,Wo +cb: VPHADDDQ Vo,Wo +d1: VPHADDUBWD Vo,Wo +d2: VPHADDUBD Vo,Wo +d3: VPHADDUBQ Vo,Wo +d6: VPHADDUWD Vo,Wo +d7: VPHADDUWQ Vo,Wo +db: VPHADDUDQ Vo,Wo +e1: VPHSUBBW Vo,Wo +e2: VPHSUBWD Vo,Wo +e3: VPHSUBDQ Vo,Wo +EndTable + +Table: XOP map Ah +Referrer: +XOPcode: 2 +10: BEXTR Gy,Ey,Id +12: GrpXOP4 +EndTable + GrpTable: Grp1 0: ADD 1: OR @@ -1320,3 +1403,29 @@ GrpTable: GrpRNG 4: xcrypt-cfb 5: xcrypt-ofb EndTable + +# GrpXOP1-4 is shown in AMD APM Vol.3 Appendix A as XOP group #1-4 +GrpTable: GrpXOP1 +1: BLCFILL By,Ey (xop) +2: BLSFILL By,Ey (xop) +3: BLCS By,Ey (xop) +4: TZMSK By,Ey (xop) +5: BLCIC By,Ey (xop) +6: BLSIC By,Ey (xop) +7: T1MSKC By,Ey (xop) +EndTable + +GrpTable: GrpXOP2 +1: BLCMSK By,Ey (xop) +6: BLCI By,Ey (xop) +EndTable + +GrpTable: GrpXOP3 +0: LLWPCB Ry (xop) +1: SLWPCB Ry (xop) +EndTable + +GrpTable: GrpXOP4 +0: LWPINS By,Ed,Id (xop) +1: LWPVAL By,Ed,Id (xop) +EndTable diff --git a/tools/arch/x86/tools/gen-insn-attr-x86.awk b/tools/arch/x86/tools/gen-insn-attr-x86.awk index 2c19d7fc8a85..7ea1b75e59b7 100644 --- a/tools/arch/x86/tools/gen-insn-attr-x86.awk +++ b/tools/arch/x86/tools/gen-insn-attr-x86.awk @@ -21,6 +21,7 @@ function clear_vars() { eid = -1 # escape id gid = -1 # group id aid = -1 # AVX id + xopid = -1 # XOP id tname = "" } @@ -39,9 +40,11 @@ BEGIN { ggid = 1 geid = 1 gaid = 0 + gxopid = 0 delete etable delete gtable delete atable + delete xoptable opnd_expr = "^[A-Za-z/]" ext_expr = "^\\(" @@ -61,6 +64,7 @@ BEGIN { imm_flag["Ob"] = "INAT_MOFFSET" imm_flag["Ov"] = "INAT_MOFFSET" imm_flag["Lx"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" + imm_flag["Lo"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" modrm_expr = "^([CDEGMNPQRSUVW/][a-z]+|NTA|T[012])" force64_expr = "\\([df]64\\)" @@ -87,6 +91,8 @@ BEGIN { evexonly_expr = "\\(ev\\)" # (es) is the same as (ev) but also "SCALABLE" i.e. W and pp determine operand size evex_scalable_expr = "\\(es\\)" + # All opcodes in XOP table or with (xop) superscript accept XOP prefix + xopok_expr = "\\(xop\\)" prefix_expr = "\\(Prefix\\)" prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ" @@ -106,6 +112,7 @@ BEGIN { prefix_num["VEX+2byte"] = "INAT_PFX_VEX3" prefix_num["EVEX"] = "INAT_PFX_EVEX" prefix_num["REX2"] = "INAT_PFX_REX2" + prefix_num["XOP"] = "INAT_PFX_XOP" clear_vars() } @@ -147,6 +154,7 @@ function array_size(arr, i,c) { if (NF != 1) { # AVX/escape opcode table aid = $2 + xopid = -1 if (gaid <= aid) gaid = aid + 1 if (tname == "") # AVX only opcode table @@ -156,6 +164,20 @@ function array_size(arr, i,c) { tname = "inat_primary_table" } +/^XOPcode:/ { + if (NF != 1) { + # XOP opcode table + xopid = $2 + aid = -1 + if (gxopid <= xopid) + gxopid = xopid + 1 + if (tname == "") # XOP only opcode table + tname = sprintf("inat_xop_table_%d", $2) + } + if (xopid == -1 && eid == -1) # primary opcode table + tname = "inat_primary_table" +} + /^GrpTable:/ { print "/* " $0 " */" if (!($2 in group)) @@ -206,6 +228,8 @@ function print_table(tbl,name,fmt,n) etable[eid,0] = tname if (aid >= 0) atable[aid,0] = tname + else if (xopid >= 0) + xoptable[xopid] = tname } if (array_size(lptable1) != 0) { print_table(lptable1,tname "_1[INAT_OPCODE_TABLE_SIZE]", @@ -347,6 +371,8 @@ function convert_operands(count,opnd, i,j,imm,mod) flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY") else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr)) flags = add_flags(flags, "INAT_VEXOK") + else if (match(ext, xopok_expr) || xopid >= 0) + flags = add_flags(flags, "INAT_XOPOK") # check prefixes if (match(ext, prefix_expr)) { @@ -413,6 +439,14 @@ END { print " ["i"]["j"] = "atable[i,j]"," print "};\n" + print "/* XOP opcode map array */" + print "const insn_attr_t * const inat_xop_tables[X86_XOP_M_MAX - X86_XOP_M_MIN + 1]" \ + " = {" + for (i = 0; i < gxopid; i++) + if (xoptable[i]) + print " ["i"] = "xoptable[i]"," + print "};" + print "#else /* !__BOOT_COMPRESSED */\n" print "/* Escape opcode map array */" @@ -430,6 +464,10 @@ END { "[INAT_LSTPFX_MAX + 1];" print "" + print "/* XOP opcode map array */" + print "static const insn_attr_t *inat_xop_tables[X86_XOP_M_MAX - X86_XOP_M_MIN + 1];" + print "" + print "static void inat_init_tables(void)" print "{" @@ -455,6 +493,12 @@ END { if (atable[i,j]) print "\tinat_avx_tables["i"]["j"] = "atable[i,j]";" + print "" + print "\t/* Print XOP opcode map array */" + for (i = 0; i < gxopid; i++) + if (xoptable[i]) + print "\tinat_xop_tables["i"] = "xoptable[i]";" + print "}" print "#endif" } diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c index 8fabddc1c0da..72c7a4e15d61 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c @@ -32,7 +32,7 @@ static void intel_pt_insn_decoder(struct insn *insn, intel_pt_insn->rel = 0; intel_pt_insn->emulated_ptwrite = false; - if (insn_is_avx(insn)) { + if (insn_is_avx_or_xop(insn)) { intel_pt_insn->op = INTEL_PT_OP_OTHER; intel_pt_insn->branch = INTEL_PT_BR_NO_BRANCH; intel_pt_insn->length = insn->length; From 65fe705367efc3e06ccfa2a3a107081d8e69f70e Mon Sep 17 00:00:00 2001 From: Julien Massot Date: Fri, 1 Aug 2025 13:18:09 +0200 Subject: [PATCH 01189/11391] dt-bindings: pinctrl: mediatek: mt8183: Allow gpio-line-names Add support for the 'gpio-line-names' property in the MT8183 pinctrl binding. This allows naming the GPIOs, which is already done in several device trees (e.g. mt8183-kukui-jacuzzi.dtsi, mt8183-kukui-kakadu.dtsi, mt8183-kukui-krane.dtsi), but was previously generating DT schema warnings. Signed-off-by: Julien Massot Reviewed-by: AngeloGioacchino Del Regno Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/20250801-mtk-dtb-warnings-v1-7-6ba4e432427b@collabora.com Signed-off-by: Linus Walleij --- .../devicetree/bindings/pinctrl/mediatek,mt8183-pinctrl.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/pinctrl/mediatek,mt8183-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/mediatek,mt8183-pinctrl.yaml index 464879274cae..3db2438fadc7 100644 --- a/Documentation/devicetree/bindings/pinctrl/mediatek,mt8183-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/mediatek,mt8183-pinctrl.yaml @@ -48,6 +48,8 @@ properties: description: GPIO valid number range. + gpio-line-names: true + interrupt-controller: true interrupts: From 694a97ee25581630f70773d160fcc2364afe98c8 Mon Sep 17 00:00:00 2001 From: Hendrik Hamerlinck Date: Tue, 5 Aug 2025 17:07:01 +0200 Subject: [PATCH 01190/11391] pinctrl: spacemit: remove extra line in debug output The debug output for spacemit_pinconf_dbg_show() prints an extra newline at the end. This is redundant as pinconf_pins_show() in pinconf.c already adds a newline in its for loop. Remove the newline to avoid the extra line in the output. Example current output: $ cat /sys/kernel/debug/pinctrl/d401e000.pinctrl/pinconf-pins Pin config settings per pin Format: pin (name): configs pin 0 (GPIO_00): , bias pull disabled, io type (Fixed/1V8), drive strength (32 mA), register (0x1041) pin 1 (GPIO_01): slew rate (0x0), bias pull disabled, io type (Fixed/1V8), drive strength (32 mA), register (0x1041) pin 2 (GPIO_02): slew rate (0x0), bias pull disabled, io type (Fixed/1V8), drive strength (32 mA), register (0x1041) ... Signed-off-by: Hendrik Hamerlinck Reviewed-by: Yixun Lan Link: https://lore.kernel.org/20250805150701.129113-1-hendrik.hamerlinck@hammernet.be Signed-off-by: Linus Walleij --- drivers/pinctrl/spacemit/pinctrl-k1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/spacemit/pinctrl-k1.c b/drivers/pinctrl/spacemit/pinctrl-k1.c index 9996b1c4a07e..fb361f2acb54 100644 --- a/drivers/pinctrl/spacemit/pinctrl-k1.c +++ b/drivers/pinctrl/spacemit/pinctrl-k1.c @@ -707,7 +707,7 @@ static void spacemit_pinconf_dbg_show(struct pinctrl_dev *pctldev, spacemit_get_drive_strength_mA(IO_TYPE_1V8, tmp), spacemit_get_drive_strength_mA(IO_TYPE_3V3, tmp)); - seq_printf(seq, ", register (0x%04x)\n", value); + seq_printf(seq, ", register (0x%04x)", value); } static const struct pinconf_ops spacemit_pinconf_ops = { From 236152dd9b1675a35eee912e79e6c57ca6b6732f Mon Sep 17 00:00:00 2001 From: Chi Zhang Date: Thu, 7 Aug 2025 14:20:38 +0800 Subject: [PATCH 01191/11391] pinctrl: single: fix bias pull up/down handling in pin_config_set In the pin_config_set function, when handling PIN_CONFIG_BIAS_PULL_DOWN or PIN_CONFIG_BIAS_PULL_UP, the function calls pcs_pinconf_clear_bias() which writes the register. However, the subsequent operations continue using the stale 'data' value from before the register write, effectively causing the bias clear operation to be overwritten and not take effect. Fix this by reading the 'data' value from the register after calling pcs_pinconf_clear_bias(). This bug seems to have existed when this code was first merged in commit 9dddb4df90d1 ("pinctrl: single: support generic pinconf"). Signed-off-by: Chi Zhang Link: https://lore.kernel.org/20250807062038.13610-1-chizhang@asrmicro.com Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-single.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 5cda6201b60f..8aedee2720bc 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -589,8 +589,10 @@ static int pcs_pinconf_set(struct pinctrl_dev *pctldev, /* 4 parameters */ case PIN_CONFIG_BIAS_PULL_DOWN: case PIN_CONFIG_BIAS_PULL_UP: - if (arg) + if (arg) { pcs_pinconf_clear_bias(pctldev, pin); + data = pcs->read(pcs->base + offset); + } fallthrough; case PIN_CONFIG_INPUT_SCHMITT_ENABLE: data &= ~func->conf[i].mask; From dbe99ea541f023d73abf5730c1477ba96111ef83 Mon Sep 17 00:00:00 2001 From: Anton Protopopov Date: Sat, 16 Aug 2025 15:15:54 +0000 Subject: [PATCH 01192/11391] bpf: Add a verbose message when the BTF limit is reached When a BPF program which is being loaded reaches the map limit (MAX_USED_MAPS) or the BTF limit (MAX_USED_BTFS) the -E2BIG is returned. However, in the former case there is an accompanying verifier verbose message, and in the latter case there is not. Add a verbose message to make the behaviour symmetrical. Reported-by: Kevin Sheldrake Signed-off-by: Anton Protopopov Signed-off-by: Daniel Borkmann Acked-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20250816151554.902995-1-a.s.protopopov@gmail.com --- kernel/bpf/verifier.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 3a3982fe20d4..07cc4a738c67 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -20193,8 +20193,11 @@ static int __add_used_btf(struct bpf_verifier_env *env, struct btf *btf) if (env->used_btfs[i].btf == btf) return i; - if (env->used_btf_cnt >= MAX_USED_BTFS) + if (env->used_btf_cnt >= MAX_USED_BTFS) { + verbose(env, "The total number of btfs per program has reached the limit of %u\n", + MAX_USED_BTFS); return -E2BIG; + } btf_get(btf); From dca2f73cf19fedd7bc38fa6a0eb50fea63cd0214 Mon Sep 17 00:00:00 2001 From: Thomas Richard Date: Mon, 11 Aug 2025 15:25:53 +0200 Subject: [PATCH 01193/11391] pinctrl: Add pin controller driver for AAEON UP boards This enables the pin control support of the onboard FPGA on AAEON UP boards. This FPGA acts as a level shifter between the Intel SoC pins and the pin header, and also as a mux or switch. +---------+ +--------------+ +---+ | | | | | | PWM0 | \ | | H | |----------|------ \-----|-------------| E | | I2C0_SDA | | | A | Intel SoC |----------|------\ | | D | | GPIO0 | \------|-------------| E | |----------|------ | | R | | | FPGA | | | ----------+ +--------------+ +---+ For most of the pins, the FPGA opens/closes a switch to enable/disable the access to the SoC pin from a pin header. Each switch, has a direction flag that is set depending the status of the SoC pin. For some other pins, the FPGA acts as a mux, and routes one pin (or the other one) to the header. The driver also provides a GPIO chip. It requests SoC pins in GPIO mode, and drives them in tandem with FPGA pins (switch/mux direction). This commit adds support only for UP Squared board. Reviewed-by: Linus Walleij Reviewed-by: Andy Shevchenko Acked-by: Linus Walleij Signed-off-by: Thomas Richard Link: https://lore.kernel.org/20250811-aaeon-up-board-pinctrl-support-v9-10-29f0cbbdfb30@bootlin.com Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 19 + drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl-upboard.c | 1070 +++++++++++++++++++++++++++++ 3 files changed, 1090 insertions(+) create mode 100644 drivers/pinctrl/pinctrl-upboard.c diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index ddd11668457c..463cf252c275 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -600,6 +600,25 @@ config PINCTRL_TH1520 This driver is needed for RISC-V development boards like the BeagleV Ahead and the LicheePi 4A. +config PINCTRL_UPBOARD + tristate "AAeon UP board FPGA pin controller" + depends on MFD_UPBOARD_FPGA + select PINMUX + select GENERIC_PINCTRL_GROUPS + select GENERIC_PINMUX_FUNCTIONS + select GPIOLIB + select GPIO_AGGREGATOR + help + Pin controller for the FPGA GPIO lines on UP boards. Due to the + hardware layout, the driver controls the FPGA pins in tandem with + their corresponding Intel SoC GPIOs. + + Currently supported: + - UP Squared + + To compile this driver as a module, choose M here: the module + will be called pinctrl-upboard. + config PINCTRL_ZYNQ bool "Pinctrl driver for Xilinx Zynq" depends on ARCH_ZYNQ || COMPILE_TEST diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 909ab89a56d2..949693f2f0ab 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -59,6 +59,7 @@ obj-$(CONFIG_PINCTRL_SX150X) += pinctrl-sx150x.o obj-$(CONFIG_PINCTRL_TB10X) += pinctrl-tb10x.o obj-$(CONFIG_PINCTRL_TPS6594) += pinctrl-tps6594.o obj-$(CONFIG_PINCTRL_TH1520) += pinctrl-th1520.o +obj-$(CONFIG_PINCTRL_UPBOARD) += pinctrl-upboard.o obj-$(CONFIG_PINCTRL_ZYNQMP) += pinctrl-zynqmp.o obj-$(CONFIG_PINCTRL_ZYNQ) += pinctrl-zynq.o diff --git a/drivers/pinctrl/pinctrl-upboard.c b/drivers/pinctrl/pinctrl-upboard.c new file mode 100644 index 000000000000..f8c8b9d84990 --- /dev/null +++ b/drivers/pinctrl/pinctrl-upboard.c @@ -0,0 +1,1070 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * UP board pin control driver. + * + * Copyright (C) 2025 Bootlin + * + * Author: Thomas Richard + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "core.h" +#include "pinmux.h" + +enum upboard_pin_mode { + UPBOARD_PIN_MODE_FUNCTION, + UPBOARD_PIN_MODE_GPIO_IN, + UPBOARD_PIN_MODE_GPIO_OUT, + UPBOARD_PIN_MODE_DISABLED, +}; + +struct upboard_pin { + struct regmap_field *funcbit; + struct regmap_field *enbit; + struct regmap_field *dirbit; +}; + +struct upboard_pingroup { + struct pingroup grp; + enum upboard_pin_mode mode; + const enum upboard_pin_mode *modes; +}; + +struct upboard_pinctrl_data { + const struct upboard_pingroup *groups; + size_t ngroups; + const struct pinfunction *funcs; + size_t nfuncs; + const unsigned int *pin_header; + size_t ngpio; +}; + +struct upboard_pinctrl { + struct device *dev; + struct pinctrl_dev *pctldev; + const struct upboard_pinctrl_data *pctrl_data; + struct gpio_pin_range pin_range; + struct upboard_pin *pins; +}; + +struct upboard_pinctrl_map { + const struct pinctrl_map *maps; + size_t nmaps; +}; + +enum upboard_func0_fpgabit { + UPBOARD_FUNC_I2C0_EN = 8, + UPBOARD_FUNC_I2C1_EN = 9, + UPBOARD_FUNC_CEC0_EN = 12, + UPBOARD_FUNC_ADC0_EN = 14, +}; + +static const struct reg_field upboard_i2c0_reg = + REG_FIELD(UPBOARD_REG_FUNC_EN0, UPBOARD_FUNC_I2C0_EN, UPBOARD_FUNC_I2C0_EN); + +static const struct reg_field upboard_i2c1_reg = + REG_FIELD(UPBOARD_REG_FUNC_EN0, UPBOARD_FUNC_I2C1_EN, UPBOARD_FUNC_I2C1_EN); + +static const struct reg_field upboard_adc0_reg = + REG_FIELD(UPBOARD_REG_FUNC_EN0, UPBOARD_FUNC_ADC0_EN, UPBOARD_FUNC_ADC0_EN); + +#define UPBOARD_UP_BIT_TO_PIN(bit) UPBOARD_UP_BIT_##bit + +#define UPBOARD_UP_PIN_NAME(id) \ + { \ + .number = UPBOARD_UP_BIT_##id, \ + .name = #id, \ + } + +#define UPBOARD_UP_PIN_MUX(bit, data) \ + { \ + .number = UPBOARD_UP_BIT_##bit, \ + .name = "PINMUX_"#bit, \ + .drv_data = (void *)(data), \ + } + +#define UPBOARD_UP_PIN_FUNC(id, data) \ + { \ + .number = UPBOARD_UP_BIT_##id, \ + .name = #id, \ + .drv_data = (void *)(data), \ + } + +enum upboard_up_fpgabit { + UPBOARD_UP_BIT_I2C1_SDA, + UPBOARD_UP_BIT_I2C1_SCL, + UPBOARD_UP_BIT_ADC0, + UPBOARD_UP_BIT_UART1_RTS, + UPBOARD_UP_BIT_GPIO27, + UPBOARD_UP_BIT_GPIO22, + UPBOARD_UP_BIT_SPI_MOSI, + UPBOARD_UP_BIT_SPI_MISO, + UPBOARD_UP_BIT_SPI_CLK, + UPBOARD_UP_BIT_I2C0_SDA, + UPBOARD_UP_BIT_GPIO5, + UPBOARD_UP_BIT_GPIO6, + UPBOARD_UP_BIT_PWM1, + UPBOARD_UP_BIT_I2S_FRM, + UPBOARD_UP_BIT_GPIO26, + UPBOARD_UP_BIT_UART1_TX, + UPBOARD_UP_BIT_UART1_RX, + UPBOARD_UP_BIT_I2S_CLK, + UPBOARD_UP_BIT_GPIO23, + UPBOARD_UP_BIT_GPIO24, + UPBOARD_UP_BIT_GPIO25, + UPBOARD_UP_BIT_SPI_CS0, + UPBOARD_UP_BIT_SPI_CS1, + UPBOARD_UP_BIT_I2C0_SCL, + UPBOARD_UP_BIT_PWM0, + UPBOARD_UP_BIT_UART1_CTS, + UPBOARD_UP_BIT_I2S_DIN, + UPBOARD_UP_BIT_I2S_DOUT, +}; + +static const struct pinctrl_pin_desc upboard_up_pins[] = { + UPBOARD_UP_PIN_FUNC(I2C1_SDA, &upboard_i2c1_reg), + UPBOARD_UP_PIN_FUNC(I2C1_SCL, &upboard_i2c1_reg), + UPBOARD_UP_PIN_FUNC(ADC0, &upboard_adc0_reg), + UPBOARD_UP_PIN_NAME(UART1_RTS), + UPBOARD_UP_PIN_NAME(GPIO27), + UPBOARD_UP_PIN_NAME(GPIO22), + UPBOARD_UP_PIN_NAME(SPI_MOSI), + UPBOARD_UP_PIN_NAME(SPI_MISO), + UPBOARD_UP_PIN_NAME(SPI_CLK), + UPBOARD_UP_PIN_FUNC(I2C0_SDA, &upboard_i2c0_reg), + UPBOARD_UP_PIN_NAME(GPIO5), + UPBOARD_UP_PIN_NAME(GPIO6), + UPBOARD_UP_PIN_NAME(PWM1), + UPBOARD_UP_PIN_NAME(I2S_FRM), + UPBOARD_UP_PIN_NAME(GPIO26), + UPBOARD_UP_PIN_NAME(UART1_TX), + UPBOARD_UP_PIN_NAME(UART1_RX), + UPBOARD_UP_PIN_NAME(I2S_CLK), + UPBOARD_UP_PIN_NAME(GPIO23), + UPBOARD_UP_PIN_NAME(GPIO24), + UPBOARD_UP_PIN_NAME(GPIO25), + UPBOARD_UP_PIN_NAME(SPI_CS0), + UPBOARD_UP_PIN_NAME(SPI_CS1), + UPBOARD_UP_PIN_FUNC(I2C0_SCL, &upboard_i2c0_reg), + UPBOARD_UP_PIN_NAME(PWM0), + UPBOARD_UP_PIN_NAME(UART1_CTS), + UPBOARD_UP_PIN_NAME(I2S_DIN), + UPBOARD_UP_PIN_NAME(I2S_DOUT), +}; + +static const unsigned int upboard_up_pin_header[] = { + UPBOARD_UP_BIT_TO_PIN(I2C0_SDA), + UPBOARD_UP_BIT_TO_PIN(I2C0_SCL), + UPBOARD_UP_BIT_TO_PIN(I2C1_SDA), + UPBOARD_UP_BIT_TO_PIN(I2C1_SCL), + UPBOARD_UP_BIT_TO_PIN(ADC0), + UPBOARD_UP_BIT_TO_PIN(GPIO5), + UPBOARD_UP_BIT_TO_PIN(GPIO6), + UPBOARD_UP_BIT_TO_PIN(SPI_CS1), + UPBOARD_UP_BIT_TO_PIN(SPI_CS0), + UPBOARD_UP_BIT_TO_PIN(SPI_MISO), + UPBOARD_UP_BIT_TO_PIN(SPI_MOSI), + UPBOARD_UP_BIT_TO_PIN(SPI_CLK), + UPBOARD_UP_BIT_TO_PIN(PWM0), + UPBOARD_UP_BIT_TO_PIN(PWM1), + UPBOARD_UP_BIT_TO_PIN(UART1_TX), + UPBOARD_UP_BIT_TO_PIN(UART1_RX), + UPBOARD_UP_BIT_TO_PIN(UART1_CTS), + UPBOARD_UP_BIT_TO_PIN(UART1_RTS), + UPBOARD_UP_BIT_TO_PIN(I2S_CLK), + UPBOARD_UP_BIT_TO_PIN(I2S_FRM), + UPBOARD_UP_BIT_TO_PIN(I2S_DIN), + UPBOARD_UP_BIT_TO_PIN(I2S_DOUT), + UPBOARD_UP_BIT_TO_PIN(GPIO22), + UPBOARD_UP_BIT_TO_PIN(GPIO23), + UPBOARD_UP_BIT_TO_PIN(GPIO24), + UPBOARD_UP_BIT_TO_PIN(GPIO25), + UPBOARD_UP_BIT_TO_PIN(GPIO26), + UPBOARD_UP_BIT_TO_PIN(GPIO27), +}; + +static const unsigned int upboard_up_uart1_pins[] = { + UPBOARD_UP_BIT_TO_PIN(UART1_TX), + UPBOARD_UP_BIT_TO_PIN(UART1_RX), + UPBOARD_UP_BIT_TO_PIN(UART1_RTS), + UPBOARD_UP_BIT_TO_PIN(UART1_CTS), +}; + +static const enum upboard_pin_mode upboard_up_uart1_modes[] = { + UPBOARD_PIN_MODE_GPIO_OUT, + UPBOARD_PIN_MODE_GPIO_IN, + UPBOARD_PIN_MODE_GPIO_OUT, + UPBOARD_PIN_MODE_GPIO_IN, +}; + +static_assert(ARRAY_SIZE(upboard_up_uart1_modes) == ARRAY_SIZE(upboard_up_uart1_pins)); + +static const unsigned int upboard_up_i2c0_pins[] = { + UPBOARD_UP_BIT_TO_PIN(I2C0_SCL), + UPBOARD_UP_BIT_TO_PIN(I2C0_SDA), +}; + +static const unsigned int upboard_up_i2c1_pins[] = { + UPBOARD_UP_BIT_TO_PIN(I2C1_SCL), + UPBOARD_UP_BIT_TO_PIN(I2C1_SDA), +}; + +static const unsigned int upboard_up_spi2_pins[] = { + UPBOARD_UP_BIT_TO_PIN(SPI_MOSI), + UPBOARD_UP_BIT_TO_PIN(SPI_MISO), + UPBOARD_UP_BIT_TO_PIN(SPI_CLK), + UPBOARD_UP_BIT_TO_PIN(SPI_CS0), + UPBOARD_UP_BIT_TO_PIN(SPI_CS1), +}; + +static const enum upboard_pin_mode upboard_up_spi2_modes[] = { + UPBOARD_PIN_MODE_GPIO_OUT, + UPBOARD_PIN_MODE_GPIO_IN, + UPBOARD_PIN_MODE_GPIO_OUT, + UPBOARD_PIN_MODE_GPIO_OUT, + UPBOARD_PIN_MODE_GPIO_OUT, +}; + +static_assert(ARRAY_SIZE(upboard_up_spi2_modes) == ARRAY_SIZE(upboard_up_spi2_pins)); + +static const unsigned int upboard_up_i2s0_pins[] = { + UPBOARD_UP_BIT_TO_PIN(I2S_FRM), + UPBOARD_UP_BIT_TO_PIN(I2S_CLK), + UPBOARD_UP_BIT_TO_PIN(I2S_DIN), + UPBOARD_UP_BIT_TO_PIN(I2S_DOUT), +}; + +static const enum upboard_pin_mode upboard_up_i2s0_modes[] = { + UPBOARD_PIN_MODE_GPIO_OUT, + UPBOARD_PIN_MODE_GPIO_OUT, + UPBOARD_PIN_MODE_GPIO_IN, + UPBOARD_PIN_MODE_GPIO_OUT, +}; + +static_assert(ARRAY_SIZE(upboard_up_i2s0_pins) == ARRAY_SIZE(upboard_up_i2s0_modes)); + +static const unsigned int upboard_up_pwm0_pins[] = { + UPBOARD_UP_BIT_TO_PIN(PWM0), +}; + +static const unsigned int upboard_up_pwm1_pins[] = { + UPBOARD_UP_BIT_TO_PIN(PWM1), +}; + +static const unsigned int upboard_up_adc0_pins[] = { + UPBOARD_UP_BIT_TO_PIN(ADC0), +}; + +#define UPBOARD_PINGROUP(n, p, m) \ +{ \ + .grp = PINCTRL_PINGROUP(n, p, ARRAY_SIZE(p)), \ + .mode = __builtin_choose_expr( \ + __builtin_types_compatible_p(typeof(m), const enum upboard_pin_mode *), \ + 0, m), \ + .modes = __builtin_choose_expr( \ + __builtin_types_compatible_p(typeof(m), const enum upboard_pin_mode *), \ + m, NULL), \ +} + +static const struct upboard_pingroup upboard_up_pin_groups[] = { + UPBOARD_PINGROUP("uart1_grp", upboard_up_uart1_pins, &upboard_up_uart1_modes[0]), + UPBOARD_PINGROUP("i2c0_grp", upboard_up_i2c0_pins, UPBOARD_PIN_MODE_GPIO_OUT), + UPBOARD_PINGROUP("i2c1_grp", upboard_up_i2c1_pins, UPBOARD_PIN_MODE_GPIO_OUT), + UPBOARD_PINGROUP("spi2_grp", upboard_up_spi2_pins, &upboard_up_spi2_modes[0]), + UPBOARD_PINGROUP("i2s0_grp", upboard_up_i2s0_pins, &upboard_up_i2s0_modes[0]), + UPBOARD_PINGROUP("pwm0_grp", upboard_up_pwm0_pins, UPBOARD_PIN_MODE_GPIO_OUT), + UPBOARD_PINGROUP("pwm1_grp", upboard_up_pwm1_pins, UPBOARD_PIN_MODE_GPIO_OUT), + UPBOARD_PINGROUP("adc0_grp", upboard_up_adc0_pins, UPBOARD_PIN_MODE_GPIO_IN), +}; + +static const char * const upboard_up_uart1_groups[] = { "uart1_grp" }; +static const char * const upboard_up_i2c0_groups[] = { "i2c0_grp" }; +static const char * const upboard_up_i2c1_groups[] = { "i2c1_grp" }; +static const char * const upboard_up_spi2_groups[] = { "spi2_grp" }; +static const char * const upboard_up_i2s0_groups[] = { "i2s0_grp" }; +static const char * const upboard_up_pwm0_groups[] = { "pwm0_grp" }; +static const char * const upboard_up_pwm1_groups[] = { "pwm1_grp" }; +static const char * const upboard_up_adc0_groups[] = { "adc0_grp" }; + +#define UPBOARD_FUNCTION(func, groups) PINCTRL_PINFUNCTION(func, groups, ARRAY_SIZE(groups)) + +static const struct pinfunction upboard_up_pin_functions[] = { + UPBOARD_FUNCTION("uart1", upboard_up_uart1_groups), + UPBOARD_FUNCTION("i2c0", upboard_up_i2c0_groups), + UPBOARD_FUNCTION("i2c1", upboard_up_i2c1_groups), + UPBOARD_FUNCTION("spi2", upboard_up_spi2_groups), + UPBOARD_FUNCTION("i2s0", upboard_up_i2s0_groups), + UPBOARD_FUNCTION("pwm0", upboard_up_pwm0_groups), + UPBOARD_FUNCTION("pwm1", upboard_up_pwm1_groups), + UPBOARD_FUNCTION("adc0", upboard_up_adc0_groups), +}; + +static const struct upboard_pinctrl_data upboard_up_pinctrl_data = { + .groups = &upboard_up_pin_groups[0], + .ngroups = ARRAY_SIZE(upboard_up_pin_groups), + .funcs = &upboard_up_pin_functions[0], + .nfuncs = ARRAY_SIZE(upboard_up_pin_functions), + .pin_header = &upboard_up_pin_header[0], + .ngpio = ARRAY_SIZE(upboard_up_pin_header), +}; + +#define UPBOARD_UP2_BIT_TO_PIN(bit) UPBOARD_UP2_BIT_##bit + +#define UPBOARD_UP2_PIN_NAME(id) \ + { \ + .number = UPBOARD_UP2_BIT_##id, \ + .name = #id, \ + } + +#define UPBOARD_UP2_PIN_MUX(bit, data) \ + { \ + .number = UPBOARD_UP2_BIT_##bit, \ + .name = "PINMUX_"#bit, \ + .drv_data = (void *)(data), \ + } + +#define UPBOARD_UP2_PIN_FUNC(id, data) \ + { \ + .number = UPBOARD_UP2_BIT_##id, \ + .name = #id, \ + .drv_data = (void *)(data), \ + } + +enum upboard_up2_fpgabit { + UPBOARD_UP2_BIT_UART1_TXD, + UPBOARD_UP2_BIT_UART1_RXD, + UPBOARD_UP2_BIT_UART1_RTS, + UPBOARD_UP2_BIT_UART1_CTS, + UPBOARD_UP2_BIT_GPIO3_ADC0, + UPBOARD_UP2_BIT_GPIO5_ADC2, + UPBOARD_UP2_BIT_GPIO6_ADC3, + UPBOARD_UP2_BIT_GPIO11, + UPBOARD_UP2_BIT_EXHAT_LVDS1n, + UPBOARD_UP2_BIT_EXHAT_LVDS1p, + UPBOARD_UP2_BIT_SPI2_TXD, + UPBOARD_UP2_BIT_SPI2_RXD, + UPBOARD_UP2_BIT_SPI2_FS1, + UPBOARD_UP2_BIT_SPI2_FS0, + UPBOARD_UP2_BIT_SPI2_CLK, + UPBOARD_UP2_BIT_SPI1_TXD, + UPBOARD_UP2_BIT_SPI1_RXD, + UPBOARD_UP2_BIT_SPI1_FS1, + UPBOARD_UP2_BIT_SPI1_FS0, + UPBOARD_UP2_BIT_SPI1_CLK, + UPBOARD_UP2_BIT_I2C0_SCL, + UPBOARD_UP2_BIT_I2C0_SDA, + UPBOARD_UP2_BIT_I2C1_SCL, + UPBOARD_UP2_BIT_I2C1_SDA, + UPBOARD_UP2_BIT_PWM1, + UPBOARD_UP2_BIT_PWM0, + UPBOARD_UP2_BIT_EXHAT_LVDS0n, + UPBOARD_UP2_BIT_EXHAT_LVDS0p, + UPBOARD_UP2_BIT_GPIO24, + UPBOARD_UP2_BIT_GPIO10, + UPBOARD_UP2_BIT_GPIO2, + UPBOARD_UP2_BIT_GPIO1, + UPBOARD_UP2_BIT_EXHAT_LVDS3n, + UPBOARD_UP2_BIT_EXHAT_LVDS3p, + UPBOARD_UP2_BIT_EXHAT_LVDS4n, + UPBOARD_UP2_BIT_EXHAT_LVDS4p, + UPBOARD_UP2_BIT_EXHAT_LVDS5n, + UPBOARD_UP2_BIT_EXHAT_LVDS5p, + UPBOARD_UP2_BIT_I2S_SDO, + UPBOARD_UP2_BIT_I2S_SDI, + UPBOARD_UP2_BIT_I2S_WS_SYNC, + UPBOARD_UP2_BIT_I2S_BCLK, + UPBOARD_UP2_BIT_EXHAT_LVDS6n, + UPBOARD_UP2_BIT_EXHAT_LVDS6p, + UPBOARD_UP2_BIT_EXHAT_LVDS7n, + UPBOARD_UP2_BIT_EXHAT_LVDS7p, + UPBOARD_UP2_BIT_EXHAT_LVDS2n, + UPBOARD_UP2_BIT_EXHAT_LVDS2p, +}; + +static const struct pinctrl_pin_desc upboard_up2_pins[] = { + UPBOARD_UP2_PIN_NAME(UART1_TXD), + UPBOARD_UP2_PIN_NAME(UART1_RXD), + UPBOARD_UP2_PIN_NAME(UART1_RTS), + UPBOARD_UP2_PIN_NAME(UART1_CTS), + UPBOARD_UP2_PIN_NAME(GPIO3_ADC0), + UPBOARD_UP2_PIN_NAME(GPIO5_ADC2), + UPBOARD_UP2_PIN_NAME(GPIO6_ADC3), + UPBOARD_UP2_PIN_NAME(GPIO11), + UPBOARD_UP2_PIN_NAME(EXHAT_LVDS1n), + UPBOARD_UP2_PIN_NAME(EXHAT_LVDS1p), + UPBOARD_UP2_PIN_NAME(SPI2_TXD), + UPBOARD_UP2_PIN_NAME(SPI2_RXD), + UPBOARD_UP2_PIN_NAME(SPI2_FS1), + UPBOARD_UP2_PIN_NAME(SPI2_FS0), + UPBOARD_UP2_PIN_NAME(SPI2_CLK), + UPBOARD_UP2_PIN_NAME(SPI1_TXD), + UPBOARD_UP2_PIN_NAME(SPI1_RXD), + UPBOARD_UP2_PIN_NAME(SPI1_FS1), + UPBOARD_UP2_PIN_NAME(SPI1_FS0), + UPBOARD_UP2_PIN_NAME(SPI1_CLK), + UPBOARD_UP2_PIN_MUX(I2C0_SCL, &upboard_i2c0_reg), + UPBOARD_UP2_PIN_MUX(I2C0_SDA, &upboard_i2c0_reg), + UPBOARD_UP2_PIN_MUX(I2C1_SCL, &upboard_i2c1_reg), + UPBOARD_UP2_PIN_MUX(I2C1_SDA, &upboard_i2c1_reg), + UPBOARD_UP2_PIN_NAME(PWM1), + UPBOARD_UP2_PIN_NAME(PWM0), + UPBOARD_UP2_PIN_NAME(EXHAT_LVDS0n), + UPBOARD_UP2_PIN_NAME(EXHAT_LVDS0p), + UPBOARD_UP2_PIN_MUX(GPIO24, &upboard_i2c0_reg), + UPBOARD_UP2_PIN_MUX(GPIO10, &upboard_i2c0_reg), + UPBOARD_UP2_PIN_MUX(GPIO2, &upboard_i2c1_reg), + UPBOARD_UP2_PIN_MUX(GPIO1, &upboard_i2c1_reg), + UPBOARD_UP2_PIN_NAME(EXHAT_LVDS3n), + UPBOARD_UP2_PIN_NAME(EXHAT_LVDS3p), + UPBOARD_UP2_PIN_NAME(EXHAT_LVDS4n), + UPBOARD_UP2_PIN_NAME(EXHAT_LVDS4p), + UPBOARD_UP2_PIN_NAME(EXHAT_LVDS5n), + UPBOARD_UP2_PIN_NAME(EXHAT_LVDS5p), + UPBOARD_UP2_PIN_NAME(I2S_SDO), + UPBOARD_UP2_PIN_NAME(I2S_SDI), + UPBOARD_UP2_PIN_NAME(I2S_WS_SYNC), + UPBOARD_UP2_PIN_NAME(I2S_BCLK), + UPBOARD_UP2_PIN_NAME(EXHAT_LVDS6n), + UPBOARD_UP2_PIN_NAME(EXHAT_LVDS6p), + UPBOARD_UP2_PIN_NAME(EXHAT_LVDS7n), + UPBOARD_UP2_PIN_NAME(EXHAT_LVDS7p), + UPBOARD_UP2_PIN_NAME(EXHAT_LVDS2n), + UPBOARD_UP2_PIN_NAME(EXHAT_LVDS2p), +}; + +static const unsigned int upboard_up2_pin_header[] = { + UPBOARD_UP2_BIT_TO_PIN(GPIO10), + UPBOARD_UP2_BIT_TO_PIN(GPIO24), + UPBOARD_UP2_BIT_TO_PIN(GPIO1), + UPBOARD_UP2_BIT_TO_PIN(GPIO2), + UPBOARD_UP2_BIT_TO_PIN(GPIO3_ADC0), + UPBOARD_UP2_BIT_TO_PIN(GPIO11), + UPBOARD_UP2_BIT_TO_PIN(SPI2_CLK), + UPBOARD_UP2_BIT_TO_PIN(SPI1_FS1), + UPBOARD_UP2_BIT_TO_PIN(SPI1_FS0), + UPBOARD_UP2_BIT_TO_PIN(SPI1_RXD), + UPBOARD_UP2_BIT_TO_PIN(SPI1_TXD), + UPBOARD_UP2_BIT_TO_PIN(SPI1_CLK), + UPBOARD_UP2_BIT_TO_PIN(PWM0), + UPBOARD_UP2_BIT_TO_PIN(PWM1), + UPBOARD_UP2_BIT_TO_PIN(UART1_TXD), + UPBOARD_UP2_BIT_TO_PIN(UART1_RXD), + UPBOARD_UP2_BIT_TO_PIN(UART1_CTS), + UPBOARD_UP2_BIT_TO_PIN(UART1_RTS), + UPBOARD_UP2_BIT_TO_PIN(I2S_BCLK), + UPBOARD_UP2_BIT_TO_PIN(I2S_WS_SYNC), + UPBOARD_UP2_BIT_TO_PIN(I2S_SDI), + UPBOARD_UP2_BIT_TO_PIN(I2S_SDO), + UPBOARD_UP2_BIT_TO_PIN(GPIO6_ADC3), + UPBOARD_UP2_BIT_TO_PIN(SPI2_FS1), + UPBOARD_UP2_BIT_TO_PIN(SPI2_RXD), + UPBOARD_UP2_BIT_TO_PIN(SPI2_TXD), + UPBOARD_UP2_BIT_TO_PIN(SPI2_FS0), + UPBOARD_UP2_BIT_TO_PIN(GPIO5_ADC2), +}; + +static const unsigned int upboard_up2_uart1_pins[] = { + UPBOARD_UP2_BIT_TO_PIN(UART1_TXD), + UPBOARD_UP2_BIT_TO_PIN(UART1_RXD), + UPBOARD_UP2_BIT_TO_PIN(UART1_RTS), + UPBOARD_UP2_BIT_TO_PIN(UART1_CTS), +}; + +static const enum upboard_pin_mode upboard_up2_uart1_modes[] = { + UPBOARD_PIN_MODE_GPIO_OUT, + UPBOARD_PIN_MODE_GPIO_IN, + UPBOARD_PIN_MODE_GPIO_OUT, + UPBOARD_PIN_MODE_GPIO_IN, +}; + +static_assert(ARRAY_SIZE(upboard_up2_uart1_modes) == ARRAY_SIZE(upboard_up2_uart1_pins)); + +static const unsigned int upboard_up2_i2c0_pins[] = { + UPBOARD_UP2_BIT_TO_PIN(I2C0_SCL), + UPBOARD_UP2_BIT_TO_PIN(I2C0_SDA), + UPBOARD_UP2_BIT_TO_PIN(GPIO24), + UPBOARD_UP2_BIT_TO_PIN(GPIO10), +}; + +static const unsigned int upboard_up2_i2c1_pins[] = { + UPBOARD_UP2_BIT_TO_PIN(I2C1_SCL), + UPBOARD_UP2_BIT_TO_PIN(I2C1_SDA), + UPBOARD_UP2_BIT_TO_PIN(GPIO2), + UPBOARD_UP2_BIT_TO_PIN(GPIO1), +}; + +static const unsigned int upboard_up2_spi1_pins[] = { + UPBOARD_UP2_BIT_TO_PIN(SPI1_TXD), + UPBOARD_UP2_BIT_TO_PIN(SPI1_RXD), + UPBOARD_UP2_BIT_TO_PIN(SPI1_FS1), + UPBOARD_UP2_BIT_TO_PIN(SPI1_FS0), + UPBOARD_UP2_BIT_TO_PIN(SPI1_CLK), +}; + +static const unsigned int upboard_up2_spi2_pins[] = { + UPBOARD_UP2_BIT_TO_PIN(SPI2_TXD), + UPBOARD_UP2_BIT_TO_PIN(SPI2_RXD), + UPBOARD_UP2_BIT_TO_PIN(SPI2_FS1), + UPBOARD_UP2_BIT_TO_PIN(SPI2_FS0), + UPBOARD_UP2_BIT_TO_PIN(SPI2_CLK), +}; + +static const enum upboard_pin_mode upboard_up2_spi_modes[] = { + UPBOARD_PIN_MODE_GPIO_OUT, + UPBOARD_PIN_MODE_GPIO_IN, + UPBOARD_PIN_MODE_GPIO_OUT, + UPBOARD_PIN_MODE_GPIO_OUT, + UPBOARD_PIN_MODE_GPIO_OUT, +}; + +static_assert(ARRAY_SIZE(upboard_up2_spi_modes) == ARRAY_SIZE(upboard_up2_spi1_pins)); + +static_assert(ARRAY_SIZE(upboard_up2_spi_modes) == ARRAY_SIZE(upboard_up2_spi2_pins)); + +static const unsigned int upboard_up2_i2s0_pins[] = { + UPBOARD_UP2_BIT_TO_PIN(I2S_BCLK), + UPBOARD_UP2_BIT_TO_PIN(I2S_WS_SYNC), + UPBOARD_UP2_BIT_TO_PIN(I2S_SDI), + UPBOARD_UP2_BIT_TO_PIN(I2S_SDO), +}; + +static const enum upboard_pin_mode upboard_up2_i2s0_modes[] = { + UPBOARD_PIN_MODE_GPIO_OUT, + UPBOARD_PIN_MODE_GPIO_OUT, + UPBOARD_PIN_MODE_GPIO_IN, + UPBOARD_PIN_MODE_GPIO_OUT, +}; + +static_assert(ARRAY_SIZE(upboard_up2_i2s0_modes) == ARRAY_SIZE(upboard_up2_i2s0_pins)); + +static const unsigned int upboard_up2_pwm0_pins[] = { + UPBOARD_UP2_BIT_TO_PIN(PWM0), +}; + +static const unsigned int upboard_up2_pwm1_pins[] = { + UPBOARD_UP2_BIT_TO_PIN(PWM1), +}; + +static const unsigned int upboard_up2_adc0_pins[] = { + UPBOARD_UP2_BIT_TO_PIN(GPIO3_ADC0), +}; + +static const unsigned int upboard_up2_adc2_pins[] = { + UPBOARD_UP2_BIT_TO_PIN(GPIO5_ADC2), +}; + +static const unsigned int upboard_up2_adc3_pins[] = { + UPBOARD_UP2_BIT_TO_PIN(GPIO6_ADC3), +}; + +static const struct upboard_pingroup upboard_up2_pin_groups[] = { + UPBOARD_PINGROUP("uart1_grp", upboard_up2_uart1_pins, &upboard_up2_uart1_modes[0]), + UPBOARD_PINGROUP("i2c0_grp", upboard_up2_i2c0_pins, UPBOARD_PIN_MODE_FUNCTION), + UPBOARD_PINGROUP("i2c1_grp", upboard_up2_i2c1_pins, UPBOARD_PIN_MODE_FUNCTION), + UPBOARD_PINGROUP("spi1_grp", upboard_up2_spi1_pins, &upboard_up2_spi_modes[0]), + UPBOARD_PINGROUP("spi2_grp", upboard_up2_spi2_pins, &upboard_up2_spi_modes[0]), + UPBOARD_PINGROUP("i2s0_grp", upboard_up2_i2s0_pins, &upboard_up2_i2s0_modes[0]), + UPBOARD_PINGROUP("pwm0_grp", upboard_up2_pwm0_pins, UPBOARD_PIN_MODE_GPIO_OUT), + UPBOARD_PINGROUP("pwm1_grp", upboard_up2_pwm1_pins, UPBOARD_PIN_MODE_GPIO_OUT), + UPBOARD_PINGROUP("adc0_grp", upboard_up2_adc0_pins, UPBOARD_PIN_MODE_GPIO_IN), + UPBOARD_PINGROUP("adc2_grp", upboard_up2_adc2_pins, UPBOARD_PIN_MODE_GPIO_IN), + UPBOARD_PINGROUP("adc3_grp", upboard_up2_adc3_pins, UPBOARD_PIN_MODE_GPIO_IN), +}; + +static const char * const upboard_up2_uart1_groups[] = { "uart1_grp" }; +static const char * const upboard_up2_i2c0_groups[] = { "i2c0_grp" }; +static const char * const upboard_up2_i2c1_groups[] = { "i2c1_grp" }; +static const char * const upboard_up2_spi1_groups[] = { "spi1_grp" }; +static const char * const upboard_up2_spi2_groups[] = { "spi2_grp" }; +static const char * const upboard_up2_i2s0_groups[] = { "i2s0_grp" }; +static const char * const upboard_up2_pwm0_groups[] = { "pwm0_grp" }; +static const char * const upboard_up2_pwm1_groups[] = { "pwm1_grp" }; +static const char * const upboard_up2_adc0_groups[] = { "adc0_grp" }; +static const char * const upboard_up2_adc2_groups[] = { "adc2_grp" }; +static const char * const upboard_up2_adc3_groups[] = { "adc3_grp" }; + +static const struct pinfunction upboard_up2_pin_functions[] = { + UPBOARD_FUNCTION("uart1", upboard_up2_uart1_groups), + UPBOARD_FUNCTION("i2c0", upboard_up2_i2c0_groups), + UPBOARD_FUNCTION("i2c1", upboard_up2_i2c1_groups), + UPBOARD_FUNCTION("spi1", upboard_up2_spi1_groups), + UPBOARD_FUNCTION("spi2", upboard_up2_spi2_groups), + UPBOARD_FUNCTION("i2s0", upboard_up2_i2s0_groups), + UPBOARD_FUNCTION("pwm0", upboard_up2_pwm0_groups), + UPBOARD_FUNCTION("pwm1", upboard_up2_pwm1_groups), + UPBOARD_FUNCTION("adc0", upboard_up2_adc0_groups), + UPBOARD_FUNCTION("adc2", upboard_up2_adc2_groups), + UPBOARD_FUNCTION("adc3", upboard_up2_adc3_groups), +}; + +static const struct upboard_pinctrl_data upboard_up2_pinctrl_data = { + .groups = &upboard_up2_pin_groups[0], + .ngroups = ARRAY_SIZE(upboard_up2_pin_groups), + .funcs = &upboard_up2_pin_functions[0], + .nfuncs = ARRAY_SIZE(upboard_up2_pin_functions), + .pin_header = &upboard_up2_pin_header[0], + .ngpio = ARRAY_SIZE(upboard_up2_pin_header), +}; + +static int upboard_pinctrl_set_function(struct pinctrl_dev *pctldev, unsigned int offset) +{ + struct upboard_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct upboard_pin *p = &pctrl->pins[offset]; + int ret; + + if (!p->funcbit) + return -EPERM; + + ret = regmap_field_write(p->enbit, 0); + if (ret) + return ret; + + return regmap_field_write(p->funcbit, 1); +} + +static int upboard_pinctrl_gpio_commit_enable(struct pinctrl_dev *pctldev, unsigned int offset) +{ + struct upboard_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct upboard_pin *p = &pctrl->pins[offset]; + int ret; + + if (p->funcbit) { + ret = regmap_field_write(p->funcbit, 0); + if (ret) + return ret; + } + + return regmap_field_write(p->enbit, 1); +} + +static int upboard_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset) +{ + return upboard_pinctrl_gpio_commit_enable(pctldev, offset); +} + +static void upboard_pinctrl_gpio_commit_disable(struct pinctrl_dev *pctldev, unsigned int offset) +{ + struct upboard_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct upboard_pin *p = &pctrl->pins[offset]; + + regmap_field_write(p->enbit, 0); +}; + +static void upboard_pinctrl_gpio_disable_free(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, unsigned int offset) +{ + return upboard_pinctrl_gpio_commit_disable(pctldev, offset); +} + +static int upboard_pinctrl_gpio_commit_direction(struct pinctrl_dev *pctldev, unsigned int offset, + bool input) +{ + struct upboard_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct upboard_pin *p = &pctrl->pins[offset]; + + return regmap_field_write(p->dirbit, input); +} + +static int upboard_pinctrl_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset, bool input) +{ + return upboard_pinctrl_gpio_commit_direction(pctldev, offset, input); +} + +static int upboard_pinctrl_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector, + unsigned int group_selector) +{ + struct upboard_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + const struct upboard_pinctrl_data *pctrl_data = pctrl->pctrl_data; + const struct upboard_pingroup *upgroups = pctrl_data->groups; + struct group_desc *grp; + unsigned int mode, i; + int ret; + + grp = pinctrl_generic_get_group(pctldev, group_selector); + if (!grp) + return -EINVAL; + + for (i = 0; i < grp->grp.npins; i++) { + mode = upgroups[group_selector].mode ?: upgroups[group_selector].modes[i]; + if (mode == UPBOARD_PIN_MODE_FUNCTION) { + ret = upboard_pinctrl_set_function(pctldev, grp->grp.pins[i]); + if (ret) + return ret; + + continue; + } + + ret = upboard_pinctrl_gpio_commit_enable(pctldev, grp->grp.pins[i]); + if (ret) + return ret; + + ret = upboard_pinctrl_gpio_commit_direction(pctldev, grp->grp.pins[i], + mode == UPBOARD_PIN_MODE_GPIO_IN); + if (ret) + return ret; + } + + return 0; +} + +static const struct pinmux_ops upboard_pinmux_ops = { + .get_functions_count = pinmux_generic_get_function_count, + .get_function_name = pinmux_generic_get_function_name, + .get_function_groups = pinmux_generic_get_function_groups, + .set_mux = upboard_pinctrl_set_mux, + .gpio_request_enable = upboard_pinctrl_gpio_request_enable, + .gpio_disable_free = upboard_pinctrl_gpio_disable_free, + .gpio_set_direction = upboard_pinctrl_gpio_set_direction, +}; + +static int upboard_pinctrl_pin_get_mode(struct pinctrl_dev *pctldev, unsigned int pin) +{ + struct upboard_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct upboard_pin *p = &pctrl->pins[pin]; + unsigned int val; + int ret; + + if (p->funcbit) { + ret = regmap_field_read(p->funcbit, &val); + if (ret) + return ret; + if (val) + return UPBOARD_PIN_MODE_FUNCTION; + } + + ret = regmap_field_read(p->enbit, &val); + if (ret) + return ret; + if (!val) + return UPBOARD_PIN_MODE_DISABLED; + + ret = regmap_field_read(p->dirbit, &val); + if (ret) + return ret; + + return val ? UPBOARD_PIN_MODE_GPIO_IN : UPBOARD_PIN_MODE_GPIO_OUT; +} + +static void upboard_pinctrl_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, + unsigned int offset) +{ + int ret; + + ret = upboard_pinctrl_pin_get_mode(pctldev, offset); + if (ret == UPBOARD_PIN_MODE_FUNCTION) + seq_puts(s, "mode function "); + else if (ret == UPBOARD_PIN_MODE_DISABLED) + seq_puts(s, "HIGH-Z "); + else if (ret < 0) + seq_puts(s, "N/A "); + else + seq_printf(s, "GPIO (%s) ", str_input_output(ret == UPBOARD_PIN_MODE_GPIO_IN)); +} + +static const struct pinctrl_ops upboard_pinctrl_ops = { + .get_groups_count = pinctrl_generic_get_group_count, + .get_group_name = pinctrl_generic_get_group_name, + .get_group_pins = pinctrl_generic_get_group_pins, + .pin_dbg_show = upboard_pinctrl_dbg_show, +}; + +static int upboard_gpio_request(struct gpio_chip *gc, unsigned int offset) +{ + struct gpiochip_fwd *fwd = gpiochip_get_data(gc); + struct upboard_pinctrl *pctrl = gpiochip_fwd_get_data(fwd); + unsigned int pin = pctrl->pctrl_data->pin_header[offset]; + struct gpio_desc *desc; + int ret; + + ret = pinctrl_gpio_request(gc, offset); + if (ret) + return ret; + + desc = gpiod_get_index(pctrl->dev, "external", pin, 0); + if (IS_ERR(desc)) { + pinctrl_gpio_free(gc, offset); + return PTR_ERR(desc); + } + + return gpiochip_fwd_desc_add(fwd, desc, offset); +} + +static void upboard_gpio_free(struct gpio_chip *gc, unsigned int offset) +{ + struct gpiochip_fwd *fwd = gpiochip_get_data(gc); + + gpiochip_fwd_desc_free(fwd, offset); + pinctrl_gpio_free(gc, offset); +} + +static int upboard_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) +{ + struct gpiochip_fwd *fwd = gpiochip_get_data(gc); + struct upboard_pinctrl *pctrl = gpiochip_fwd_get_data(fwd); + unsigned int pin = pctrl->pctrl_data->pin_header[offset]; + int mode; + + /* If the pin is in function mode or high-z, input direction is returned */ + mode = upboard_pinctrl_pin_get_mode(pctrl->pctldev, pin); + if (mode < 0) + return mode; + + if (mode == UPBOARD_PIN_MODE_GPIO_OUT) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; +} + +static int upboard_gpio_direction_input(struct gpio_chip *gc, unsigned int offset) +{ + struct gpiochip_fwd *fwd = gpiochip_get_data(gc); + int ret; + + ret = pinctrl_gpio_direction_input(gc, offset); + if (ret) + return ret; + + return gpiochip_fwd_gpio_direction_input(fwd, offset); +} + +static int upboard_gpio_direction_output(struct gpio_chip *gc, unsigned int offset, int value) +{ + struct gpiochip_fwd *fwd = gpiochip_get_data(gc); + int ret; + + ret = pinctrl_gpio_direction_output(gc, offset); + if (ret) + return ret; + + return gpiochip_fwd_gpio_direction_output(fwd, offset, value); +} + +static int upboard_pinctrl_register_groups(struct upboard_pinctrl *pctrl) +{ + const struct upboard_pingroup *groups = pctrl->pctrl_data->groups; + size_t ngroups = pctrl->pctrl_data->ngroups; + unsigned int i; + int ret; + + for (i = 0; i < ngroups; i++) { + ret = pinctrl_generic_add_group(pctrl->pctldev, groups[i].grp.name, + groups[i].grp.pins, groups[i].grp.npins, pctrl); + if (ret < 0) + return ret; + } + + return 0; +} + +static int upboard_pinctrl_register_functions(struct upboard_pinctrl *pctrl) +{ + const struct pinfunction *funcs = pctrl->pctrl_data->funcs; + size_t nfuncs = pctrl->pctrl_data->nfuncs; + unsigned int i; + int ret; + + for (i = 0; i < nfuncs ; i++) { + ret = pinmux_generic_add_function(pctrl->pctldev, funcs[i].name, + funcs[i].groups, funcs[i].ngroups, NULL); + if (ret < 0) + return ret; + } + + return 0; +} + +static const struct pinctrl_map pinctrl_map_apl01[] = { + PIN_MAP_MUX_GROUP_DEFAULT("upboard-pinctrl", "INT3452:00", "pwm0_grp", "pwm0"), + PIN_MAP_MUX_GROUP_DEFAULT("upboard-pinctrl", "INT3452:00", "pwm1_grp", "pwm1"), + PIN_MAP_MUX_GROUP_DEFAULT("upboard-pinctrl", "INT3452:00", "uart1_grp", "uart1"), + PIN_MAP_MUX_GROUP_DEFAULT("upboard-pinctrl", "INT3452:02", "i2c0_grp", "i2c0"), + PIN_MAP_MUX_GROUP_DEFAULT("upboard-pinctrl", "INT3452:02", "i2c1_grp", "i2c1"), + PIN_MAP_MUX_GROUP_DEFAULT("upboard-pinctrl", "INT3452:01", "ssp0_grp", "ssp0"), +}; + +static const struct upboard_pinctrl_map upboard_pinctrl_map_apl01 = { + .maps = &pinctrl_map_apl01[0], + .nmaps = ARRAY_SIZE(pinctrl_map_apl01), +}; + +static const struct dmi_system_id dmi_platform_info[] = { + { + /* UP Squared */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "AAEON"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "UP-APL01"), + }, + .driver_data = (void *)&upboard_pinctrl_map_apl01, + }, + { } +}; + +static int upboard_pinctrl_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct upboard_fpga *fpga = dev_get_drvdata(dev->parent); + const struct upboard_pinctrl_map *board_map; + const struct dmi_system_id *dmi_id; + struct pinctrl_desc *pctldesc; + struct upboard_pinctrl *pctrl; + struct upboard_pin *pins; + struct gpiochip_fwd *fwd; + struct pinctrl *pinctrl; + struct gpio_chip *chip; + unsigned int i; + int ret; + + pctldesc = devm_kzalloc(dev, sizeof(*pctldesc), GFP_KERNEL); + if (!pctldesc) + return -ENOMEM; + + pctrl = devm_kzalloc(dev, sizeof(*pctrl), GFP_KERNEL); + if (!pctrl) + return -ENOMEM; + + switch (fpga->fpga_data->type) { + case UPBOARD_UP_FPGA: + pctldesc->pins = upboard_up_pins; + pctldesc->npins = ARRAY_SIZE(upboard_up_pins); + pctrl->pctrl_data = &upboard_up_pinctrl_data; + break; + case UPBOARD_UP2_FPGA: + pctldesc->pins = upboard_up2_pins; + pctldesc->npins = ARRAY_SIZE(upboard_up2_pins); + pctrl->pctrl_data = &upboard_up2_pinctrl_data; + break; + default: + return dev_err_probe(dev, -ENODEV, "Unsupported device type %d\n", + fpga->fpga_data->type); + } + + dmi_id = dmi_first_match(dmi_platform_info); + if (!dmi_id) + return dev_err_probe(dev, -ENODEV, "Unsupported board\n"); + + board_map = (const struct upboard_pinctrl_map *)dmi_id->driver_data; + + pctldesc->name = dev_name(dev); + pctldesc->owner = THIS_MODULE; + pctldesc->pctlops = &upboard_pinctrl_ops; + pctldesc->pmxops = &upboard_pinmux_ops; + + pctrl->dev = dev; + + pins = devm_kcalloc(dev, pctldesc->npins, sizeof(*pins), GFP_KERNEL); + if (!pins) + return -ENOMEM; + + /* Initialize pins */ + for (i = 0; i < pctldesc->npins; i++) { + const struct pinctrl_pin_desc *pin_desc = &pctldesc->pins[i]; + unsigned int regoff = pin_desc->number / UPBOARD_REGISTER_SIZE; + unsigned int lsb = pin_desc->number % UPBOARD_REGISTER_SIZE; + struct reg_field * const fld_func = pin_desc->drv_data; + struct upboard_pin *pin = &pins[i]; + struct reg_field fldconf = {}; + + if (fld_func) { + pin->funcbit = devm_regmap_field_alloc(dev, fpga->regmap, *fld_func); + if (IS_ERR(pin->funcbit)) + return PTR_ERR(pin->funcbit); + } + + fldconf.reg = UPBOARD_REG_GPIO_EN0 + regoff; + fldconf.lsb = lsb; + fldconf.msb = lsb; + pin->enbit = devm_regmap_field_alloc(dev, fpga->regmap, fldconf); + if (IS_ERR(pin->enbit)) + return PTR_ERR(pin->enbit); + + fldconf.reg = UPBOARD_REG_GPIO_DIR0 + regoff; + fldconf.lsb = lsb; + fldconf.msb = lsb; + pin->dirbit = devm_regmap_field_alloc(dev, fpga->regmap, fldconf); + if (IS_ERR(pin->dirbit)) + return PTR_ERR(pin->dirbit); + } + + pctrl->pins = pins; + + ret = devm_pinctrl_register_and_init(dev, pctldesc, pctrl, &pctrl->pctldev); + if (ret) + return dev_err_probe(dev, ret, "Failed to register pinctrl\n"); + + ret = upboard_pinctrl_register_groups(pctrl); + if (ret) + return dev_err_probe(dev, ret, "Failed to register groups\n"); + + ret = upboard_pinctrl_register_functions(pctrl); + if (ret) + return dev_err_probe(dev, ret, "Failed to register functions\n"); + + ret = devm_pinctrl_register_mappings(dev, board_map->maps, board_map->nmaps); + if (ret) + return ret; + + pinctrl = devm_pinctrl_get_select_default(dev); + if (IS_ERR(pinctrl)) + return dev_err_probe(dev, PTR_ERR(pinctrl), "Failed to select pinctrl\n"); + + ret = pinctrl_enable(pctrl->pctldev); + if (ret) + return ret; + + fwd = devm_gpiochip_fwd_alloc(dev, pctrl->pctrl_data->ngpio); + if (IS_ERR(fwd)) + return dev_err_probe(dev, PTR_ERR(fwd), "Failed to allocate the gpiochip forwarder\n"); + + chip = gpiochip_fwd_get_gpiochip(fwd); + chip->request = upboard_gpio_request; + chip->free = upboard_gpio_free; + chip->get_direction = upboard_gpio_get_direction; + chip->direction_output = upboard_gpio_direction_output; + chip->direction_input = upboard_gpio_direction_input; + + ret = gpiochip_fwd_register(fwd, pctrl); + if (ret) + return dev_err_probe(dev, ret, "Failed to register the gpiochip forwarder\n"); + + return gpiochip_add_sparse_pin_range(chip, dev_name(dev), 0, pctrl->pctrl_data->pin_header, + pctrl->pctrl_data->ngpio); +} + +static struct platform_driver upboard_pinctrl_driver = { + .driver = { + .name = "upboard-pinctrl", + }, + .probe = upboard_pinctrl_probe, +}; +module_platform_driver(upboard_pinctrl_driver); + +MODULE_AUTHOR("Thomas Richard Date: Mon, 18 Aug 2025 17:47:48 +0800 Subject: [PATCH 01194/11391] Documentation/sphinx: Fix typo in automarkup.py "whan" -> "when" Signed-off-by: Iris Shi <0.0@owo.li> Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/8e5ddb7d-8faf-314f-b1b1-2d15d6900862@owo.li --- Documentation/sphinx/automarkup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/sphinx/automarkup.py b/Documentation/sphinx/automarkup.py index 563033f764bb..1d9dada40a74 100644 --- a/Documentation/sphinx/automarkup.py +++ b/Documentation/sphinx/automarkup.py @@ -244,7 +244,7 @@ def add_and_resolve_xref(app, docname, domain, reftype, target, contnode=None): return contnode # -# Variant of markup_abi_ref() that warns whan a reference is not found +# Variant of markup_abi_ref() that warns when a reference is not found # def markup_abi_file_ref(docname, app, match): return markup_abi_ref(docname, app, match, warning=True) From ed14c74ddf4932a2505afae30dac7639c96bcb0c Mon Sep 17 00:00:00 2001 From: "Nikola Z. Ivanov" Date: Sat, 16 Aug 2025 22:00:28 +0300 Subject: [PATCH 01195/11391] docs: Replace dead links to spectre side channel white papers The papers are published by Intel, AMD and MIPS. Signed-off-by: Nikola Z. Ivanov Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250816190028.55573-1-zlatistiv@gmail.com --- Documentation/admin-guide/hw-vuln/spectre.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/admin-guide/hw-vuln/spectre.rst b/Documentation/admin-guide/hw-vuln/spectre.rst index 132e0bc6007e..991f12adef8d 100644 --- a/Documentation/admin-guide/hw-vuln/spectre.rst +++ b/Documentation/admin-guide/hw-vuln/spectre.rst @@ -664,7 +664,7 @@ Intel white papers: .. _spec_ref1: -[1] `Intel analysis of speculative execution side channels `_. +[1] `Intel analysis of speculative execution side channels `_. .. _spec_ref2: @@ -682,7 +682,7 @@ AMD white papers: .. _spec_ref5: -[5] `AMD64 technology indirect branch control extension `_. +[5] `AMD64 technology indirect branch control extension `_. .. _spec_ref6: @@ -708,7 +708,7 @@ MIPS white paper: .. _spec_ref10: -[10] `MIPS: response on speculative execution and side channel vulnerabilities `_. +[10] `MIPS: response on speculative execution and side channel vulnerabilities `_. Academic papers: From 6865cb19082140a07da356f57d52168aec38340c Mon Sep 17 00:00:00 2001 From: Vivek Yadav Date: Sat, 16 Aug 2025 01:24:52 -0700 Subject: [PATCH 01196/11391] docs: remove a duplicated word from kernel-parameters.txt Fix kernel-doc warning in kernel-parameters.txt WARNING: Possible repeated word: 'is' Signed-off-by: Vivek Yadav Acked-by: Randy Dunlap Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250816082452.219009-1-vivekyadav1207731111@gmail.com --- Documentation/admin-guide/kernel-parameters.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 747a55abf494..302145870f1c 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -7506,7 +7506,7 @@ Set a trigger on top of a specific event, with an optional filter. - The format is is "trace_trigger=.[ if ],..." + The format is "trace_trigger=.[ if ],..." Where more than one trigger may be specified that are comma deliminated. For example: From 6cf5f13ef3f1c032b48fddd4f0f9108236c7762a Mon Sep 17 00:00:00 2001 From: Ranganath V N Date: Fri, 15 Aug 2025 00:13:03 +0530 Subject: [PATCH 01197/11391] Documentation: Fix driver-api typos Corrected a few spelling mistakes functionalty ==> functionality in Documentation/driver-api/cxl/devices/device-types.rst adjascent ==> adjacent in Documentation/driver-api/cxl/platform/example-configurations/one-dev-per-hb.rst succeessful ==> successful in Documentation/driver-api/thermal/exynos_thermal_emulation.rst Signed-off-by: Ranganath V N Reviewed-by: Randy Dunlap Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250814184304.20448-1-vnranganath.20@gmail.com --- .../driver-api/cxl/devices/device-types.rst | 2 +- .../example-configurations/one-dev-per-hb.rst | 2 +- .../thermal/exynos_thermal_emulation.rst | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Documentation/driver-api/cxl/devices/device-types.rst b/Documentation/driver-api/cxl/devices/device-types.rst index 923f5d89bc04..7f69dfa4509b 100644 --- a/Documentation/driver-api/cxl/devices/device-types.rst +++ b/Documentation/driver-api/cxl/devices/device-types.rst @@ -22,7 +22,7 @@ The basic interaction protocol, similar to PCIe configuration mechanisms. Typically used for initialization, configuration, and I/O access for anything other than memory (CXL.mem) or cache (CXL.cache) operations. -The Linux CXL driver exposes access to .io functionalty via the various sysfs +The Linux CXL driver exposes access to .io functionality via the various sysfs interfaces and /dev/cxl/ devices (which exposes direct access to device mailboxes). diff --git a/Documentation/driver-api/cxl/platform/example-configurations/one-dev-per-hb.rst b/Documentation/driver-api/cxl/platform/example-configurations/one-dev-per-hb.rst index aebda0eb3e17..a4c3fb51ea7d 100644 --- a/Documentation/driver-api/cxl/platform/example-configurations/one-dev-per-hb.rst +++ b/Documentation/driver-api/cxl/platform/example-configurations/one-dev-per-hb.rst @@ -10,7 +10,7 @@ has a single CXL memory expander with a 4GB of memory. Things to note: * Cross-Bridge interleave is not being used. -* The expanders are in two separate but adjascent memory regions. +* The expanders are in two separate but adjacent memory regions. * This CEDT/SRAT describes one node per device * The expanders have the same performance and will be in the same memory tier. diff --git a/Documentation/driver-api/thermal/exynos_thermal_emulation.rst b/Documentation/driver-api/thermal/exynos_thermal_emulation.rst index c21d10838bc5..c679502f01c7 100644 --- a/Documentation/driver-api/thermal/exynos_thermal_emulation.rst +++ b/Documentation/driver-api/thermal/exynos_thermal_emulation.rst @@ -28,13 +28,13 @@ changed into it. delay of changing temperature. However, this node only uses same delay of real sensing time, 938us.) -Exynos emulation mode requires synchronous of value changing and -enabling. It means when you want to update the any value of delay or -next temperature, then you have to enable emulation mode at the same -time. (Or you have to keep the mode enabling.) If you don't, it fails to -change the value to updated one and just use last succeessful value -repeatedly. That's why this node gives users the right to change -termerpature only. Just one interface makes it more simply to use. +Exynos emulation mode requires that value changes and enabling are performed +synchronously. This means that when you want to update any value, such as the +delay or the next temperature, you must enable emulation mode at the same +time (or keep the mode enabled). If you do not, the value will fail to update +and the last successful value will continue to be used. For this reason, +this node only allows users to change the temperature. Providing a single +interface makes it simpler to use. Disabling emulation mode only requires writing value 0 to sysfs node. From 670ec7333a2c4823ac777b70f045cf731525ae5e Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 14 Aug 2025 09:40:29 -0600 Subject: [PATCH 01198/11391] docs: kdoc: remove dead code create_parameter_list() tests an argument against the same regex twice, in two different locations; remove the pointless extra tests and the never-executed error cases that go with them. Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250814154035.328769-2-corbet@lwn.net --- scripts/lib/kdoc/kdoc_parser.py | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py index 9e65948f8254..96e3fe4ec431 100644 --- a/scripts/lib/kdoc/kdoc_parser.py +++ b/scripts/lib/kdoc/kdoc_parser.py @@ -564,28 +564,18 @@ class KernelDoc: args.insert(0, first_arg.pop()) dtype = ' '.join(first_arg) + bitfield_re = KernRe(r'(.*?):(\w+)') for param in args: - if KernRe(r'^(\*+)\s*(.*)').match(param): - r = KernRe(r'^(\*+)\s*(.*)') - if not r.match(param): - self.emit_msg(ln, f"Invalid param: {param}") - continue - - param = r.group(1) - + r = KernRe(r'^(\*+)\s*(.*)') + if r.match(param): self.push_parameter(ln, decl_type, r.group(2), f"{dtype} {r.group(1)}", arg, declaration_name) - elif KernRe(r'(.*?):(\w+)').search(param): - r = KernRe(r'(.*?):(\w+)') - if not r.match(param): - self.emit_msg(ln, f"Invalid param: {param}") - continue - + elif bitfield_re.search(param): if dtype != "": # Skip unnamed bit-fields - self.push_parameter(ln, decl_type, r.group(1), - f"{dtype}:{r.group(2)}", + self.push_parameter(ln, decl_type, bitfield_re.group(1), + f"{dtype}:{bitfield_re.group(2)}", arg, declaration_name) else: self.push_parameter(ln, decl_type, param, dtype, From f51b42b99e1d35698e0277337fde2c15ccc29a2b Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 14 Aug 2025 09:40:30 -0600 Subject: [PATCH 01199/11391] docs: kdoc: tidy up space removal in create_parameter_list() Remove a redundant test and add a comment describing what the space removal is doing. Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250814154035.328769-3-corbet@lwn.net --- scripts/lib/kdoc/kdoc_parser.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py index 96e3fe4ec431..53051ce831ba 100644 --- a/scripts/lib/kdoc/kdoc_parser.py +++ b/scripts/lib/kdoc/kdoc_parser.py @@ -545,12 +545,14 @@ class KernelDoc: arg, declaration_name) elif arg: + # + # Clean up extraneous spaces and split the string at commas; the first + # element of the resulting list will also include the type information. + # arg = KernRe(r'\s*:\s*').sub(":", arg) arg = KernRe(r'\s*\[').sub('[', arg) - args = KernRe(r'\s*,\s*').split(arg) - if args[0] and '*' in args[0]: - args[0] = re.sub(r'(\*+)\s*', r' \1', args[0]) + args[0] = re.sub(r'(\*+)\s*', r' \1', args[0]) first_arg = [] r = KernRe(r'^(.*\s+)(.*?\[.*\].*)$') From 05d72fe07242a8e4535aa52e0858f9198e668a41 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 14 Aug 2025 09:40:31 -0600 Subject: [PATCH 01200/11391] docs: kdoc: clean up the create_parameter_list() "first arg" logic The logic for finding the name of the first in a series of variable names is somewhat convoluted and, in the use of .extend(), actively buggy. Document what is happening and simplify the logic. Acked-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250814154035.328769-4-corbet@lwn.net --- scripts/lib/kdoc/kdoc_parser.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py index 53051ce831ba..07234ce04409 100644 --- a/scripts/lib/kdoc/kdoc_parser.py +++ b/scripts/lib/kdoc/kdoc_parser.py @@ -553,18 +553,18 @@ class KernelDoc: arg = KernRe(r'\s*\[').sub('[', arg) args = KernRe(r'\s*,\s*').split(arg) args[0] = re.sub(r'(\*+)\s*', r' \1', args[0]) - - first_arg = [] - r = KernRe(r'^(.*\s+)(.*?\[.*\].*)$') - if args[0] and r.match(args[0]): - args.pop(0) - first_arg.extend(r.group(1)) - first_arg.append(r.group(2)) + # + # args[0] has a string of "type a". If "a" includes an [array] + # declaration, we want to not be fooled by any white space inside + # the brackets, so detect and handle that case specially. + # + r = KernRe(r'^([^[\]]*\s+)(.*)$') + if r.match(args[0]): + args[0] = r.group(2) + dtype = r.group(1) else: - first_arg = KernRe(r'\s+').split(args.pop(0)) - - args.insert(0, first_arg.pop()) - dtype = ' '.join(first_arg) + # No space in args[0]; this seems wrong but preserves previous behavior + dtype = '' bitfield_re = KernRe(r'(.*?):(\w+)') for param in args: From 8f05fbc5afb86f0d4dcae33f3cb0cda561d4d93e Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 14 Aug 2025 09:40:32 -0600 Subject: [PATCH 01201/11391] docs: kdoc: add a couple more comments in create_parameter_list() Make what the final code is doing a bit more clear to slow readers like me. Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250814154035.328769-5-corbet@lwn.net --- scripts/lib/kdoc/kdoc_parser.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py index 07234ce04409..29881757bf1c 100644 --- a/scripts/lib/kdoc/kdoc_parser.py +++ b/scripts/lib/kdoc/kdoc_parser.py @@ -568,12 +568,18 @@ class KernelDoc: bitfield_re = KernRe(r'(.*?):(\w+)') for param in args: + # + # For pointers, shift the star(s) from the variable name to the + # type declaration. + # r = KernRe(r'^(\*+)\s*(.*)') if r.match(param): self.push_parameter(ln, decl_type, r.group(2), f"{dtype} {r.group(1)}", arg, declaration_name) - + # + # Perform a similar shift for bitfields. + # elif bitfield_re.search(param): if dtype != "": # Skip unnamed bit-fields self.push_parameter(ln, decl_type, bitfield_re.group(1), From bf6b310d1b7e31a1cd6951eb75608a1d2876c04a Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 14 Aug 2025 09:40:33 -0600 Subject: [PATCH 01202/11391] docs: kdoc: tighten up the array-of-pointers case Simplify one gnarly regex and remove another altogether; add a comment describing what is going on. There will be no #-substituted commas in this case, so don't bother trying to put them back. Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250814154035.328769-6-corbet@lwn.net --- scripts/lib/kdoc/kdoc_parser.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py index 29881757bf1c..7f4d95dd47d4 100644 --- a/scripts/lib/kdoc/kdoc_parser.py +++ b/scripts/lib/kdoc/kdoc_parser.py @@ -527,23 +527,21 @@ class KernelDoc: dtype = KernRe(r'([^\(]+\(\*?)\s*' + re.escape(param)).sub(r'\1', arg) self.push_parameter(ln, decl_type, param, dtype, arg, declaration_name) - + # + # The array-of-pointers case. Dig the parameter name out from the middle + # of the declaration. + # elif KernRe(r'\(.+\)\s*\[').search(arg): - # Array-of-pointers - - arg = arg.replace('#', ',') - r = KernRe(r'[^\(]+\(\s*\*\s*([\w\[\].]*?)\s*(\s*\[\s*[\w]+\s*\]\s*)*\)') + r = KernRe(r'[^\(]+\(\s*\*\s*' # Up to "(" and maybe "*" + r'([\w.]*?)' # The actual pointer name + r'\s*(\[\s*\w+\s*\]\s*)*\)') # The [array portion] if r.match(arg): param = r.group(1) else: self.emit_msg(ln, f"Invalid param: {arg}") param = arg - - dtype = KernRe(r'([^\(]+\(\*?)\s*' + re.escape(param)).sub(r'\1', arg) - - self.push_parameter(ln, decl_type, param, dtype, - arg, declaration_name) - + dtype = arg.replace(param, '') + self.push_parameter(ln, decl_type, param, dtype, arg, declaration_name) elif arg: # # Clean up extraneous spaces and split the string at commas; the first From e5d91662fcbac251dd17f04dbacf4d997939316e Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 14 Aug 2025 09:40:34 -0600 Subject: [PATCH 01203/11391] docs: kdoc: tighten up the pointer-to-function case Tighten up the code and remove an unneeded regex operation. Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250814154035.328769-7-corbet@lwn.net --- scripts/lib/kdoc/kdoc_parser.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py index 7f4d95dd47d4..998b1ece932a 100644 --- a/scripts/lib/kdoc/kdoc_parser.py +++ b/scripts/lib/kdoc/kdoc_parser.py @@ -511,22 +511,21 @@ class KernelDoc: # Treat preprocessor directive as a typeless variable self.push_parameter(ln, decl_type, arg, "", "", declaration_name) - + # + # The pointer-to-function case. + # elif KernRe(r'\(.+\)\s*\(').search(arg): - # Pointer-to-function - arg = arg.replace('#', ',') - - r = KernRe(r'[^\(]+\(\*?\s*([\w\[\].]*)\s*\)') + r = KernRe(r'[^\(]+\(\*?\s*' # Everything up to "(*" + r'([\w\[\].]*)' # Capture the name and possible [array] + r'\s*\)') # Make sure the trailing ")" is there if r.match(arg): param = r.group(1) else: self.emit_msg(ln, f"Invalid param: {arg}") param = arg - - dtype = KernRe(r'([^\(]+\(\*?)\s*' + re.escape(param)).sub(r'\1', arg) - self.push_parameter(ln, decl_type, param, dtype, - arg, declaration_name) + dtype = arg.replace(param, '') + self.push_parameter(ln, decl_type, param, dtype, arg, declaration_name) # # The array-of-pointers case. Dig the parameter name out from the middle # of the declaration. From 1d8125e27323d8a378cb38f88a6c5a0d7fdb2f6c Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 14 Aug 2025 09:40:35 -0600 Subject: [PATCH 01204/11391] docs: kdoc: remove redundant comment stripping By the time stuff gets to create_parameter_list(), comments have long since been stripped out, so we do not need to do it again here. Acked-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250814154035.328769-8-corbet@lwn.net --- scripts/lib/kdoc/kdoc_parser.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py index 998b1ece932a..a560546c1867 100644 --- a/scripts/lib/kdoc/kdoc_parser.py +++ b/scripts/lib/kdoc/kdoc_parser.py @@ -493,9 +493,6 @@ class KernelDoc: args = arg_expr.sub(r"\1#", args) for arg in args.split(splitter): - # Strip comments - arg = KernRe(r'/\*.*\*/').sub('', arg) - # Ignore argument attributes arg = KernRe(r'\sPOS0?\s').sub(' ', arg) From 359ad700eb8b563461819b6227b021b280e37e3e Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Thu, 14 Aug 2025 08:20:45 +0700 Subject: [PATCH 01205/11391] Documentation: ktap: Correct "its" spelling Fix possessive adjective "its" spelling. Signed-off-by: Bagas Sanjaya Reviewed-by: Randy Dunlap Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250814012046.21235-2-bagasdotme@gmail.com --- Documentation/dev-tools/ktap.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/dev-tools/ktap.rst b/Documentation/dev-tools/ktap.rst index 414c105b10a9..54fac3d3bf7b 100644 --- a/Documentation/dev-tools/ktap.rst +++ b/Documentation/dev-tools/ktap.rst @@ -5,7 +5,7 @@ The Kernel Test Anything Protocol (KTAP), version 1 =================================================== TAP, or the Test Anything Protocol is a format for specifying test results used -by a number of projects. It's website and specification are found at this `link +by a number of projects. Its website and specification are found at this `link `_. The Linux Kernel largely uses TAP output for test results. However, Kernel testing frameworks have special needs for test results which don't align with the original TAP specification. Thus, a "Kernel TAP" From fea71fe1f060a722f7cb26aeca27d36d9370916d Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Thu, 14 Aug 2025 08:20:46 +0700 Subject: [PATCH 01206/11391] Documentation: ktap: Separate first bullet list items The first bullet list items are shown in htmldocs output as combined with previous paragraph due to missing blank line separator. Add it. Signed-off-by: Bagas Sanjaya Reviewed-by: Randy Dunlap Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250814012046.21235-3-bagasdotme@gmail.com --- Documentation/dev-tools/ktap.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/dev-tools/ktap.rst b/Documentation/dev-tools/ktap.rst index 54fac3d3bf7b..a9810bed5fd4 100644 --- a/Documentation/dev-tools/ktap.rst +++ b/Documentation/dev-tools/ktap.rst @@ -20,6 +20,7 @@ machine-readable, whereas the diagnostic data is unstructured and is there to aid human debugging. KTAP output is built from four different types of lines: + - Version lines - Plan lines - Test case result lines @@ -38,6 +39,7 @@ All KTAP-formatted results begin with a "version line" which specifies which version of the (K)TAP standard the result is compliant with. For example: + - "KTAP version 1" - "TAP version 13" - "TAP version 14" @@ -276,6 +278,7 @@ Example KTAP output This output defines the following hierarchy: A single test called "main_test", which fails, and has three subtests: + - "example_test_1", which passes, and has one subtest: - "test_1", which passes, and outputs the diagnostic message "test_1: initializing test_1" From 126750523eac0ea79df672d9771eb483f7497b16 Mon Sep 17 00:00:00 2001 From: Mohammad Rafi Shaik Date: Fri, 15 Aug 2025 22:53:52 +0530 Subject: [PATCH 01207/11391] ASoC: dt-bindings: qcom,wsa8830: Add reset-gpios for shared line On Qualcomm platforms such as QCS6490-RB3Gen2, the WSA883x speaker amplifiers share the SD_N GPIO line between two speakers, thus requires coordinated control when asserting the GPIO. Linux supports shared GPIO handling via the "reset-gpios" property, which can be used to specify either the powerdown or reset GPIOs. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Mohammad Rafi Shaik Link: https://patch.msgid.link/20250815172353.2430981-2-mohammad.rafi.shaik@oss.qualcomm.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/qcom,wsa883x.yaml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml b/Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml index 14d312f9c345..098f1df62c8c 100644 --- a/Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml @@ -29,6 +29,10 @@ properties: description: GPIO spec for Powerdown/Shutdown line to use (pin SD_N) maxItems: 1 + reset-gpios: + description: Powerdown/Shutdown line to use (pin SD_N) + maxItems: 1 + vdd-supply: description: VDD Supply for the Codec @@ -50,10 +54,15 @@ required: - compatible - reg - vdd-supply - - powerdown-gpios - "#thermal-sensor-cells" - "#sound-dai-cells" +oneOf: + - required: + - powerdown-gpios + - required: + - reset-gpios + unevaluatedProperties: false examples: From cf65182247761f7993737b710afe8c781699356b Mon Sep 17 00:00:00 2001 From: Mohammad Rafi Shaik Date: Fri, 15 Aug 2025 22:53:53 +0530 Subject: [PATCH 01208/11391] ASoC: codecs: wsa883x: Handle shared reset GPIO for WSA883x speakers On some Qualcomm platforms such as QCS6490-RB3Gen2, the multiple WSA8830/WSA8835 speaker amplifiers share a common reset (shutdown) GPIO. To handle such scenario, use the reset controller framework and its "reset-gpio" driver to handle such case. This allows proper handling of all WSA883x speaker amplifiers on QCS6490-RB3Gen2 board. Signed-off-by: Mohammad Rafi Shaik Reviewed-by: Krzysztof Kozlowski Reviewed-by: Srinivas Kandagatla Link: https://patch.msgid.link/20250815172353.2430981-3-mohammad.rafi.shaik@oss.qualcomm.com Signed-off-by: Mark Brown --- sound/soc/codecs/wsa883x.c | 57 ++++++++++++++++++++++++++++++++------ 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c index 188363b03b93..ca4520ade79a 100644 --- a/sound/soc/codecs/wsa883x.c +++ b/sound/soc/codecs/wsa883x.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -468,6 +469,7 @@ struct wsa883x_priv { struct sdw_stream_runtime *sruntime; struct sdw_port_config port_config[WSA883X_MAX_SWR_PORTS]; struct gpio_desc *sd_n; + struct reset_control *sd_reset; bool port_prepared[WSA883X_MAX_SWR_PORTS]; bool port_enable[WSA883X_MAX_SWR_PORTS]; int active_ports; @@ -1546,6 +1548,46 @@ static const struct hwmon_chip_info wsa883x_hwmon_chip_info = { .info = wsa883x_hwmon_info, }; +static void wsa883x_reset_assert(void *data) +{ + struct wsa883x_priv *wsa883x = data; + + if (wsa883x->sd_reset) + reset_control_assert(wsa883x->sd_reset); + else + gpiod_direction_output(wsa883x->sd_n, 1); +} + +static void wsa883x_reset_deassert(struct wsa883x_priv *wsa883x) +{ + if (wsa883x->sd_reset) + reset_control_deassert(wsa883x->sd_reset); + else + gpiod_direction_output(wsa883x->sd_n, 0); +} + +static int wsa883x_get_reset(struct device *dev, struct wsa883x_priv *wsa883x) +{ + wsa883x->sd_reset = devm_reset_control_get_optional_shared(dev, NULL); + if (IS_ERR(wsa883x->sd_reset)) + return dev_err_probe(dev, PTR_ERR(wsa883x->sd_reset), + "Failed to get reset\n"); + /* + * if sd_reset: NULL, so use the backwards compatible way for powerdown-gpios, + * which does not handle sharing GPIO properly. + */ + if (!wsa883x->sd_reset) { + wsa883x->sd_n = devm_gpiod_get_optional(dev, "powerdown", + GPIOD_FLAGS_BIT_NONEXCLUSIVE | + GPIOD_OUT_HIGH); + if (IS_ERR(wsa883x->sd_n)) + return dev_err_probe(dev, PTR_ERR(wsa883x->sd_n), + "Shutdown Control GPIO not found\n"); + } + + return 0; +} + static int wsa883x_probe(struct sdw_slave *pdev, const struct sdw_device_id *id) { @@ -1566,13 +1608,9 @@ static int wsa883x_probe(struct sdw_slave *pdev, if (ret) return dev_err_probe(dev, ret, "Failed to enable vdd regulator\n"); - wsa883x->sd_n = devm_gpiod_get_optional(dev, "powerdown", - GPIOD_FLAGS_BIT_NONEXCLUSIVE | GPIOD_OUT_HIGH); - if (IS_ERR(wsa883x->sd_n)) { - ret = dev_err_probe(dev, PTR_ERR(wsa883x->sd_n), - "Shutdown Control GPIO not found\n"); + ret = wsa883x_get_reset(dev, wsa883x); + if (ret) goto err; - } dev_set_drvdata(dev, wsa883x); wsa883x->slave = pdev; @@ -1595,11 +1633,14 @@ static int wsa883x_probe(struct sdw_slave *pdev, pdev->prop.simple_clk_stop_capable = true; pdev->prop.sink_dpn_prop = wsa_sink_dpn_prop; pdev->prop.scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; - gpiod_direction_output(wsa883x->sd_n, 0); + + wsa883x_reset_deassert(wsa883x); + ret = devm_add_action_or_reset(dev, wsa883x_reset_assert, wsa883x); + if (ret) + return ret; wsa883x->regmap = devm_regmap_init_sdw(pdev, &wsa883x_regmap_config); if (IS_ERR(wsa883x->regmap)) { - gpiod_direction_output(wsa883x->sd_n, 1); ret = dev_err_probe(dev, PTR_ERR(wsa883x->regmap), "regmap_init failed\n"); goto err; From c676a536f6b5d4c423ff66a2aa27b6c4141e4895 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 13 Aug 2025 15:04:57 -0500 Subject: [PATCH 01209/11391] Documentation: Fix PCI typos Fix typos. Signed-off-by: Bjorn Helgaas Reviewed-by: Randy Dunlap Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250813200526.290420-2-helgaas@kernel.org --- Documentation/PCI/endpoint/pci-endpoint-cfs.rst | 4 ++-- Documentation/PCI/endpoint/pci-endpoint.rst | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/PCI/endpoint/pci-endpoint-cfs.rst b/Documentation/PCI/endpoint/pci-endpoint-cfs.rst index fb73345cfb8a..e69c2872ce3b 100644 --- a/Documentation/PCI/endpoint/pci-endpoint-cfs.rst +++ b/Documentation/PCI/endpoint/pci-endpoint-cfs.rst @@ -86,7 +86,7 @@ The directory can have a list of symbolic links be created by the user to represent the virtual functions that are bound to the physical function. In the above directory structure is a physical function and is a virtual function. An EPF device once -it's linked to another EPF device, cannot be linked to a EPC device. +it's linked to another EPF device, cannot be linked to an EPC device. EPC Device ========== @@ -108,7 +108,7 @@ entries corresponding to EPC device will be created by the EPC core. The directory will have a list of symbolic links to . These symbolic links should be created by the user to represent the functions present in the endpoint device. Only -that represents a physical function can be linked to a EPC device. +that represents a physical function can be linked to an EPC device. The directory will also have a *start* field. Once "1" is written to this field, the endpoint device will be ready to diff --git a/Documentation/PCI/endpoint/pci-endpoint.rst b/Documentation/PCI/endpoint/pci-endpoint.rst index 599763aa01ca..0741c8cbd74e 100644 --- a/Documentation/PCI/endpoint/pci-endpoint.rst +++ b/Documentation/PCI/endpoint/pci-endpoint.rst @@ -197,8 +197,8 @@ by the PCI endpoint function driver. * pci_epf_register_driver() The PCI Endpoint Function driver should implement the following ops: - * bind: ops to perform when a EPC device has been bound to EPF device - * unbind: ops to perform when a binding has been lost between a EPC + * bind: ops to perform when an EPC device has been bound to EPF device + * unbind: ops to perform when a binding has been lost between an EPC device and EPF device * add_cfs: optional ops to create function specific configfs attributes @@ -251,7 +251,7 @@ pci-ep-cfs.c can be used as reference for using these APIs. * pci_epf_bind() pci_epf_bind() should be invoked when the EPF device has been bound to - a EPC device. + an EPC device. * pci_epf_unbind() From aa7acf34c50b991702a0d052aa2b99b434e8a01c Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 13 Aug 2025 15:04:58 -0500 Subject: [PATCH 01210/11391] Documentation: Fix RCU typos Fix typos. Signed-off-by: Bjorn Helgaas Reviewed-by: Randy Dunlap Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250813200526.290420-3-helgaas@kernel.org --- Documentation/RCU/lockdep.rst | 2 +- Documentation/RCU/stallwarn.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/RCU/lockdep.rst b/Documentation/RCU/lockdep.rst index 69e73a39bd11..741b157bbacb 100644 --- a/Documentation/RCU/lockdep.rst +++ b/Documentation/RCU/lockdep.rst @@ -106,7 +106,7 @@ or the RCU-protected data that it points to can change concurrently. Like rcu_dereference(), when lockdep is enabled, RCU list and hlist traversal primitives check for being called from within an RCU read-side critical section. However, a lockdep expression can be passed to them -as a additional optional argument. With this lockdep expression, these +as an additional optional argument. With this lockdep expression, these traversal primitives will complain only if the lockdep expression is false and they are called from outside any RCU read-side critical section. diff --git a/Documentation/RCU/stallwarn.rst b/Documentation/RCU/stallwarn.rst index d1ccd6039a8c..d7c8eff63317 100644 --- a/Documentation/RCU/stallwarn.rst +++ b/Documentation/RCU/stallwarn.rst @@ -119,7 +119,7 @@ warnings: uncommon in large datacenter. In one memorable case some decades back, a CPU failed in a running system, becoming unresponsive, but not causing an immediate crash. This resulted in a series - of RCU CPU stall warnings, eventually leading the realization + of RCU CPU stall warnings, eventually leading to the realization that the CPU had failed. The RCU, RCU-sched, RCU-tasks, and RCU-tasks-trace implementations have From c349216707362a8c2376995296cb55604d4c0ee9 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 13 Aug 2025 15:04:59 -0500 Subject: [PATCH 01211/11391] Documentation: Fix admin-guide typos Fix typos. Signed-off-by: Bjorn Helgaas Reviewed-by: Randy Dunlap Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250813200526.290420-4-helgaas@kernel.org --- Documentation/admin-guide/LSM/SafeSetID.rst | 2 +- Documentation/admin-guide/RAS/main.rst | 2 +- Documentation/admin-guide/blockdev/paride.rst | 2 +- .../admin-guide/device-mapper/vdo-design.rst | 2 +- Documentation/admin-guide/hw-vuln/mds.rst | 2 +- Documentation/admin-guide/kdump/kdump.rst | 2 +- Documentation/admin-guide/kernel-parameters.txt | 12 ++++++------ Documentation/admin-guide/laptops/sonypi.rst | 2 +- Documentation/admin-guide/media/imx.rst | 2 +- Documentation/admin-guide/media/si4713.rst | 6 +++--- Documentation/admin-guide/mm/damon/usage.rst | 2 +- Documentation/admin-guide/perf/hisi-pmu.rst | 4 ++-- .../admin-guide/quickly-build-trimmed-linux.rst | 4 ++-- Documentation/admin-guide/reporting-issues.rst | 4 ++-- .../verify-bugs-and-bisect-regressions.rst | 2 +- 15 files changed, 25 insertions(+), 25 deletions(-) diff --git a/Documentation/admin-guide/LSM/SafeSetID.rst b/Documentation/admin-guide/LSM/SafeSetID.rst index 0ec34863c674..6d439c987563 100644 --- a/Documentation/admin-guide/LSM/SafeSetID.rst +++ b/Documentation/admin-guide/LSM/SafeSetID.rst @@ -41,7 +41,7 @@ namespace). The higher level goal is to allow for uid-based sandboxing of system services without having to give out CAP_SETUID all over the place just so that non-root programs can drop to even-lesser-privileged uids. This is especially relevant when one non-root daemon on the system should be allowed to spawn other -processes as different uids, but its undesirable to give the daemon a +processes as different uids, but it's undesirable to give the daemon a basically-root-equivalent CAP_SETUID. diff --git a/Documentation/admin-guide/RAS/main.rst b/Documentation/admin-guide/RAS/main.rst index 7ac1d4ccc509..447bfde509fb 100644 --- a/Documentation/admin-guide/RAS/main.rst +++ b/Documentation/admin-guide/RAS/main.rst @@ -253,7 +253,7 @@ interface. Some architectures have ECC detectors for L1, L2 and L3 caches, along with DMA engines, fabric switches, main data path switches, interconnections, and various other hardware data paths. If the hardware -reports it, then a edac_device device probably can be constructed to +reports it, then an edac_device device probably can be constructed to harvest and present that to userspace. diff --git a/Documentation/admin-guide/blockdev/paride.rst b/Documentation/admin-guide/blockdev/paride.rst index e85ad37cc0e5..b2f627d4c2f8 100644 --- a/Documentation/admin-guide/blockdev/paride.rst +++ b/Documentation/admin-guide/blockdev/paride.rst @@ -118,7 +118,7 @@ and high-level drivers that you would use: ================ ============ ======== All parports and all protocol drivers are probed automatically unless probe=0 -parameter is used. So just "modprobe epat" is enough for a Imation SuperDisk +parameter is used. So just "modprobe epat" is enough for an Imation SuperDisk drive to work. Manual device creation:: diff --git a/Documentation/admin-guide/device-mapper/vdo-design.rst b/Documentation/admin-guide/device-mapper/vdo-design.rst index 3cd59decbec0..faa0ecd4a5ae 100644 --- a/Documentation/admin-guide/device-mapper/vdo-design.rst +++ b/Documentation/admin-guide/device-mapper/vdo-design.rst @@ -600,7 +600,7 @@ lock and return itself to the pool. All storage within vdo is managed as 4KB blocks, but it can accept writes as small as 512 bytes. Processing a write that is smaller than 4K requires a read-modify-write operation that reads the relevant 4K block, copies the -new data over the approriate sectors of the block, and then launches a +new data over the appropriate sectors of the block, and then launches a write operation for the modified data block. The read and write stages of this operation are nearly identical to the normal read and write operations, and a single data_vio is used throughout this operation. diff --git a/Documentation/admin-guide/hw-vuln/mds.rst b/Documentation/admin-guide/hw-vuln/mds.rst index 48c7b0b72aed..754679db0ce8 100644 --- a/Documentation/admin-guide/hw-vuln/mds.rst +++ b/Documentation/admin-guide/hw-vuln/mds.rst @@ -214,7 +214,7 @@ XEON PHI specific considerations command line with the 'ring3mwait=disable' command line option. XEON PHI is not affected by the other MDS variants and MSBDS is mitigated - before the CPU enters a idle state. As XEON PHI is not affected by L1TF + before the CPU enters an idle state. As XEON PHI is not affected by L1TF either disabling SMT is not required for full protection. .. _mds_smt_control: diff --git a/Documentation/admin-guide/kdump/kdump.rst b/Documentation/admin-guide/kdump/kdump.rst index 9c6cd52f69cf..7b011eb116a7 100644 --- a/Documentation/admin-guide/kdump/kdump.rst +++ b/Documentation/admin-guide/kdump/kdump.rst @@ -471,7 +471,7 @@ Notes on loading the dump-capture kernel: performance degradation. To enable multi-cpu support, you should bring up an SMP dump-capture kernel and specify maxcpus/nr_cpus options while loading it. -* For s390x there are two kdump modes: If a ELF header is specified with +* For s390x there are two kdump modes: If an ELF header is specified with the elfcorehdr= kernel parameter, it is used by the kdump kernel as it is done on all other architectures. If no elfcorehdr= kernel parameter is specified, the s390x kdump kernel dynamically creates the header. The diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 747a55abf494..d4a91dec20b8 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3700,7 +3700,7 @@ looking for corruption. Enabling this will both detect corruption and prevent the kernel from using the memory being corrupted. - However, its intended as a diagnostic tool; if + However, it's intended as a diagnostic tool; if repeatable BIOS-originated corruption always affects the same memory, you can use memmap= to prevent the kernel from using that memory. @@ -7382,7 +7382,7 @@ (converted into nanoseconds). Fast, but depending on the architecture, may not be in sync between CPUs. - global - Event time stamps are synchronize across + global - Event time stamps are synchronized across CPUs. May be slower than the local clock, but better for some race conditions. counter - Simple counting of events (1, 2, ..) @@ -7502,12 +7502,12 @@ section. trace_trigger=[trigger-list] - [FTRACE] Add a event trigger on specific events. + [FTRACE] Add an event trigger on specific events. Set a trigger on top of a specific event, with an optional filter. - The format is is "trace_trigger=.[ if ],..." - Where more than one trigger may be specified that are comma deliminated. + The format is "trace_trigger=.[ if ],..." + Where more than one trigger may be specified that are comma delimited. For example: @@ -7515,7 +7515,7 @@ The above will enable the "stacktrace" trigger on the "sched_switch" event but only trigger it if the "prev_state" of the "sched_switch" - event is "2" (TASK_UNINTERUPTIBLE). + event is "2" (TASK_UNINTERRUPTIBLE). See also "Event triggers" in Documentation/trace/events.rst diff --git a/Documentation/admin-guide/laptops/sonypi.rst b/Documentation/admin-guide/laptops/sonypi.rst index 190da1234314..7541f56e0007 100644 --- a/Documentation/admin-guide/laptops/sonypi.rst +++ b/Documentation/admin-guide/laptops/sonypi.rst @@ -25,7 +25,7 @@ generate, like: (when available) Those events (see linux/sonypi.h) can be polled using the character device node -/dev/sonypi (major 10, minor auto allocated or specified as a option). +/dev/sonypi (major 10, minor auto allocated or specified as an option). A simple daemon which translates the jogdial movements into mouse wheel events can be downloaded at: diff --git a/Documentation/admin-guide/media/imx.rst b/Documentation/admin-guide/media/imx.rst index b8fa70f854fd..bb68100d8acb 100644 --- a/Documentation/admin-guide/media/imx.rst +++ b/Documentation/admin-guide/media/imx.rst @@ -96,7 +96,7 @@ Some of the features of this driver include: motion compensation modes: low, medium, and high motion. Pipelines are defined that allow sending frames to the VDIC subdev directly from the CSI. There is also support in the future for sending frames to the - VDIC from memory buffers via a output/mem2mem devices. + VDIC from memory buffers via output/mem2mem devices. - Includes a Frame Interval Monitor (FIM) that can correct vertical sync problems with the ADV718x video decoders. diff --git a/Documentation/admin-guide/media/si4713.rst b/Documentation/admin-guide/media/si4713.rst index be8e6b49b7b4..85dcf1cd2df8 100644 --- a/Documentation/admin-guide/media/si4713.rst +++ b/Documentation/admin-guide/media/si4713.rst @@ -13,7 +13,7 @@ Contact: Eduardo Valentin Information about the Device ---------------------------- -This chip is a Silicon Labs product. It is a I2C device, currently on 0x63 address. +This chip is a Silicon Labs product. It is an I2C device, currently on 0x63 address. Basically, it has transmission and signal noise level measurement features. The Si4713 integrates transmit functions for FM broadcast stereo transmission. @@ -28,7 +28,7 @@ Users must comply with local regulations on radio frequency (RF) transmission. Device driver description ------------------------- -There are two modules to handle this device. One is a I2C device driver +There are two modules to handle this device. One is an I2C device driver and the other is a platform driver. The I2C device driver exports a v4l2-subdev interface to the kernel. @@ -113,7 +113,7 @@ Here is a summary of them: - acomp_attack_time - Sets the attack time for audio dynamic range control. - acomp_release_time - Sets the release time for audio dynamic range control. -* Limiter setups audio deviation limiter feature. Once a over deviation occurs, +* Limiter sets up the audio deviation limiter feature. Once an over deviation occurs, it is possible to adjust the front-end gain of the audio input and always prevent over deviation. diff --git a/Documentation/admin-guide/mm/damon/usage.rst b/Documentation/admin-guide/mm/damon/usage.rst index ff3a2dda1f02..5cd42d428c89 100644 --- a/Documentation/admin-guide/mm/damon/usage.rst +++ b/Documentation/admin-guide/mm/damon/usage.rst @@ -357,7 +357,7 @@ The directory for the :ref:`quotas ` of the given DAMON-based operation scheme. Under ``quotas`` directory, four files (``ms``, ``bytes``, -``reset_interval_ms``, ``effective_bytes``) and two directores (``weights`` and +``reset_interval_ms``, ``effective_bytes``) and two directories (``weights`` and ``goals``) exist. You can set the ``time quota`` in milliseconds, ``size quota`` in bytes, and diff --git a/Documentation/admin-guide/perf/hisi-pmu.rst b/Documentation/admin-guide/perf/hisi-pmu.rst index 48992a0b8e94..721eb1623ca7 100644 --- a/Documentation/admin-guide/perf/hisi-pmu.rst +++ b/Documentation/admin-guide/perf/hisi-pmu.rst @@ -109,8 +109,8 @@ uring channel. It is 2 bits. Some important codes are as follows: - 2'b11: count the events which sent to the uring_ext (MATA) channel; - 2'b01: is the same as 2'b11; - 2'b10: count the events which sent to the uring (non-MATA) channel; -- 2'b00: default value, count the events which sent to the both uring and - uring_ext channel; +- 2'b00: default value, count the events which sent to both uring and + uring_ext channels; Users could configure IDs to count data come from specific CCL/ICL, by setting srcid_cmd & srcid_msk, and data desitined for specific CCL/ICL by setting diff --git a/Documentation/admin-guide/quickly-build-trimmed-linux.rst b/Documentation/admin-guide/quickly-build-trimmed-linux.rst index 4a5ffb0996a3..cb4b78468a93 100644 --- a/Documentation/admin-guide/quickly-build-trimmed-linux.rst +++ b/Documentation/admin-guide/quickly-build-trimmed-linux.rst @@ -273,7 +273,7 @@ again. does nothing at all; in that case you have to manually install your kernel, as outlined in the reference section. - If you are running a immutable Linux distribution, check its documentation + If you are running an immutable Linux distribution, check its documentation and the web to find out how to install your own kernel there. [:ref:`details`] @@ -884,7 +884,7 @@ When a build error occurs, it might be caused by some aspect of your machine's setup that often can be fixed quickly; other times though the problem lies in the code and can only be fixed by a developer. A close examination of the failure messages coupled with some research on the internet will often tell you -which of the two it is. To perform such a investigation, restart the build +which of the two it is. To perform such an investigation, restart the build process like this:: make V=1 diff --git a/Documentation/admin-guide/reporting-issues.rst b/Documentation/admin-guide/reporting-issues.rst index 9a847506f6ec..a68e6d909274 100644 --- a/Documentation/admin-guide/reporting-issues.rst +++ b/Documentation/admin-guide/reporting-issues.rst @@ -611,7 +611,7 @@ better place. How to read the MAINTAINERS file ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -To illustrate how to use the :ref:`MAINTAINERS ` file, lets assume +To illustrate how to use the :ref:`MAINTAINERS ` file, let's assume the WiFi in your Laptop suddenly misbehaves after updating the kernel. In that case it's likely an issue in the WiFi driver. Obviously it could also be some code it builds upon, but unless you suspect something like that stick to the @@ -1543,7 +1543,7 @@ as well, because that will speed things up. And note, it helps developers a great deal if you can specify the exact version that introduced the problem. Hence if possible within a reasonable time frame, -try to find that version using vanilla kernels. Lets assume something broke when +try to find that version using vanilla kernels. Let's assume something broke when your distributor released a update from Linux kernel 5.10.5 to 5.10.8. Then as instructed above go and check the latest kernel from that version line, say 5.10.9. If it shows the problem, try a vanilla 5.10.5 to ensure that no patches diff --git a/Documentation/admin-guide/verify-bugs-and-bisect-regressions.rst b/Documentation/admin-guide/verify-bugs-and-bisect-regressions.rst index d8946b084b1e..d83601f2a459 100644 --- a/Documentation/admin-guide/verify-bugs-and-bisect-regressions.rst +++ b/Documentation/admin-guide/verify-bugs-and-bisect-regressions.rst @@ -1757,7 +1757,7 @@ or all of these tasks: to your bootloader's configuration. You have to take care of some or all of the tasks yourself, if your -distribution lacks a installkernel script or does only handle part of them. +distribution lacks an installkernel script or does only handle part of them. Consult the distribution's documentation for details. If in doubt, install the kernel manually:: From 8900f9ad90c05d0c44a21786cfef08061230f5b7 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 13 Aug 2025 15:05:00 -0500 Subject: [PATCH 01212/11391] Documentation: Fix core-api typos Fix typos. Signed-off-by: Bjorn Helgaas Reviewed-by: Randy Dunlap Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250813200526.290420-5-helgaas@kernel.org --- Documentation/core-api/irq/irq-affinity.rst | 6 ++-- Documentation/core-api/irq/irq-domain.rst | 38 ++++++++++----------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Documentation/core-api/irq/irq-affinity.rst b/Documentation/core-api/irq/irq-affinity.rst index 29da5000836a..9cb460cf60b6 100644 --- a/Documentation/core-api/irq/irq-affinity.rst +++ b/Documentation/core-api/irq/irq-affinity.rst @@ -9,9 +9,9 @@ ChangeLog: /proc/irq/IRQ#/smp_affinity and /proc/irq/IRQ#/smp_affinity_list specify which target CPUs are permitted for a given IRQ source. It's a bitmask -(smp_affinity) or cpu list (smp_affinity_list) of allowed CPUs. It's not +(smp_affinity) or CPU list (smp_affinity_list) of allowed CPUs. It's not allowed to turn off all CPUs, and if an IRQ controller does not support -IRQ affinity then the value will not change from the default of all cpus. +IRQ affinity then the value will not change from the default of all CPUs. /proc/irq/default_smp_affinity specifies default affinity mask that applies to all non-active IRQs. Once IRQ is allocated/activated its affinity bitmask @@ -60,7 +60,7 @@ Now lets restrict that IRQ to CPU(4-7). This time around IRQ44 was delivered only to the last four processors. i.e counters for the CPU0-3 did not change. -Here is an example of limiting that same irq (44) to cpus 1024 to 1031:: +Here is an example of limiting that same IRQ (44) to CPUs 1024 to 1031:: [root@moon 44]# echo 1024-1031 > smp_affinity_list [root@moon 44]# cat smp_affinity_list diff --git a/Documentation/core-api/irq/irq-domain.rst b/Documentation/core-api/irq/irq-domain.rst index a01c6ead1bc0..68eb2612e8a4 100644 --- a/Documentation/core-api/irq/irq-domain.rst +++ b/Documentation/core-api/irq/irq-domain.rst @@ -18,8 +18,8 @@ handlers as irqchips. I.e. in effect cascading interrupt controllers. So in the past, IRQ numbers could be chosen so that they match the hardware IRQ line into the root interrupt controller (i.e. the component actually firing the interrupt line to the CPU). Nowadays, -this number is just a number and the number loose all kind of -correspondence to hardware interrupt numbers. +this number is just a number and the number has no +relationship to hardware interrupt numbers. For this reason, we need a mechanism to separate controller-local interrupt numbers, called hardware IRQs, from Linux IRQ numbers. @@ -77,15 +77,15 @@ Once a mapping has been established, it can be retrieved or used via a variety of methods: - irq_resolve_mapping() returns a pointer to the irq_desc structure - for a given domain and hwirq number, and NULL if there was no + for a given domain and hwirq number, or NULL if there was no mapping. - irq_find_mapping() returns a Linux IRQ number for a given domain and - hwirq number, and 0 if there was no mapping + hwirq number, or 0 if there was no mapping - generic_handle_domain_irq() handles an interrupt described by a domain and a hwirq number -Note that irq domain lookups must happen in contexts that are -compatible with a RCU read-side critical section. +Note that irq_domain lookups must happen in contexts that are +compatible with an RCU read-side critical section. The irq_create_mapping() function must be called *at least once* before any call to irq_find_mapping(), lest the descriptor will not @@ -100,7 +100,7 @@ Types of irq_domain Mappings ============================ There are several mechanisms available for reverse mapping from hwirq -to Linux irq, and each mechanism uses a different allocation function. +to Linux IRQ, and each mechanism uses a different allocation function. Which reverse map type should be used depends on the use case. Each of the reverse map types are described below: @@ -111,13 +111,13 @@ Linear irq_domain_create_linear() -The linear reverse map maintains a fixed size table indexed by the +The linear reverse map maintains a fixed-size table indexed by the hwirq number. When a hwirq is mapped, an irq_desc is allocated for the hwirq, and the IRQ number is stored in the table. The Linear map is a good choice when the maximum number of hwirqs is fixed and a relatively small number (~ < 256). The advantages of this -map are fixed time lookup for IRQ numbers, and irq_descs are only +map are fixed-time lookup for IRQ numbers, and irq_descs are only allocated for in-use IRQs. The disadvantage is that the table must be as large as the largest possible hwirq number. @@ -134,7 +134,7 @@ The irq_domain maintains a radix tree map from hwirq numbers to Linux IRQs. When an hwirq is mapped, an irq_desc is allocated and the hwirq is used as the lookup key for the radix tree. -The tree map is a good choice if the hwirq number can be very large +The Tree map is a good choice if the hwirq number can be very large since it doesn't need to allocate a table as large as the largest hwirq number. The disadvantage is that hwirq to IRQ number lookup is dependent on how many entries are in the table. @@ -169,10 +169,10 @@ Legacy The Legacy mapping is a special case for drivers that already have a range of irq_descs allocated for the hwirqs. It is used when the -driver cannot be immediately converted to use the linear mapping. For +driver cannot be immediately converted to use the Linear mapping. For example, many embedded system board support files use a set of #defines for IRQ numbers that are passed to struct device registrations. In that -case the Linux IRQ numbers cannot be dynamically assigned and the legacy +case the Linux IRQ numbers cannot be dynamically assigned and the Legacy mapping should be used. As the name implies, the \*_legacy() functions are deprecated and only @@ -180,15 +180,15 @@ exist to ease the support of ancient platforms. No new users should be added. Same goes for the \*_simple() functions when their use results in the legacy behaviour. -The legacy map assumes a contiguous range of IRQ numbers has already +The Legacy map assumes a contiguous range of IRQ numbers has already been allocated for the controller and that the IRQ number can be calculated by adding a fixed offset to the hwirq number, and visa-versa. The disadvantage is that it requires the interrupt controller to manage IRQ allocations and it requires an irq_desc to be allocated for every hwirq, even if it is unused. -The legacy map should only be used if fixed IRQ mappings must be -supported. For example, ISA controllers would use the legacy map for +The Legacy map should only be used if fixed IRQ mappings must be +supported. For example, ISA controllers would use the Legacy map for mapping Linux IRQs 0-15 so that existing ISA drivers get the correct IRQ numbers. @@ -197,7 +197,7 @@ which will use a legacy domain only if an IRQ range is supplied by the system and will otherwise use a linear domain mapping. The semantics of this call are such that if an IRQ range is specified then descriptors will be allocated on-the-fly for it, and if no range is specified it -will fall through to irq_domain_create_linear() which means *no* irq +will fall through to irq_domain_create_linear() which means *no* IRQ descriptors will be allocated. A typical use case for simple domains is where an irqchip provider @@ -214,7 +214,7 @@ Hierarchy IRQ Domain On some architectures, there may be multiple interrupt controllers involved in delivering an interrupt from the device to the target CPU. -Let's look at a typical interrupt delivering path on x86 platforms:: +Let's look at a typical interrupt delivery path on x86 platforms:: Device --> IOAPIC -> Interrupt remapping Controller -> Local APIC -> CPU @@ -227,8 +227,8 @@ There are three interrupt controllers involved: To support such a hardware topology and make software architecture match hardware architecture, an irq_domain data structure is built for each interrupt controller and those irq_domains are organized into hierarchy. -When building irq_domain hierarchy, the irq_domain near to the device is -child and the irq_domain near to CPU is parent. So a hierarchy structure +When building irq_domain hierarchy, the irq_domain nearest the device is +child and the irq_domain nearest the CPU is parent. So a hierarchy structure as below will be built for the example above:: CPU Vector irq_domain (root irq_domain to manage CPU vectors) From 81fd803b5a5da3fad0140163091e12b3ac2ae484 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 13 Aug 2025 15:05:01 -0500 Subject: [PATCH 01213/11391] Documentation: Fix filesystems typos Fix typos. Signed-off-by: Bjorn Helgaas Reviewed-by: Randy Dunlap Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250813200526.290420-6-helgaas@kernel.org --- Documentation/filesystems/erofs.rst | 2 +- Documentation/filesystems/gfs2-glocks.rst | 2 +- Documentation/filesystems/hpfs.rst | 2 +- Documentation/filesystems/resctrl.rst | 2 +- Documentation/filesystems/xfs/xfs-online-fsck-design.rst | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Documentation/filesystems/erofs.rst b/Documentation/filesystems/erofs.rst index 7ddb235aee9d..08194f194b94 100644 --- a/Documentation/filesystems/erofs.rst +++ b/Documentation/filesystems/erofs.rst @@ -116,7 +116,7 @@ cache_strategy=%s Select a strategy for cached decompression from now on: cluster for further reading. It still does in-place I/O decompression for the rest compressed physical clusters; - readaround Cache the both ends of incomplete compressed + readaround Cache both ends of incomplete compressed physical clusters for further reading. It still does in-place I/O decompression for the rest compressed physical clusters. diff --git a/Documentation/filesystems/gfs2-glocks.rst b/Documentation/filesystems/gfs2-glocks.rst index adc0d4c4d979..ce5ff08cbd59 100644 --- a/Documentation/filesystems/gfs2-glocks.rst +++ b/Documentation/filesystems/gfs2-glocks.rst @@ -105,7 +105,7 @@ go_unlocked Yes No Operations must not drop either the bit lock or the spinlock if its held on entry. go_dump and do_demote_ok must never block. Note that go_dump will only be called if the glock's state - indicates that it is caching uptodate data. + indicates that it is caching up-to-date data. Glock locking order within GFS2: diff --git a/Documentation/filesystems/hpfs.rst b/Documentation/filesystems/hpfs.rst index 7e0dd2f4373e..0f9516b5eb07 100644 --- a/Documentation/filesystems/hpfs.rst +++ b/Documentation/filesystems/hpfs.rst @@ -65,7 +65,7 @@ are case sensitive, so for example when you create a file FOO, you can use 'cat FOO', 'cat Foo', 'cat foo' or 'cat F*' but not 'cat f*'. Note, that you also won't be able to compile linux kernel (and maybe other things) on HPFS because kernel creates different files with names like bootsect.S and -bootsect.s. When searching for file thats name has characters >= 128, codepages +bootsect.s. When searching for file whose name has characters >= 128, codepages are used - see below. OS/2 ignores dots and spaces at the end of file name, so this driver does as well. If you create 'a. ...', the file 'a' will be created, but you can still diff --git a/Documentation/filesystems/resctrl.rst b/Documentation/filesystems/resctrl.rst index c7949dd44f2f..4db3b07c16c5 100644 --- a/Documentation/filesystems/resctrl.rst +++ b/Documentation/filesystems/resctrl.rst @@ -563,7 +563,7 @@ this would be dependent on number of cores the benchmark is run on. depending on # of threads: For the same SKU in #1, a 'single thread, with 10% bandwidth' and '4 -thread, with 10% bandwidth' can consume upto 10GBps and 40GBps although +thread, with 10% bandwidth' can consume up to 10GBps and 40GBps although they have same percentage bandwidth of 10%. This is simply because as threads start using more cores in an rdtgroup, the actual bandwidth may increase or vary although user specified bandwidth percentage is same. diff --git a/Documentation/filesystems/xfs/xfs-online-fsck-design.rst b/Documentation/filesystems/xfs/xfs-online-fsck-design.rst index e231d127cd40..9fe994353395 100644 --- a/Documentation/filesystems/xfs/xfs-online-fsck-design.rst +++ b/Documentation/filesystems/xfs/xfs-online-fsck-design.rst @@ -454,7 +454,7 @@ filesystem so that it can apply pending filesystem updates to the staging information. Once the scan is done, the owning object is re-locked, the live data is used to write a new ondisk structure, and the repairs are committed atomically. -The hooks are disabled and the staging staging area is freed. +The hooks are disabled and the staging area is freed. Finally, the storage from the old data structure are carefully reaped. Introducing concurrency helps online repair avoid various locking problems, but @@ -2185,7 +2185,7 @@ The chapter about :ref:`secondary metadata` mentioned that checking and repairing of secondary metadata commonly requires coordination between a live metadata scan of the filesystem and writer threads that are updating that metadata. -Keeping the scan data up to date requires requires the ability to propagate +Keeping the scan data up to date requires the ability to propagate metadata updates from the filesystem into the data being collected by the scan. This *can* be done by appending concurrent updates into a separate log file and applying them before writing the new metadata to disk, but this leads to From e855d7e5e2e9ed311930d557f7ed033e200fcdef Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 13 Aug 2025 15:05:02 -0500 Subject: [PATCH 01214/11391] Documentation: Fix networking typos Fix typos. Signed-off-by: Bjorn Helgaas Reviewed-by: Randy Dunlap Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250813200526.290420-7-helgaas@kernel.org --- Documentation/networking/can.rst | 2 +- .../device_drivers/ethernet/ti/am65_nuss_cpsw_switchdev.rst | 2 +- .../networking/device_drivers/ethernet/ti/cpsw_switchdev.rst | 2 +- Documentation/networking/rds.rst | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/networking/can.rst b/Documentation/networking/can.rst index bc1b585355f7..680dc7451493 100644 --- a/Documentation/networking/can.rst +++ b/Documentation/networking/can.rst @@ -539,7 +539,7 @@ CAN Filter Usage Optimisation The CAN filters are processed in per-device filter lists at CAN frame reception time. To reduce the number of checks that need to be performed while walking through the filter lists the CAN core provides an optimized -filter handling when the filter subscription focusses on a single CAN ID. +filter handling when the filter subscription focuses on a single CAN ID. For the possible 2048 SFF CAN identifiers the identifier is used as an index to access the corresponding subscription list without any further checks. diff --git a/Documentation/networking/device_drivers/ethernet/ti/am65_nuss_cpsw_switchdev.rst b/Documentation/networking/device_drivers/ethernet/ti/am65_nuss_cpsw_switchdev.rst index 25fd9aa284e2..f0424597aac1 100644 --- a/Documentation/networking/device_drivers/ethernet/ti/am65_nuss_cpsw_switchdev.rst +++ b/Documentation/networking/device_drivers/ethernet/ti/am65_nuss_cpsw_switchdev.rst @@ -42,7 +42,7 @@ Port's netdev devices have to be in UP before joining to the bridge to avoid overwriting of bridge configuration as CPSW switch driver completely reloads its configuration when first port changes its state to UP. -When the both interfaces joined the bridge - CPSW switch driver will enable +When both interfaces have joined the bridge - CPSW switch driver will enable marking packets with offload_fwd_mark flag. All configuration is implemented via switchdev API. diff --git a/Documentation/networking/device_drivers/ethernet/ti/cpsw_switchdev.rst b/Documentation/networking/device_drivers/ethernet/ti/cpsw_switchdev.rst index 464dce938ed1..2f3c43a32bfc 100644 --- a/Documentation/networking/device_drivers/ethernet/ti/cpsw_switchdev.rst +++ b/Documentation/networking/device_drivers/ethernet/ti/cpsw_switchdev.rst @@ -92,7 +92,7 @@ Port's netdev devices have to be in UP before joining to the bridge to avoid overwriting of bridge configuration as CPSW switch driver copletly reloads its configuration when first Port changes its state to UP. -When the both interfaces joined the bridge - CPSW switch driver will enable +When both interfaces have joined the bridge - CPSW switch driver will enable marking packets with offload_fwd_mark flag unless "ale_bypass=0" All configuration is implemented via switchdev API. diff --git a/Documentation/networking/rds.rst b/Documentation/networking/rds.rst index 41b0a6182fe4..4261146e9d92 100644 --- a/Documentation/networking/rds.rst +++ b/Documentation/networking/rds.rst @@ -339,7 +339,7 @@ The send path rds_sendmsg() - struct rds_message built from incoming data - CMSGs parsed (e.g. RDMA ops) - - transport connection alloced and connected if not already + - transport connection allocated and connected if not already - rds_message placed on send queue - send worker awoken From 3dae66aec6b0bd847e5056fb5174dfc325162734 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 13 Aug 2025 15:05:03 -0500 Subject: [PATCH 01215/11391] Documentation: Fix power typos Fix typos. Signed-off-by: Bjorn Helgaas Reviewed-by: Randy Dunlap Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250813200526.290420-8-helgaas@kernel.org --- Documentation/power/pci.rst | 4 ++-- Documentation/power/suspend-and-cpuhotplug.rst | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/power/pci.rst b/Documentation/power/pci.rst index 9ebecb7b00b2..38e614d92a4a 100644 --- a/Documentation/power/pci.rst +++ b/Documentation/power/pci.rst @@ -472,7 +472,7 @@ in the device tree from the root bridge to a leaf device contains both of them). The pci_pm_suspend_noirq() routine is executed after suspend_device_irqs() has been called, which means that the device driver's interrupt handler won't be invoked while this routine is running. It first checks if the device's driver -implements legacy PCI suspends routines (Section 3), in which case the legacy +implements legacy PCI suspend routines (Section 3), in which case the legacy late suspend routine is called and its result is returned (the standard configuration registers of the device are saved if the driver's callback hasn't done that). Second, if the device driver's struct dev_pm_ops object is not @@ -544,7 +544,7 @@ result is then returned). The resume phase is carried out asynchronously for PCI devices, like the suspend phase described above, which means that if two PCI devices don't depend on each other in a known way, the pci_pm_resume() routine may be executed for -the both of them in parallel. +both of them in parallel. The pci_pm_complete() routine only executes the device driver's pm->complete() callback, if defined. diff --git a/Documentation/power/suspend-and-cpuhotplug.rst b/Documentation/power/suspend-and-cpuhotplug.rst index ebedb6c75db9..641d09a6546b 100644 --- a/Documentation/power/suspend-and-cpuhotplug.rst +++ b/Documentation/power/suspend-and-cpuhotplug.rst @@ -13,7 +13,7 @@ infrastructure uses it internally? And where do they share common code? Well, a picture is worth a thousand words... So ASCII art follows :-) -[This depicts the current design in the kernel, and focusses only on the +[This depicts the current design in the kernel, and focuses only on the interactions involving the freezer and CPU hotplug and also tries to explain the locking involved. It outlines the notifications involved as well. But please note that here, only the call paths are illustrated, with the aim From 29fe206065f3784397252c7f6aa28dc6d413fb94 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 13 Aug 2025 15:05:04 -0500 Subject: [PATCH 01216/11391] Documentation: Fix trace typos Fix typos. Signed-off-by: Bjorn Helgaas Reviewed-by: Randy Dunlap Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250813200526.290420-9-helgaas@kernel.org --- Documentation/trace/fprobe.rst | 2 +- Documentation/trace/ftrace-uses.rst | 2 +- Documentation/trace/ftrace.rst | 14 +++++++------- Documentation/trace/histogram.rst | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Documentation/trace/fprobe.rst b/Documentation/trace/fprobe.rst index 71cd40472d36..06b0edad0179 100644 --- a/Documentation/trace/fprobe.rst +++ b/Documentation/trace/fprobe.rst @@ -81,7 +81,7 @@ Same as ftrace, the registered callbacks will start being called some time after the register_fprobe() is called and before it returns. See :file:`Documentation/trace/ftrace.rst`. -Also, the unregister_fprobe() will guarantee that the both enter and exit +Also, the unregister_fprobe() will guarantee that both enter and exit handlers are no longer being called by functions after unregister_fprobe() returns as same as unregister_ftrace_function(). diff --git a/Documentation/trace/ftrace-uses.rst b/Documentation/trace/ftrace-uses.rst index e198854ace79..e225cc46b71e 100644 --- a/Documentation/trace/ftrace-uses.rst +++ b/Documentation/trace/ftrace-uses.rst @@ -193,7 +193,7 @@ FTRACE_OPS_FL_RECURSION Note, if this flag is set, then the callback will always be called with preemption disabled. If it is not set, then it is possible (but not guaranteed) that the callback will be called in - preemptable context. + preemptible context. FTRACE_OPS_FL_IPMODIFY Requires FTRACE_OPS_FL_SAVE_REGS set. If the callback is to "hijack" diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst index af66a05e18cc..aef674df3afd 100644 --- a/Documentation/trace/ftrace.rst +++ b/Documentation/trace/ftrace.rst @@ -30,7 +30,7 @@ disabled and enabled, as well as for preemption and from a time a task is woken to the task is actually scheduled in. One of the most common uses of ftrace is the event tracing. -Throughout the kernel is hundreds of static event points that +Throughout the kernel are hundreds of static event points that can be enabled via the tracefs file system to see what is going on in certain parts of the kernel. @@ -383,7 +383,7 @@ of ftrace. Here is a list of some of the key files: not be listed in this count. If the callback registered to be traced by a function with - the "save regs" attribute (thus even more overhead), a 'R' + the "save regs" attribute (thus even more overhead), an 'R' will be displayed on the same line as the function that is returning registers. @@ -392,7 +392,7 @@ of ftrace. Here is a list of some of the key files: an 'I' will be displayed on the same line as the function that can be overridden. - If a non ftrace trampoline is attached (BPF) a 'D' will be displayed. + If a non-ftrace trampoline is attached (BPF) a 'D' will be displayed. Note, normal ftrace trampolines can also be attached, but only one "direct" trampoline can be attached to a given function at a time. @@ -402,7 +402,7 @@ of ftrace. Here is a list of some of the key files: If a function had either the "ip modify" or a "direct" call attached to it in the past, a 'M' will be shown. This flag is never cleared. It is - used to know if a function was every modified by the ftrace infrastructure, + used to know if a function was ever modified by the ftrace infrastructure, and can be used for debugging. If the architecture supports it, it will also show what callback @@ -418,7 +418,7 @@ of ftrace. Here is a list of some of the key files: This file contains all the functions that ever had a function callback to it via the ftrace infrastructure. It has the same format as - enabled_functions but shows all functions that have every been + enabled_functions but shows all functions that have ever been traced. To see any function that has every been modified by "ip modify" or a @@ -517,7 +517,7 @@ of ftrace. Here is a list of some of the key files: Whenever an event is recorded into the ring buffer, a "timestamp" is added. This stamp comes from a specified clock. By default, ftrace uses the "local" clock. This - clock is very fast and strictly per cpu, but on some + clock is very fast and strictly per CPU, but on some systems it may not be monotonic with respect to other CPUs. In other words, the local clocks may not be in sync with local clocks on other CPUs. @@ -868,7 +868,7 @@ Here is the list of current tracers that may be configured. "mmiotrace" - A special tracer that is used to trace binary module. + A special tracer that is used to trace binary modules. It will trace all the calls that a module makes to the hardware. Everything it writes and reads from the I/O as well. diff --git a/Documentation/trace/histogram.rst b/Documentation/trace/histogram.rst index 2b98c1720a54..af6d2e15568e 100644 --- a/Documentation/trace/histogram.rst +++ b/Documentation/trace/histogram.rst @@ -840,7 +840,7 @@ Extended error information The compound key examples used a key and a sum value (hitcount) to sort the output, but we can just as easily use two keys instead. - Here's an example where we use a compound key composed of the the + Here's an example where we use a compound key composed of the common_pid and size event fields. Sorting with pid as the primary key and 'size' as the secondary key allows us to display an ordered summary of the recvfrom sizes, with counts, received by From 37c52167b007d9d0bb8c5ed53dd6efc4969a1356 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Wed, 13 Aug 2025 12:00:52 +0200 Subject: [PATCH 01217/11391] docs: Remove remainders of reiserfs Reiserfs has been removed in 6.13, there are still some mentions in the documentation about it and the tools. Remove those that don't seem relevant anymore but keep references to reiserfs' r5 hash used by some code. There's one change in a script scripts/selinux/install_policy.sh but it does not seem to be relevant either. Signed-off-by: David Sterba Acked-by: Paul Moore Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20250813100053.1291961-1-dsterba@suse.com --- Documentation/admin-guide/ext4.rst | 2 +- Documentation/admin-guide/laptops/laptop-mode.rst | 8 ++++---- .../arch/powerpc/eeh-pci-error-recovery.rst | 1 - .../translations/it_IT/process/changes.rst | 14 -------------- fs/btrfs/tree-log.c | 2 +- scripts/selinux/install_policy.sh | 2 +- 6 files changed, 7 insertions(+), 22 deletions(-) diff --git a/Documentation/admin-guide/ext4.rst b/Documentation/admin-guide/ext4.rst index b857eb6ca1b6..ac0c709ea9e7 100644 --- a/Documentation/admin-guide/ext4.rst +++ b/Documentation/admin-guide/ext4.rst @@ -398,7 +398,7 @@ There are 3 different data modes: * writeback mode In data=writeback mode, ext4 does not journal data at all. This mode provides - a similar level of journaling as that of XFS, JFS, and ReiserFS in its default + a similar level of journaling as that of XFS and JFS in its default mode - metadata journaling. A crash+recovery can cause incorrect data to appear in files which were written shortly before the crash. This mode will typically provide the best ext4 performance. diff --git a/Documentation/admin-guide/laptops/laptop-mode.rst b/Documentation/admin-guide/laptops/laptop-mode.rst index b61cc601d298..66eb9cd918b5 100644 --- a/Documentation/admin-guide/laptops/laptop-mode.rst +++ b/Documentation/admin-guide/laptops/laptop-mode.rst @@ -61,7 +61,7 @@ Caveats Check your drive's rating, and don't wear down your drive's lifetime if you don't need to. -* If you mount some of your ext3/reiserfs filesystems with the -n option, then +* If you mount some of your ext3 filesystems with the -n option, then the control script will not be able to remount them correctly. You must set DO_REMOUNTS=0 in the control script, otherwise it will remount them with the wrong options -- or it will fail because it cannot write to /etc/mtab. @@ -96,7 +96,7 @@ control script increases dirty_expire_centisecs and dirty_writeback_centisecs in dirtied are not forced to be written to disk as often. The control script also changes the dirty background ratio, so that background writeback of dirty pages is not done anymore. Combined with a higher commit value (also 10 minutes) for -ext3 or ReiserFS filesystems (also done automatically by the control script), +ext3 filesystem (also done automatically by the control script), this results in concentration of disk activity in a small time interval which occurs only once every 10 minutes, or whenever the disk is forced to spin up by a cache miss. The disk can then be spun down in the periods of inactivity. @@ -587,7 +587,7 @@ Control script:: FST=$(deduce_fstype $MP) fi case "$FST" in - "ext3"|"reiserfs") + "ext3") PARSEDOPTS="$(parse_mount_opts commit "$OPTS")" mount $DEV -t $FST $MP -o remount,$PARSEDOPTS,commit=$MAX_AGE$NOATIME_OPT ;; @@ -647,7 +647,7 @@ Control script:: FST=$(deduce_fstype $MP) fi case "$FST" in - "ext3"|"reiserfs") + "ext3") PARSEDOPTS="$(parse_mount_opts_wfstab $DEV commit $OPTS)" PARSEDOPTS="$(parse_yesno_opts_wfstab $DEV atime atime $PARSEDOPTS)" mount $DEV -t $FST $MP -o remount,$PARSEDOPTS diff --git a/Documentation/arch/powerpc/eeh-pci-error-recovery.rst b/Documentation/arch/powerpc/eeh-pci-error-recovery.rst index d6643a91bdf8..153d0af055b6 100644 --- a/Documentation/arch/powerpc/eeh-pci-error-recovery.rst +++ b/Documentation/arch/powerpc/eeh-pci-error-recovery.rst @@ -315,7 +315,6 @@ network daemons and file systems that didn't need to be disturbed. ideally, the reset should happen at or below the block layer, so that the file systems are not disturbed. - Reiserfs does not tolerate errors returned from the block device. Ext3fs seems to be tolerant, retrying reads/writes until it does succeed. Both have been only lightly tested in this scenario. diff --git a/Documentation/translations/it_IT/process/changes.rst b/Documentation/translations/it_IT/process/changes.rst index 77db13c4022b..7e93833b4511 100644 --- a/Documentation/translations/it_IT/process/changes.rst +++ b/Documentation/translations/it_IT/process/changes.rst @@ -46,7 +46,6 @@ util-linux 2.10o mount --version kmod 13 depmod -V e2fsprogs 1.41.4 e2fsck -V jfsutils 1.1.3 fsck.jfs -V -reiserfsprogs 3.6.3 reiserfsck -V xfsprogs 2.6.0 xfs_db -V squashfs-tools 4.0 mksquashfs -version btrfs-progs 0.18 btrfsck @@ -260,14 +259,6 @@ Sono disponibili i seguenti strumenti: - sono disponibili altri strumenti per il file-system. -Reiserfsprogs -------------- - -Il pacchetto reiserfsprogs dovrebbe essere usato con reiserfs-3.6.x (Linux -kernel 2.4.x). Questo è un pacchetto combinato che contiene versioni -funzionanti di ``mkreiserfs``, ``resize_reiserfs``, ``debugreiserfs`` e -``reiserfsck``. Questi programmi funzionano sulle piattaforme i386 e alpha. - Xfsprogs -------- @@ -479,11 +470,6 @@ JFSutils - -Reiserfsprogs -------------- - -- - Xfsprogs -------- diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 2186e87fb61b..f72ce393f480 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -5460,7 +5460,7 @@ struct btrfs_dir_list { * See process_dir_items_leaf() for details about why it is needed. * This is a recursive operation - if an existing dentry corresponds to a * directory, that directory's new entries are logged too (same behaviour as - * ext3/4, xfs, f2fs, reiserfs, nilfs2). Note that when logging the inodes + * ext3/4, xfs, f2fs, nilfs2). Note that when logging the inodes * the dentries point to we do not acquire their VFS lock, otherwise lockdep * complains about the following circular lock dependency / possible deadlock: * diff --git a/scripts/selinux/install_policy.sh b/scripts/selinux/install_policy.sh index db40237e60ce..77368a73f111 100755 --- a/scripts/selinux/install_policy.sh +++ b/scripts/selinux/install_policy.sh @@ -74,7 +74,7 @@ cd /etc/selinux/dummy/contexts/files $SF -F file_contexts / mounts=`cat /proc/$$/mounts | \ - grep -E "ext[234]|jfs|xfs|reiserfs|jffs2|gfs2|btrfs|f2fs|ocfs2" | \ + grep -E "ext[234]|jfs|xfs|jffs2|gfs2|btrfs|f2fs|ocfs2" | \ awk '{ print $2 '}` $SF -F file_contexts $mounts From e6a9530b3ee7407b70b60e4df70688db0d239e1a Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Mon, 18 Aug 2025 08:39:53 -0700 Subject: [PATCH 01218/11391] 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 27758d8c2583d10472b745a43ff86fef96c11ef7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Thu, 14 Aug 2025 12:14:46 +0200 Subject: [PATCH 01219/11391] kbuild: enable -Werror for hostprogs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hostprog compilers and linkers do not share the regular compiler flags, so they are not affected by CONFIG_WERROR or W=e. As hostprogs are used during the bootstrap of the build, they can't depend on kconfig options. Enable -Werror unconditionally. Signed-off-by: Thomas Weißschuh Link: https://lore.kernel.org/rust-for-linux/CANiq72k-PdSH2BNgbq=X+FhpyEErifSCKfO5ObXz6bu9_J8+fA@mail.gmail.com/ Link: https://lore.kernel.org/r/20250814-kbuild-werror-v2-6-c01e596309d2@linutronix.de Signed-off-by: Nathan Chancellor --- scripts/Makefile.extrawarn | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/Makefile.extrawarn b/scripts/Makefile.extrawarn index 96ff3f5582d6..1434cb6208cb 100644 --- a/scripts/Makefile.extrawarn +++ b/scripts/Makefile.extrawarn @@ -224,3 +224,8 @@ KBUILD_USERLDFLAGS += -Wl,--fatal-warnings KBUILD_RUSTFLAGS += -Dwarnings endif + +# Hostprog flags are used during build bootstrapping and can not rely on CONFIG_ symbols. +KBUILD_HOSTCFLAGS += -Werror +KBUILD_HOSTLDFLAGS += -Wl,--fatal-warnings +KBUILD_HOSTRUSTFLAGS += -Dwarnings From 89d912e494f786e79f69ed9d567a8842c71dbb03 Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Thu, 14 Aug 2025 11:59:27 +0200 Subject: [PATCH 01220/11391] bpf: Add dynptr type for skb metadata Add a dynptr type, similar to skb dynptr, but for the skb metadata access. The dynptr provides an alternative to __sk_buff->data_meta for accessing the custom metadata area allocated using the bpf_xdp_adjust_meta() helper. More importantly, it abstracts away the fact where the storage for the custom metadata lives, which opens up the way to persist the metadata by relocating it as the skb travels through the network stack layers. Writes to skb metadata invalidate any existing skb payload and metadata slices. While this is more restrictive that needed at the moment, it leaves the door open to reallocating the metadata on writes, and should be only a minor inconvenience to the users. Only the program types which can access __sk_buff->data_meta today are allowed to create a dynptr for skb metadata at the moment. We need to modify the network stack to persist the metadata across layers before opening up access to other BPF hooks. Once more BPF hooks gain access to skb_meta dynptr, we will also need to add a read-only variant of the helper similar to bpf_dynptr_from_skb_rdonly. skb_meta dynptr ops are stubbed out and implemented by subsequent changes. Signed-off-by: Jakub Sitnicki Signed-off-by: Martin KaFai Lau Reviewed-by: Jesse Brandeburg Link: https://patch.msgid.link/20250814-skb-metadata-thru-dynptr-v7-1-8a39e636e0fb@cloudflare.com --- include/linux/bpf.h | 7 ++++++- kernel/bpf/helpers.c | 7 +++++++ kernel/bpf/log.c | 2 ++ kernel/bpf/verifier.c | 15 +++++++++++++-- net/core/filter.c | 41 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 69 insertions(+), 3 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index cc700925b802..ec527b476dba 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -767,12 +767,15 @@ enum bpf_type_flag { */ MEM_WRITE = BIT(18 + BPF_BASE_TYPE_BITS), + /* DYNPTR points to skb_metadata_end()-skb_metadata_len() */ + DYNPTR_TYPE_SKB_META = BIT(19 + BPF_BASE_TYPE_BITS), + __BPF_TYPE_FLAG_MAX, __BPF_TYPE_LAST_FLAG = __BPF_TYPE_FLAG_MAX - 1, }; #define DYNPTR_TYPE_FLAG_MASK (DYNPTR_TYPE_LOCAL | DYNPTR_TYPE_RINGBUF | DYNPTR_TYPE_SKB \ - | DYNPTR_TYPE_XDP) + | DYNPTR_TYPE_XDP | DYNPTR_TYPE_SKB_META) /* Max number of base types. */ #define BPF_BASE_TYPE_LIMIT (1UL << BPF_BASE_TYPE_BITS) @@ -1358,6 +1361,8 @@ enum bpf_dynptr_type { BPF_DYNPTR_TYPE_SKB, /* Underlying data is a xdp_buff */ BPF_DYNPTR_TYPE_XDP, + /* Points to skb_metadata_end()-skb_metadata_len() */ + BPF_DYNPTR_TYPE_SKB_META, }; int bpf_dynptr_check_size(u32 size); diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 6b4877e85a68..9552b32208c5 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -1780,6 +1780,8 @@ static int __bpf_dynptr_read(void *dst, u32 len, const struct bpf_dynptr_kern *s return __bpf_skb_load_bytes(src->data, src->offset + offset, dst, len); case BPF_DYNPTR_TYPE_XDP: return __bpf_xdp_load_bytes(src->data, src->offset + offset, dst, len); + case BPF_DYNPTR_TYPE_SKB_META: + return -EOPNOTSUPP; /* not implemented */ default: WARN_ONCE(true, "bpf_dynptr_read: unknown dynptr type %d\n", type); return -EFAULT; @@ -1836,6 +1838,8 @@ int __bpf_dynptr_write(const struct bpf_dynptr_kern *dst, u32 offset, void *src, if (flags) return -EINVAL; return __bpf_xdp_store_bytes(dst->data, dst->offset + offset, src, len); + case BPF_DYNPTR_TYPE_SKB_META: + return -EOPNOTSUPP; /* not implemented */ default: WARN_ONCE(true, "bpf_dynptr_write: unknown dynptr type %d\n", type); return -EFAULT; @@ -1882,6 +1886,7 @@ BPF_CALL_3(bpf_dynptr_data, const struct bpf_dynptr_kern *, ptr, u32, offset, u3 return (unsigned long)(ptr->data + ptr->offset + offset); case BPF_DYNPTR_TYPE_SKB: case BPF_DYNPTR_TYPE_XDP: + case BPF_DYNPTR_TYPE_SKB_META: /* skb and xdp dynptrs should use bpf_dynptr_slice / bpf_dynptr_slice_rdwr */ return 0; default: @@ -2710,6 +2715,8 @@ __bpf_kfunc void *bpf_dynptr_slice(const struct bpf_dynptr *p, u32 offset, bpf_xdp_copy_buf(ptr->data, ptr->offset + offset, buffer__opt, len, false); return buffer__opt; } + case BPF_DYNPTR_TYPE_SKB_META: + return NULL; /* not implemented */ default: WARN_ONCE(true, "unknown dynptr type %d\n", type); return NULL; diff --git a/kernel/bpf/log.c b/kernel/bpf/log.c index 38050f4ee400..e4983c1303e7 100644 --- a/kernel/bpf/log.c +++ b/kernel/bpf/log.c @@ -498,6 +498,8 @@ const char *dynptr_type_str(enum bpf_dynptr_type type) return "skb"; case BPF_DYNPTR_TYPE_XDP: return "xdp"; + case BPF_DYNPTR_TYPE_SKB_META: + return "skb_meta"; case BPF_DYNPTR_TYPE_INVALID: return ""; default: diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index c4f69a9e9af6..5964bed40ffb 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -674,6 +674,8 @@ static enum bpf_dynptr_type arg_to_dynptr_type(enum bpf_arg_type arg_type) return BPF_DYNPTR_TYPE_SKB; case DYNPTR_TYPE_XDP: return BPF_DYNPTR_TYPE_XDP; + case DYNPTR_TYPE_SKB_META: + return BPF_DYNPTR_TYPE_SKB_META; default: return BPF_DYNPTR_TYPE_INVALID; } @@ -690,6 +692,8 @@ static enum bpf_type_flag get_dynptr_type_flag(enum bpf_dynptr_type type) return DYNPTR_TYPE_SKB; case BPF_DYNPTR_TYPE_XDP: return DYNPTR_TYPE_XDP; + case BPF_DYNPTR_TYPE_SKB_META: + return DYNPTR_TYPE_SKB_META; default: return 0; } @@ -2274,7 +2278,8 @@ static bool reg_is_pkt_pointer_any(const struct bpf_reg_state *reg) static bool reg_is_dynptr_slice_pkt(const struct bpf_reg_state *reg) { return base_type(reg->type) == PTR_TO_MEM && - (reg->type & DYNPTR_TYPE_SKB || reg->type & DYNPTR_TYPE_XDP); + (reg->type & + (DYNPTR_TYPE_SKB | DYNPTR_TYPE_XDP | DYNPTR_TYPE_SKB_META)); } /* Unmodified PTR_TO_PACKET[_META,_END] register from ctx access. */ @@ -11641,7 +11646,8 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn if (dynptr_type == BPF_DYNPTR_TYPE_INVALID) return -EFAULT; - if (dynptr_type == BPF_DYNPTR_TYPE_SKB) + if (dynptr_type == BPF_DYNPTR_TYPE_SKB || + dynptr_type == BPF_DYNPTR_TYPE_SKB_META) /* this will trigger clear_all_pkt_pointers(), which will * invalidate all dynptr slices associated with the skb */ @@ -12228,6 +12234,7 @@ enum special_kfunc_type { KF_bpf_rbtree_right, KF_bpf_dynptr_from_skb, KF_bpf_dynptr_from_xdp, + KF_bpf_dynptr_from_skb_meta, KF_bpf_dynptr_slice, KF_bpf_dynptr_slice_rdwr, KF_bpf_dynptr_clone, @@ -12277,9 +12284,11 @@ BTF_ID(func, bpf_rbtree_right) #ifdef CONFIG_NET BTF_ID(func, bpf_dynptr_from_skb) BTF_ID(func, bpf_dynptr_from_xdp) +BTF_ID(func, bpf_dynptr_from_skb_meta) #else BTF_ID_UNUSED BTF_ID_UNUSED +BTF_ID_UNUSED #endif BTF_ID(func, bpf_dynptr_slice) BTF_ID(func, bpf_dynptr_slice_rdwr) @@ -13253,6 +13262,8 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ dynptr_arg_type |= DYNPTR_TYPE_SKB; } else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_from_xdp]) { dynptr_arg_type |= DYNPTR_TYPE_XDP; + } else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_from_skb_meta]) { + dynptr_arg_type |= DYNPTR_TYPE_SKB_META; } else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_clone] && (dynptr_arg_type & MEM_UNINIT)) { enum bpf_dynptr_type parent_type = meta->initialized_dynptr.type; diff --git a/net/core/filter.c b/net/core/filter.c index da391e2b0788..31b4b50dbadf 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -12007,6 +12007,36 @@ __bpf_kfunc int bpf_dynptr_from_skb(struct __sk_buff *s, u64 flags, return 0; } +/** + * bpf_dynptr_from_skb_meta() - Initialize a dynptr to the skb metadata area. + * @skb_: socket buffer carrying the metadata + * @flags: future use, must be zero + * @ptr__uninit: dynptr to initialize + * + * Set up a dynptr for access to the metadata area earlier allocated from the + * XDP context with bpf_xdp_adjust_meta(). Serves as an alternative to + * &__sk_buff->data_meta. + * + * Return: + * * %0 - dynptr ready to use + * * %-EINVAL - invalid flags, dynptr set to null + */ +__bpf_kfunc int bpf_dynptr_from_skb_meta(struct __sk_buff *skb_, u64 flags, + struct bpf_dynptr *ptr__uninit) +{ + struct bpf_dynptr_kern *ptr = (struct bpf_dynptr_kern *)ptr__uninit; + struct sk_buff *skb = (struct sk_buff *)skb_; + + if (flags) { + bpf_dynptr_set_null(ptr); + return -EINVAL; + } + + bpf_dynptr_init(ptr, skb, BPF_DYNPTR_TYPE_SKB_META, 0, skb_metadata_len(skb)); + + return 0; +} + __bpf_kfunc int bpf_dynptr_from_xdp(struct xdp_md *x, u64 flags, struct bpf_dynptr *ptr__uninit) { @@ -12181,6 +12211,10 @@ BTF_KFUNCS_START(bpf_kfunc_check_set_skb) BTF_ID_FLAGS(func, bpf_dynptr_from_skb, KF_TRUSTED_ARGS) BTF_KFUNCS_END(bpf_kfunc_check_set_skb) +BTF_KFUNCS_START(bpf_kfunc_check_set_skb_meta) +BTF_ID_FLAGS(func, bpf_dynptr_from_skb_meta, KF_TRUSTED_ARGS) +BTF_KFUNCS_END(bpf_kfunc_check_set_skb_meta) + BTF_KFUNCS_START(bpf_kfunc_check_set_xdp) BTF_ID_FLAGS(func, bpf_dynptr_from_xdp) BTF_KFUNCS_END(bpf_kfunc_check_set_xdp) @@ -12202,6 +12236,11 @@ static const struct btf_kfunc_id_set bpf_kfunc_set_skb = { .set = &bpf_kfunc_check_set_skb, }; +static const struct btf_kfunc_id_set bpf_kfunc_set_skb_meta = { + .owner = THIS_MODULE, + .set = &bpf_kfunc_check_set_skb_meta, +}; + static const struct btf_kfunc_id_set bpf_kfunc_set_xdp = { .owner = THIS_MODULE, .set = &bpf_kfunc_check_set_xdp, @@ -12237,6 +12276,8 @@ static int __init bpf_kfunc_init(void) ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_LWT_SEG6LOCAL, &bpf_kfunc_set_skb); ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_NETFILTER, &bpf_kfunc_set_skb); ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, &bpf_kfunc_set_skb); + ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_CLS, &bpf_kfunc_set_skb_meta); + ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_ACT, &bpf_kfunc_set_skb_meta); ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_XDP, &bpf_kfunc_set_xdp); ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_CGROUP_SOCK_ADDR, &bpf_kfunc_set_sock_addr); From 6877cd392baecf816c2ba896a9d42874628004a5 Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Thu, 14 Aug 2025 11:59:28 +0200 Subject: [PATCH 01221/11391] bpf: Enable read/write access to skb metadata through a dynptr Now that we can create a dynptr to skb metadata, make reads to the metadata area possible with bpf_dynptr_read() or through a bpf_dynptr_slice(), and make writes to the metadata area possible with bpf_dynptr_write() or through a bpf_dynptr_slice_rdwr(). Note that for cloned skbs which share data with the original, we limit the skb metadata dynptr to be read-only since we don't unclone on a bpf_dynptr_write to metadata. Signed-off-by: Jakub Sitnicki Signed-off-by: Martin KaFai Lau Link: https://patch.msgid.link/20250814-skb-metadata-thru-dynptr-v7-2-8a39e636e0fb@cloudflare.com --- include/linux/filter.h | 6 ++++++ kernel/bpf/helpers.c | 10 +++++++--- net/core/filter.c | 16 ++++++++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/include/linux/filter.h b/include/linux/filter.h index 1e7fd3ee759e..9ed21b65e2e9 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -1784,6 +1784,7 @@ int __bpf_xdp_store_bytes(struct xdp_buff *xdp, u32 offset, void *buf, u32 len); void *bpf_xdp_pointer(struct xdp_buff *xdp, u32 offset, u32 len); void bpf_xdp_copy_buf(struct xdp_buff *xdp, unsigned long off, void *buf, unsigned long len, bool flush); +void *bpf_skb_meta_pointer(struct sk_buff *skb, u32 offset); #else /* CONFIG_NET */ static inline int __bpf_skb_load_bytes(const struct sk_buff *skb, u32 offset, void *to, u32 len) @@ -1818,6 +1819,11 @@ static inline void bpf_xdp_copy_buf(struct xdp_buff *xdp, unsigned long off, voi unsigned long len, bool flush) { } + +static inline void *bpf_skb_meta_pointer(struct sk_buff *skb, u32 offset) +{ + return NULL; +} #endif /* CONFIG_NET */ #endif /* __LINUX_FILTER_H__ */ diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 9552b32208c5..cdffd74ddbe6 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -1781,7 +1781,8 @@ static int __bpf_dynptr_read(void *dst, u32 len, const struct bpf_dynptr_kern *s case BPF_DYNPTR_TYPE_XDP: return __bpf_xdp_load_bytes(src->data, src->offset + offset, dst, len); case BPF_DYNPTR_TYPE_SKB_META: - return -EOPNOTSUPP; /* not implemented */ + memmove(dst, bpf_skb_meta_pointer(src->data, src->offset + offset), len); + return 0; default: WARN_ONCE(true, "bpf_dynptr_read: unknown dynptr type %d\n", type); return -EFAULT; @@ -1839,7 +1840,10 @@ int __bpf_dynptr_write(const struct bpf_dynptr_kern *dst, u32 offset, void *src, return -EINVAL; return __bpf_xdp_store_bytes(dst->data, dst->offset + offset, src, len); case BPF_DYNPTR_TYPE_SKB_META: - return -EOPNOTSUPP; /* not implemented */ + if (flags) + return -EINVAL; + memmove(bpf_skb_meta_pointer(dst->data, dst->offset + offset), src, len); + return 0; default: WARN_ONCE(true, "bpf_dynptr_write: unknown dynptr type %d\n", type); return -EFAULT; @@ -2716,7 +2720,7 @@ __bpf_kfunc void *bpf_dynptr_slice(const struct bpf_dynptr *p, u32 offset, return buffer__opt; } case BPF_DYNPTR_TYPE_SKB_META: - return NULL; /* not implemented */ + return bpf_skb_meta_pointer(ptr->data, ptr->offset + offset); default: WARN_ONCE(true, "unknown dynptr type %d\n", type); return NULL; diff --git a/net/core/filter.c b/net/core/filter.c index 31b4b50dbadf..63f3baee2daf 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -11990,6 +11990,16 @@ bpf_sk_base_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return func; } +/** + * bpf_skb_meta_pointer() - Gets a mutable pointer within the skb metadata area. + * @skb: socket buffer carrying the metadata + * @offset: offset into the metadata area, must be <= skb_metadata_len() + */ +void *bpf_skb_meta_pointer(struct sk_buff *skb, u32 offset) +{ + return skb_metadata_end(skb) - skb_metadata_len(skb) + offset; +} + __bpf_kfunc_start_defs(); __bpf_kfunc int bpf_dynptr_from_skb(struct __sk_buff *s, u64 flags, struct bpf_dynptr *ptr__uninit) @@ -12017,6 +12027,9 @@ __bpf_kfunc int bpf_dynptr_from_skb(struct __sk_buff *s, u64 flags, * XDP context with bpf_xdp_adjust_meta(). Serves as an alternative to * &__sk_buff->data_meta. * + * If passed @skb_ is a clone which shares the data with the original, the + * dynptr will be read-only. This limitation may be lifted in the future. + * * Return: * * %0 - dynptr ready to use * * %-EINVAL - invalid flags, dynptr set to null @@ -12034,6 +12047,9 @@ __bpf_kfunc int bpf_dynptr_from_skb_meta(struct __sk_buff *skb_, u64 flags, bpf_dynptr_init(ptr, skb, BPF_DYNPTR_TYPE_SKB_META, 0, skb_metadata_len(skb)); + if (skb_cloned(skb)) + bpf_dynptr_set_rdonly(ptr); + return 0; } From 0e74eb4d57f00e6103ac23ce2312766c25ad88f6 Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Thu, 14 Aug 2025 11:59:29 +0200 Subject: [PATCH 01222/11391] selftests/bpf: Cover verifier checks for skb_meta dynptr type dynptr for skb metadata behaves the same way as the dynptr for skb data with one exception - writes to skb_meta dynptr don't invalidate existing skb and skb_meta slices. Duplicate those the skb dynptr tests which we can, since bpf_dynptr_from_skb_meta kfunc can be called only from TC BPF, to cover the skb_meta dynptr verifier checks. Also add a couple of new tests (skb_data_valid_*) to ensure we don't invalidate the slices in the mentioned case, which are specific to skb_meta dynptr. Signed-off-by: Jakub Sitnicki Signed-off-by: Martin KaFai Lau Reviewed-by: Jesse Brandeburg Link: https://patch.msgid.link/20250814-skb-metadata-thru-dynptr-v7-3-8a39e636e0fb@cloudflare.com --- .../testing/selftests/bpf/prog_tests/dynptr.c | 2 + .../testing/selftests/bpf/progs/dynptr_fail.c | 258 ++++++++++++++++++ .../selftests/bpf/progs/dynptr_success.c | 55 ++++ 3 files changed, 315 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/dynptr.c b/tools/testing/selftests/bpf/prog_tests/dynptr.c index 9b2d9ceda210..b9f86cb91e81 100644 --- a/tools/testing/selftests/bpf/prog_tests/dynptr.c +++ b/tools/testing/selftests/bpf/prog_tests/dynptr.c @@ -32,6 +32,8 @@ static struct { {"test_ringbuf", SETUP_SYSCALL_SLEEP}, {"test_skb_readonly", SETUP_SKB_PROG}, {"test_dynptr_skb_data", SETUP_SKB_PROG}, + {"test_dynptr_skb_meta_data", SETUP_SKB_PROG}, + {"test_dynptr_skb_meta_flags", SETUP_SKB_PROG}, {"test_adjust", SETUP_SYSCALL_SLEEP}, {"test_adjust_err", SETUP_SYSCALL_SLEEP}, {"test_zero_size_dynptr", SETUP_SYSCALL_SLEEP}, diff --git a/tools/testing/selftests/bpf/progs/dynptr_fail.c b/tools/testing/selftests/bpf/progs/dynptr_fail.c index bd8f15229f5c..dda6a8dada82 100644 --- a/tools/testing/selftests/bpf/progs/dynptr_fail.c +++ b/tools/testing/selftests/bpf/progs/dynptr_fail.c @@ -269,6 +269,26 @@ int data_slice_out_of_bounds_skb(struct __sk_buff *skb) return SK_PASS; } +/* A metadata slice can't be accessed out of bounds */ +SEC("?tc") +__failure __msg("value is outside of the allowed memory range") +int data_slice_out_of_bounds_skb_meta(struct __sk_buff *skb) +{ + struct bpf_dynptr meta; + __u8 *md; + + bpf_dynptr_from_skb_meta(skb, 0, &meta); + + md = bpf_dynptr_slice_rdwr(&meta, 0, NULL, sizeof(*md)); + if (!md) + return SK_DROP; + + /* this should fail */ + *(md + 1) = 42; + + return SK_PASS; +} + SEC("?raw_tp") __failure __msg("value is outside of the allowed memory range") int data_slice_out_of_bounds_map_value(void *ctx) @@ -1089,6 +1109,26 @@ int skb_invalid_slice_write(struct __sk_buff *skb) return SK_PASS; } +/* bpf_dynptr_slice()s are read-only and cannot be written to */ +SEC("?tc") +__failure __msg("R{{[0-9]+}} cannot write into rdonly_mem") +int skb_meta_invalid_slice_write(struct __sk_buff *skb) +{ + struct bpf_dynptr meta; + __u8 *md; + + bpf_dynptr_from_skb_meta(skb, 0, &meta); + + md = bpf_dynptr_slice(&meta, 0, NULL, sizeof(*md)); + if (!md) + return SK_DROP; + + /* this should fail */ + *md = 42; + + return SK_PASS; +} + /* The read-only data slice is invalidated whenever a helper changes packet data */ SEC("?tc") __failure __msg("invalid mem access 'scalar'") @@ -1192,6 +1232,188 @@ int skb_invalid_data_slice4(struct __sk_buff *skb) return SK_PASS; } +/* Read-only skb data slice is invalidated on write to skb metadata */ +SEC("?tc") +__failure __msg("invalid mem access 'scalar'") +int ro_skb_slice_invalid_after_metadata_write(struct __sk_buff *skb) +{ + struct bpf_dynptr data, meta; + __u8 *d; + + bpf_dynptr_from_skb(skb, 0, &data); + bpf_dynptr_from_skb_meta(skb, 0, &meta); + + d = bpf_dynptr_slice(&data, 0, NULL, sizeof(*d)); + if (!d) + return SK_DROP; + + bpf_dynptr_write(&meta, 0, "x", 1, 0); + + /* this should fail */ + val = *d; + + return SK_PASS; +} + +/* Read-write skb data slice is invalidated on write to skb metadata */ +SEC("?tc") +__failure __msg("invalid mem access 'scalar'") +int rw_skb_slice_invalid_after_metadata_write(struct __sk_buff *skb) +{ + struct bpf_dynptr data, meta; + __u8 *d; + + bpf_dynptr_from_skb(skb, 0, &data); + bpf_dynptr_from_skb_meta(skb, 0, &meta); + + d = bpf_dynptr_slice_rdwr(&data, 0, NULL, sizeof(*d)); + if (!d) + return SK_DROP; + + bpf_dynptr_write(&meta, 0, "x", 1, 0); + + /* this should fail */ + *d = 42; + + return SK_PASS; +} + +/* Read-only skb metadata slice is invalidated on write to skb data */ +SEC("?tc") +__failure __msg("invalid mem access 'scalar'") +int ro_skb_meta_slice_invalid_after_payload_write(struct __sk_buff *skb) +{ + struct bpf_dynptr data, meta; + __u8 *md; + + bpf_dynptr_from_skb(skb, 0, &data); + bpf_dynptr_from_skb_meta(skb, 0, &meta); + + md = bpf_dynptr_slice(&meta, 0, NULL, sizeof(*md)); + if (!md) + return SK_DROP; + + bpf_dynptr_write(&data, 0, "x", 1, 0); + + /* this should fail */ + val = *md; + + return SK_PASS; +} + +/* Read-write skb metadata slice is invalidated on write to skb data slice */ +SEC("?tc") +__failure __msg("invalid mem access 'scalar'") +int rw_skb_meta_slice_invalid_after_payload_write(struct __sk_buff *skb) +{ + struct bpf_dynptr data, meta; + __u8 *md; + + bpf_dynptr_from_skb(skb, 0, &data); + bpf_dynptr_from_skb_meta(skb, 0, &meta); + + md = bpf_dynptr_slice_rdwr(&meta, 0, NULL, sizeof(*md)); + if (!md) + return SK_DROP; + + bpf_dynptr_write(&data, 0, "x", 1, 0); + + /* this should fail */ + *md = 42; + + return SK_PASS; +} + +/* Read-only skb metadata slice is invalidated whenever a helper changes packet data */ +SEC("?tc") +__failure __msg("invalid mem access 'scalar'") +int ro_skb_meta_slice_invalid_after_payload_helper(struct __sk_buff *skb) +{ + struct bpf_dynptr meta; + __u8 *md; + + bpf_dynptr_from_skb_meta(skb, 0, &meta); + + md = bpf_dynptr_slice(&meta, 0, NULL, sizeof(*md)); + if (!md) + return SK_DROP; + + if (bpf_skb_pull_data(skb, skb->len)) + return SK_DROP; + + /* this should fail */ + val = *md; + + return SK_PASS; +} + +/* Read-write skb metadata slice is invalidated whenever a helper changes packet data */ +SEC("?tc") +__failure __msg("invalid mem access 'scalar'") +int rw_skb_meta_slice_invalid_after_payload_helper(struct __sk_buff *skb) +{ + struct bpf_dynptr meta; + __u8 *md; + + bpf_dynptr_from_skb_meta(skb, 0, &meta); + + md = bpf_dynptr_slice_rdwr(&meta, 0, NULL, sizeof(*md)); + if (!md) + return SK_DROP; + + if (bpf_skb_pull_data(skb, skb->len)) + return SK_DROP; + + /* this should fail */ + *md = 42; + + return SK_PASS; +} + +/* Read-only skb metadata slice is invalidated on write to skb metadata */ +SEC("?tc") +__failure __msg("invalid mem access 'scalar'") +int ro_skb_meta_slice_invalid_after_metadata_write(struct __sk_buff *skb) +{ + struct bpf_dynptr meta; + __u8 *md; + + bpf_dynptr_from_skb_meta(skb, 0, &meta); + + md = bpf_dynptr_slice(&meta, 0, NULL, sizeof(*md)); + if (!md) + return SK_DROP; + + bpf_dynptr_write(&meta, 0, "x", 1, 0); + + /* this should fail */ + val = *md; + + return SK_PASS; +} + +/* Read-write skb metadata slice is invalidated on write to skb metadata */ +SEC("?tc") +__failure __msg("invalid mem access 'scalar'") +int rw_skb_meta_slice_invalid_after_metadata_write(struct __sk_buff *skb) +{ + struct bpf_dynptr meta; + __u8 *md; + + bpf_dynptr_from_skb_meta(skb, 0, &meta); + + md = bpf_dynptr_slice_rdwr(&meta, 0, NULL, sizeof(*md)); + if (!md) + return SK_DROP; + + bpf_dynptr_write(&meta, 0, "x", 1, 0); + + /* this should fail */ + *md = 42; + + return SK_PASS; +} + /* The read-only data slice is invalidated whenever a helper changes packet data */ SEC("?xdp") __failure __msg("invalid mem access 'scalar'") @@ -1255,6 +1477,19 @@ int skb_invalid_ctx(void *ctx) return 0; } +/* Only supported prog type can create skb_meta-type dynptrs */ +SEC("?raw_tp") +__failure __msg("calling kernel function bpf_dynptr_from_skb_meta is not allowed") +int skb_meta_invalid_ctx(void *ctx) +{ + struct bpf_dynptr meta; + + /* this should fail */ + bpf_dynptr_from_skb_meta(ctx, 0, &meta); + + return 0; +} + SEC("fentry/skb_tx_error") __failure __msg("must be referenced or trusted") int BPF_PROG(skb_invalid_ctx_fentry, void *skb) @@ -1665,6 +1900,29 @@ int clone_skb_packet_data(struct __sk_buff *skb) return 0; } +/* A skb clone's metadata slice becomes invalid anytime packet data changes */ +SEC("?tc") +__failure __msg("invalid mem access 'scalar'") +int clone_skb_packet_meta(struct __sk_buff *skb) +{ + struct bpf_dynptr clone, meta; + __u8 *md; + + bpf_dynptr_from_skb_meta(skb, 0, &meta); + bpf_dynptr_clone(&meta, &clone); + md = bpf_dynptr_slice_rdwr(&clone, 0, NULL, sizeof(*md)); + if (!md) + return SK_DROP; + + if (bpf_skb_pull_data(skb, skb->len)) + return SK_DROP; + + /* this should fail */ + *md = 42; + + return 0; +} + /* A xdp clone's data slices should be invalid anytime packet data changes */ SEC("?xdp") __failure __msg("invalid mem access 'scalar'") diff --git a/tools/testing/selftests/bpf/progs/dynptr_success.c b/tools/testing/selftests/bpf/progs/dynptr_success.c index 8315273cb900..127dea342e5a 100644 --- a/tools/testing/selftests/bpf/progs/dynptr_success.c +++ b/tools/testing/selftests/bpf/progs/dynptr_success.c @@ -211,6 +211,61 @@ int test_dynptr_skb_data(struct __sk_buff *skb) return 1; } +SEC("?tc") +int test_dynptr_skb_meta_data(struct __sk_buff *skb) +{ + struct bpf_dynptr meta; + __u8 *md; + int ret; + + err = 1; + ret = bpf_dynptr_from_skb_meta(skb, 0, &meta); + if (ret) + return 1; + + /* This should return NULL. Must use bpf_dynptr_slice API */ + err = 2; + md = bpf_dynptr_data(&meta, 0, sizeof(*md)); + if (md) + return 1; + + err = 0; + return 1; +} + +/* Check that skb metadata dynptr ops don't accept any flags. */ +SEC("?tc") +int test_dynptr_skb_meta_flags(struct __sk_buff *skb) +{ + const __u64 INVALID_FLAGS = ~0ULL; + struct bpf_dynptr meta; + __u8 buf; + int ret; + + err = 1; + ret = bpf_dynptr_from_skb_meta(skb, INVALID_FLAGS, &meta); + if (ret != -EINVAL) + return 1; + + err = 2; + ret = bpf_dynptr_from_skb_meta(skb, 0, &meta); + if (ret) + return 1; + + err = 3; + ret = bpf_dynptr_read(&buf, 0, &meta, 0, INVALID_FLAGS); + if (ret != -EINVAL) + return 1; + + err = 4; + ret = bpf_dynptr_write(&meta, 0, &buf, 0, INVALID_FLAGS); + if (ret != -EINVAL) + return 1; + + err = 0; + return 1; +} + SEC("tp/syscalls/sys_enter_nanosleep") int test_adjust(void *ctx) { From 6dfd5e01e1a7728e162f721cd8adf5ecd24fbc80 Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Thu, 14 Aug 2025 11:59:30 +0200 Subject: [PATCH 01223/11391] selftests/bpf: Pass just bpf_map to xdp_context_test helper Prepare for parametrizing the xdp_context tests. The assert_test_result helper doesn't need the whole skeleton. Pass just what it needs. Signed-off-by: Jakub Sitnicki Signed-off-by: Martin KaFai Lau Reviewed-by: Jesse Brandeburg Acked-by: Eduard Zingerman Link: https://patch.msgid.link/20250814-skb-metadata-thru-dynptr-v7-4-8a39e636e0fb@cloudflare.com --- .../selftests/bpf/prog_tests/xdp_context_test_run.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c b/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c index b9d9f0a502ce..0134651d94ab 100644 --- a/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c +++ b/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c @@ -156,15 +156,14 @@ static int send_test_packet(int ifindex) return -1; } -static void assert_test_result(struct test_xdp_meta *skel) +static void assert_test_result(const struct bpf_map *result_map) { int err; __u32 map_key = 0; __u8 map_value[TEST_PAYLOAD_LEN]; - err = bpf_map__lookup_elem(skel->maps.test_result, &map_key, - sizeof(map_key), &map_value, - TEST_PAYLOAD_LEN, BPF_ANY); + err = bpf_map__lookup_elem(result_map, &map_key, sizeof(map_key), + &map_value, TEST_PAYLOAD_LEN, BPF_ANY); if (!ASSERT_OK(err, "lookup test_result")) return; @@ -248,7 +247,7 @@ void test_xdp_context_veth(void) if (!ASSERT_OK(ret, "send_test_packet")) goto close; - assert_test_result(skel); + assert_test_result(skel->maps.test_result); close: close_netns(nstoken); @@ -313,7 +312,7 @@ void test_xdp_context_tuntap(void) if (!ASSERT_EQ(ret, sizeof(packet), "write packet")) goto close; - assert_test_result(skel); + assert_test_result(skel->maps.test_result); close: if (tap_fd >= 0) From dd9f6cfb4ef4394c2afd1e2b564af25aff151bc8 Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Thu, 14 Aug 2025 11:59:31 +0200 Subject: [PATCH 01224/11391] selftests/bpf: Parametrize test_xdp_context_tuntap We want to add more test cases to cover different ways to access the metadata area. Prepare for it. Pull up the skeleton management. Signed-off-by: Jakub Sitnicki Signed-off-by: Martin KaFai Lau Reviewed-by: Jesse Brandeburg Acked-by: Eduard Zingerman Link: https://patch.msgid.link/20250814-skb-metadata-thru-dynptr-v7-5-8a39e636e0fb@cloudflare.com --- .../bpf/prog_tests/xdp_context_test_run.c | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c b/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c index 0134651d94ab..6c66e27e5bc7 100644 --- a/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c +++ b/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c @@ -256,12 +256,13 @@ void test_xdp_context_veth(void) netns_free(tx_ns); } -void test_xdp_context_tuntap(void) +static void test_tuntap(struct bpf_program *xdp_prog, + struct bpf_program *tc_prog, + struct bpf_map *result_map) { LIBBPF_OPTS(bpf_tc_hook, tc_hook, .attach_point = BPF_TC_INGRESS); LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1); struct netns_obj *ns = NULL; - struct test_xdp_meta *skel = NULL; __u8 packet[sizeof(struct ethhdr) + TEST_PAYLOAD_LEN]; int tap_fd = -1; int tap_ifindex; @@ -277,10 +278,6 @@ void test_xdp_context_tuntap(void) SYS(close, "ip link set dev " TAP_NAME " up"); - skel = test_xdp_meta__open_and_load(); - if (!ASSERT_OK_PTR(skel, "open and load skeleton")) - goto close; - tap_ifindex = if_nametoindex(TAP_NAME); if (!ASSERT_GE(tap_ifindex, 0, "if_nametoindex")) goto close; @@ -290,12 +287,12 @@ void test_xdp_context_tuntap(void) if (!ASSERT_OK(ret, "bpf_tc_hook_create")) goto close; - tc_opts.prog_fd = bpf_program__fd(skel->progs.ing_cls); + tc_opts.prog_fd = bpf_program__fd(tc_prog); ret = bpf_tc_attach(&tc_hook, &tc_opts); if (!ASSERT_OK(ret, "bpf_tc_attach")) goto close; - ret = bpf_xdp_attach(tap_ifindex, bpf_program__fd(skel->progs.ing_xdp), + ret = bpf_xdp_attach(tap_ifindex, bpf_program__fd(xdp_prog), 0, NULL); if (!ASSERT_GE(ret, 0, "bpf_xdp_attach")) goto close; @@ -312,11 +309,25 @@ void test_xdp_context_tuntap(void) if (!ASSERT_EQ(ret, sizeof(packet), "write packet")) goto close; - assert_test_result(skel->maps.test_result); + assert_test_result(result_map); close: if (tap_fd >= 0) close(tap_fd); - test_xdp_meta__destroy(skel); netns_free(ns); } + +void test_xdp_context_tuntap(void) +{ + struct test_xdp_meta *skel = NULL; + + skel = test_xdp_meta__open_and_load(); + if (!ASSERT_OK_PTR(skel, "open and load skeleton")) + return; + + if (test__start_subtest("data_meta")) + test_tuntap(skel->progs.ing_xdp, skel->progs.ing_cls, + skel->maps.test_result); + + test_xdp_meta__destroy(skel); +} From 153f6bfd489076309227413e9221960712336369 Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Thu, 14 Aug 2025 11:59:32 +0200 Subject: [PATCH 01225/11391] selftests/bpf: Cover read access to skb metadata via dynptr Exercise reading from SKB metadata area in two new ways: 1. indirectly, with bpf_dynptr_read(), and 2. directly, with bpf_dynptr_slice(). Signed-off-by: Jakub Sitnicki Signed-off-by: Martin KaFai Lau Reviewed-by: Jesse Brandeburg Acked-by: Eduard Zingerman Link: https://patch.msgid.link/20250814-skb-metadata-thru-dynptr-v7-6-8a39e636e0fb@cloudflare.com --- tools/testing/selftests/bpf/bpf_kfuncs.h | 3 ++ .../bpf/prog_tests/xdp_context_test_run.c | 21 ++++++++++ .../selftests/bpf/progs/test_xdp_meta.c | 42 +++++++++++++++++++ 3 files changed, 66 insertions(+) diff --git a/tools/testing/selftests/bpf/bpf_kfuncs.h b/tools/testing/selftests/bpf/bpf_kfuncs.h index 9386dfe8b884..794d44d19c88 100644 --- a/tools/testing/selftests/bpf/bpf_kfuncs.h +++ b/tools/testing/selftests/bpf/bpf_kfuncs.h @@ -19,6 +19,9 @@ extern int bpf_dynptr_from_skb(struct __sk_buff *skb, __u64 flags, extern int bpf_dynptr_from_xdp(struct xdp_md *xdp, __u64 flags, struct bpf_dynptr *ptr__uninit) __ksym __weak; +extern int bpf_dynptr_from_skb_meta(struct __sk_buff *skb, __u64 flags, + struct bpf_dynptr *ptr__uninit) __ksym __weak; + /* Description * Obtain a read-only pointer to the dynptr's data * Returns diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c b/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c index 6c66e27e5bc7..7e4526461a4c 100644 --- a/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c +++ b/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c @@ -171,6 +171,18 @@ static void assert_test_result(const struct bpf_map *result_map) "test_result map contains test payload"); } +static bool clear_test_result(struct bpf_map *result_map) +{ + const __u8 v[sizeof(test_payload)] = {}; + const __u32 k = 0; + int err; + + err = bpf_map__update_elem(result_map, &k, sizeof(k), v, sizeof(v), BPF_ANY); + ASSERT_OK(err, "update test_result"); + + return err == 0; +} + void test_xdp_context_veth(void) { LIBBPF_OPTS(bpf_tc_hook, tc_hook, .attach_point = BPF_TC_INGRESS); @@ -268,6 +280,9 @@ static void test_tuntap(struct bpf_program *xdp_prog, int tap_ifindex; int ret; + if (!clear_test_result(result_map)) + return; + ns = netns_new(TAP_NETNS, true); if (!ASSERT_OK_PTR(ns, "create and open ns")) return; @@ -328,6 +343,12 @@ void test_xdp_context_tuntap(void) if (test__start_subtest("data_meta")) test_tuntap(skel->progs.ing_xdp, skel->progs.ing_cls, skel->maps.test_result); + if (test__start_subtest("dynptr_read")) + test_tuntap(skel->progs.ing_xdp, skel->progs.ing_cls_dynptr_read, + skel->maps.test_result); + if (test__start_subtest("dynptr_slice")) + test_tuntap(skel->progs.ing_xdp, skel->progs.ing_cls_dynptr_slice, + skel->maps.test_result); test_xdp_meta__destroy(skel); } diff --git a/tools/testing/selftests/bpf/progs/test_xdp_meta.c b/tools/testing/selftests/bpf/progs/test_xdp_meta.c index fcf6ca14f2ea..0ba647fb1b1d 100644 --- a/tools/testing/selftests/bpf/progs/test_xdp_meta.c +++ b/tools/testing/selftests/bpf/progs/test_xdp_meta.c @@ -1,8 +1,10 @@ +#include #include #include #include #include +#include "bpf_kfuncs.h" #define META_SIZE 32 @@ -40,6 +42,46 @@ int ing_cls(struct __sk_buff *ctx) return TC_ACT_SHOT; } +/* Read from metadata using bpf_dynptr_read helper */ +SEC("tc") +int ing_cls_dynptr_read(struct __sk_buff *ctx) +{ + struct bpf_dynptr meta; + const __u32 zero = 0; + __u8 *dst; + + dst = bpf_map_lookup_elem(&test_result, &zero); + if (!dst) + return TC_ACT_SHOT; + + bpf_dynptr_from_skb_meta(ctx, 0, &meta); + bpf_dynptr_read(dst, META_SIZE, &meta, 0, 0); + + return TC_ACT_SHOT; +} + +/* Read from metadata using read-only dynptr slice */ +SEC("tc") +int ing_cls_dynptr_slice(struct __sk_buff *ctx) +{ + struct bpf_dynptr meta; + const __u32 zero = 0; + __u8 *dst, *src; + + dst = bpf_map_lookup_elem(&test_result, &zero); + if (!dst) + return TC_ACT_SHOT; + + bpf_dynptr_from_skb_meta(ctx, 0, &meta); + src = bpf_dynptr_slice(&meta, 0, NULL, META_SIZE); + if (!src) + return TC_ACT_SHOT; + + __builtin_memcpy(dst, src, META_SIZE); + + return TC_ACT_SHOT; +} + SEC("xdp") int ing_xdp(struct xdp_md *ctx) { From ed93360807801e7f69b74efec98a1bd674ba035e Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Thu, 14 Aug 2025 11:59:33 +0200 Subject: [PATCH 01226/11391] selftests/bpf: Cover write access to skb metadata via dynptr Add tests what exercise writes to skb metadata in two ways: 1. indirectly, using bpf_dynptr_write helper, 2. directly, using a read-write dynptr slice. Signed-off-by: Jakub Sitnicki Signed-off-by: Martin KaFai Lau Reviewed-by: Jesse Brandeburg Acked-by: Eduard Zingerman Link: https://patch.msgid.link/20250814-skb-metadata-thru-dynptr-v7-7-8a39e636e0fb@cloudflare.com --- .../bpf/prog_tests/xdp_context_test_run.c | 36 ++++++++-- .../selftests/bpf/progs/test_xdp_meta.c | 67 +++++++++++++++++++ 2 files changed, 98 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c b/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c index 7e4526461a4c..79c4c58276e6 100644 --- a/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c +++ b/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c @@ -269,7 +269,8 @@ void test_xdp_context_veth(void) } static void test_tuntap(struct bpf_program *xdp_prog, - struct bpf_program *tc_prog, + struct bpf_program *tc_prio_1_prog, + struct bpf_program *tc_prio_2_prog, struct bpf_map *result_map) { LIBBPF_OPTS(bpf_tc_hook, tc_hook, .attach_point = BPF_TC_INGRESS); @@ -302,11 +303,20 @@ static void test_tuntap(struct bpf_program *xdp_prog, if (!ASSERT_OK(ret, "bpf_tc_hook_create")) goto close; - tc_opts.prog_fd = bpf_program__fd(tc_prog); + tc_opts.prog_fd = bpf_program__fd(tc_prio_1_prog); ret = bpf_tc_attach(&tc_hook, &tc_opts); if (!ASSERT_OK(ret, "bpf_tc_attach")) goto close; + if (tc_prio_2_prog) { + LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 2, + .prog_fd = bpf_program__fd(tc_prio_2_prog)); + + ret = bpf_tc_attach(&tc_hook, &tc_opts); + if (!ASSERT_OK(ret, "bpf_tc_attach")) + goto close; + } + ret = bpf_xdp_attach(tap_ifindex, bpf_program__fd(xdp_prog), 0, NULL); if (!ASSERT_GE(ret, 0, "bpf_xdp_attach")) @@ -341,13 +351,29 @@ void test_xdp_context_tuntap(void) return; if (test__start_subtest("data_meta")) - test_tuntap(skel->progs.ing_xdp, skel->progs.ing_cls, + test_tuntap(skel->progs.ing_xdp, + skel->progs.ing_cls, + NULL, /* tc prio 2 */ skel->maps.test_result); if (test__start_subtest("dynptr_read")) - test_tuntap(skel->progs.ing_xdp, skel->progs.ing_cls_dynptr_read, + test_tuntap(skel->progs.ing_xdp, + skel->progs.ing_cls_dynptr_read, + NULL, /* tc prio 2 */ skel->maps.test_result); if (test__start_subtest("dynptr_slice")) - test_tuntap(skel->progs.ing_xdp, skel->progs.ing_cls_dynptr_slice, + test_tuntap(skel->progs.ing_xdp, + skel->progs.ing_cls_dynptr_slice, + NULL, /* tc prio 2 */ + skel->maps.test_result); + if (test__start_subtest("dynptr_write")) + test_tuntap(skel->progs.ing_xdp_zalloc_meta, + skel->progs.ing_cls_dynptr_write, + skel->progs.ing_cls_dynptr_read, + skel->maps.test_result); + if (test__start_subtest("dynptr_slice_rdwr")) + test_tuntap(skel->progs.ing_xdp_zalloc_meta, + skel->progs.ing_cls_dynptr_slice_rdwr, + skel->progs.ing_cls_dynptr_slice, skel->maps.test_result); test_xdp_meta__destroy(skel); diff --git a/tools/testing/selftests/bpf/progs/test_xdp_meta.c b/tools/testing/selftests/bpf/progs/test_xdp_meta.c index 0ba647fb1b1d..e7879860f403 100644 --- a/tools/testing/selftests/bpf/progs/test_xdp_meta.c +++ b/tools/testing/selftests/bpf/progs/test_xdp_meta.c @@ -60,6 +60,24 @@ int ing_cls_dynptr_read(struct __sk_buff *ctx) return TC_ACT_SHOT; } +/* Write to metadata using bpf_dynptr_write helper */ +SEC("tc") +int ing_cls_dynptr_write(struct __sk_buff *ctx) +{ + struct bpf_dynptr data, meta; + __u8 *src; + + bpf_dynptr_from_skb(ctx, 0, &data); + src = bpf_dynptr_slice(&data, sizeof(struct ethhdr), NULL, META_SIZE); + if (!src) + return TC_ACT_SHOT; + + bpf_dynptr_from_skb_meta(ctx, 0, &meta); + bpf_dynptr_write(&meta, 0, src, META_SIZE, 0); + + return TC_ACT_UNSPEC; /* pass */ +} + /* Read from metadata using read-only dynptr slice */ SEC("tc") int ing_cls_dynptr_slice(struct __sk_buff *ctx) @@ -82,6 +100,55 @@ int ing_cls_dynptr_slice(struct __sk_buff *ctx) return TC_ACT_SHOT; } +/* Write to metadata using writeable dynptr slice */ +SEC("tc") +int ing_cls_dynptr_slice_rdwr(struct __sk_buff *ctx) +{ + struct bpf_dynptr data, meta; + __u8 *src, *dst; + + bpf_dynptr_from_skb(ctx, 0, &data); + src = bpf_dynptr_slice(&data, sizeof(struct ethhdr), NULL, META_SIZE); + if (!src) + return TC_ACT_SHOT; + + bpf_dynptr_from_skb_meta(ctx, 0, &meta); + dst = bpf_dynptr_slice_rdwr(&meta, 0, NULL, META_SIZE); + if (!dst) + return TC_ACT_SHOT; + + __builtin_memcpy(dst, src, META_SIZE); + + return TC_ACT_UNSPEC; /* pass */ +} + +/* Reserve and clear space for metadata but don't populate it */ +SEC("xdp") +int ing_xdp_zalloc_meta(struct xdp_md *ctx) +{ + struct ethhdr *eth = ctx_ptr(ctx, data); + __u8 *meta; + int ret; + + /* Drop any non-test packets */ + if (eth + 1 > ctx_ptr(ctx, data_end)) + return XDP_DROP; + if (eth->h_proto != 0) + return XDP_DROP; + + ret = bpf_xdp_adjust_meta(ctx, -META_SIZE); + if (ret < 0) + return XDP_DROP; + + meta = ctx_ptr(ctx, data_meta); + if (meta + META_SIZE > ctx_ptr(ctx, data)) + return XDP_DROP; + + __builtin_memset(meta, 0, META_SIZE); + + return XDP_PASS; +} + SEC("xdp") int ing_xdp(struct xdp_md *ctx) { From bd1b51b319788cbc5769a44f0081a1cb012f8ae4 Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Thu, 14 Aug 2025 11:59:34 +0200 Subject: [PATCH 01227/11391] selftests/bpf: Cover read/write to skb metadata at an offset Exercise r/w access to skb metadata through an offset-adjusted dynptr, read/write helper with an offset argument, and a slice starting at an offset. Also check for the expected errors when the offset is out of bounds. Signed-off-by: Jakub Sitnicki Signed-off-by: Martin KaFai Lau Reviewed-by: Jesse Brandeburg Acked-by: Eduard Zingerman Link: https://patch.msgid.link/20250814-skb-metadata-thru-dynptr-v7-8-8a39e636e0fb@cloudflare.com --- .../bpf/prog_tests/xdp_context_test_run.c | 10 ++ .../selftests/bpf/progs/test_xdp_meta.c | 119 ++++++++++++++++++ 2 files changed, 129 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c b/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c index 79c4c58276e6..24a7b4b7fdb6 100644 --- a/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c +++ b/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c @@ -375,6 +375,16 @@ void test_xdp_context_tuntap(void) skel->progs.ing_cls_dynptr_slice_rdwr, skel->progs.ing_cls_dynptr_slice, skel->maps.test_result); + if (test__start_subtest("dynptr_offset")) + test_tuntap(skel->progs.ing_xdp_zalloc_meta, + skel->progs.ing_cls_dynptr_offset_wr, + skel->progs.ing_cls_dynptr_offset_rd, + skel->maps.test_result); + if (test__start_subtest("dynptr_offset_oob")) + test_tuntap(skel->progs.ing_xdp, + skel->progs.ing_cls_dynptr_offset_oob, + skel->progs.ing_cls, + skel->maps.test_result); test_xdp_meta__destroy(skel); } diff --git a/tools/testing/selftests/bpf/progs/test_xdp_meta.c b/tools/testing/selftests/bpf/progs/test_xdp_meta.c index e7879860f403..ee3d8adf5e9c 100644 --- a/tools/testing/selftests/bpf/progs/test_xdp_meta.c +++ b/tools/testing/selftests/bpf/progs/test_xdp_meta.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -122,6 +123,124 @@ int ing_cls_dynptr_slice_rdwr(struct __sk_buff *ctx) return TC_ACT_UNSPEC; /* pass */ } +/* Read skb metadata in chunks from various offsets in different ways. */ +SEC("tc") +int ing_cls_dynptr_offset_rd(struct __sk_buff *ctx) +{ + struct bpf_dynptr meta; + const __u32 chunk_len = META_SIZE / 4; + const __u32 zero = 0; + __u8 *dst, *src; + + dst = bpf_map_lookup_elem(&test_result, &zero); + if (!dst) + return TC_ACT_SHOT; + + /* 1. Regular read */ + bpf_dynptr_from_skb_meta(ctx, 0, &meta); + bpf_dynptr_read(dst, chunk_len, &meta, 0, 0); + dst += chunk_len; + + /* 2. Read from an offset-adjusted dynptr */ + bpf_dynptr_adjust(&meta, chunk_len, bpf_dynptr_size(&meta)); + bpf_dynptr_read(dst, chunk_len, &meta, 0, 0); + dst += chunk_len; + + /* 3. Read at an offset */ + bpf_dynptr_read(dst, chunk_len, &meta, chunk_len, 0); + dst += chunk_len; + + /* 4. Read from a slice starting at an offset */ + src = bpf_dynptr_slice(&meta, 2 * chunk_len, NULL, chunk_len); + if (!src) + return TC_ACT_SHOT; + __builtin_memcpy(dst, src, chunk_len); + + return TC_ACT_SHOT; +} + +/* Write skb metadata in chunks at various offsets in different ways. */ +SEC("tc") +int ing_cls_dynptr_offset_wr(struct __sk_buff *ctx) +{ + const __u32 chunk_len = META_SIZE / 4; + __u8 payload[META_SIZE]; + struct bpf_dynptr meta; + __u8 *dst, *src; + + bpf_skb_load_bytes(ctx, sizeof(struct ethhdr), payload, sizeof(payload)); + src = payload; + + /* 1. Regular write */ + bpf_dynptr_from_skb_meta(ctx, 0, &meta); + bpf_dynptr_write(&meta, 0, src, chunk_len, 0); + src += chunk_len; + + /* 2. Write to an offset-adjusted dynptr */ + bpf_dynptr_adjust(&meta, chunk_len, bpf_dynptr_size(&meta)); + bpf_dynptr_write(&meta, 0, src, chunk_len, 0); + src += chunk_len; + + /* 3. Write at an offset */ + bpf_dynptr_write(&meta, chunk_len, src, chunk_len, 0); + src += chunk_len; + + /* 4. Write to a slice starting at an offset */ + dst = bpf_dynptr_slice_rdwr(&meta, 2 * chunk_len, NULL, chunk_len); + if (!dst) + return TC_ACT_SHOT; + __builtin_memcpy(dst, src, chunk_len); + + return TC_ACT_UNSPEC; /* pass */ +} + +/* Pass an OOB offset to dynptr read, write, adjust, slice. */ +SEC("tc") +int ing_cls_dynptr_offset_oob(struct __sk_buff *ctx) +{ + struct bpf_dynptr meta; + __u8 md, *p; + int err; + + err = bpf_dynptr_from_skb_meta(ctx, 0, &meta); + if (err) + goto fail; + + /* read offset OOB */ + err = bpf_dynptr_read(&md, sizeof(md), &meta, META_SIZE, 0); + if (err != -E2BIG) + goto fail; + + /* write offset OOB */ + err = bpf_dynptr_write(&meta, META_SIZE, &md, sizeof(md), 0); + if (err != -E2BIG) + goto fail; + + /* adjust end offset OOB */ + err = bpf_dynptr_adjust(&meta, 0, META_SIZE + 1); + if (err != -ERANGE) + goto fail; + + /* adjust start offset OOB */ + err = bpf_dynptr_adjust(&meta, META_SIZE + 1, META_SIZE + 1); + if (err != -ERANGE) + goto fail; + + /* slice offset OOB */ + p = bpf_dynptr_slice(&meta, META_SIZE, NULL, sizeof(*p)); + if (p) + goto fail; + + /* slice rdwr offset OOB */ + p = bpf_dynptr_slice_rdwr(&meta, META_SIZE, NULL, sizeof(*p)); + if (p) + goto fail; + + return TC_ACT_UNSPEC; +fail: + return TC_ACT_SHOT; +} + /* Reserve and clear space for metadata but don't populate it */ SEC("xdp") int ing_xdp_zalloc_meta(struct xdp_md *ctx) From 403fae59781fddc699af761f38ed024d3245096b Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Thu, 14 Aug 2025 11:59:35 +0200 Subject: [PATCH 01228/11391] selftests/bpf: Cover metadata access from a modified skb clone Demonstrate that, when processing an skb clone, the metadata gets truncated if the program contains a direct write to either the payload or the metadata, due to an implicit unclone in the prologue, and otherwise the dynptr to the metadata is limited to being read-only. Signed-off-by: Jakub Sitnicki Signed-off-by: Martin KaFai Lau Link: https://patch.msgid.link/20250814-skb-metadata-thru-dynptr-v7-9-8a39e636e0fb@cloudflare.com --- tools/testing/selftests/bpf/config | 1 + .../bpf/prog_tests/xdp_context_test_run.c | 125 +++++++++++- .../selftests/bpf/progs/test_xdp_meta.c | 191 ++++++++++++++++++ 3 files changed, 306 insertions(+), 11 deletions(-) diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config index 8916ab814a3e..70b28c1e653e 100644 --- a/tools/testing/selftests/bpf/config +++ b/tools/testing/selftests/bpf/config @@ -61,6 +61,7 @@ CONFIG_MPLS_IPTUNNEL=y CONFIG_MPLS_ROUTING=y CONFIG_MPTCP=y CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y CONFIG_NET_ACT_SKBMOD=y CONFIG_NET_CLS=y CONFIG_NET_CLS_ACT=y diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c b/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c index 24a7b4b7fdb6..46e0730174ed 100644 --- a/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c +++ b/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c @@ -9,6 +9,7 @@ #define TX_NETNS "xdp_context_tx" #define RX_NETNS "xdp_context_rx" #define TAP_NAME "tap0" +#define DUMMY_NAME "dum0" #define TAP_NETNS "xdp_context_tuntap" #define TEST_PAYLOAD_LEN 32 @@ -156,6 +157,22 @@ static int send_test_packet(int ifindex) return -1; } +static int write_test_packet(int tap_fd) +{ + __u8 packet[sizeof(struct ethhdr) + TEST_PAYLOAD_LEN]; + int n; + + /* The ethernet header doesn't need to be valid for this test */ + memset(packet, 0, sizeof(struct ethhdr)); + memcpy(packet + sizeof(struct ethhdr), test_payload, TEST_PAYLOAD_LEN); + + n = write(tap_fd, packet, sizeof(packet)); + if (!ASSERT_EQ(n, sizeof(packet), "write packet")) + return -1; + + return 0; +} + static void assert_test_result(const struct bpf_map *result_map) { int err; @@ -276,7 +293,6 @@ static void test_tuntap(struct bpf_program *xdp_prog, LIBBPF_OPTS(bpf_tc_hook, tc_hook, .attach_point = BPF_TC_INGRESS); LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1); struct netns_obj *ns = NULL; - __u8 packet[sizeof(struct ethhdr) + TEST_PAYLOAD_LEN]; int tap_fd = -1; int tap_ifindex; int ret; @@ -322,16 +338,8 @@ static void test_tuntap(struct bpf_program *xdp_prog, if (!ASSERT_GE(ret, 0, "bpf_xdp_attach")) goto close; - /* The ethernet header is not relevant for this test and doesn't need to - * be meaningful. - */ - struct ethhdr eth = { 0 }; - - memcpy(packet, ð, sizeof(eth)); - memcpy(packet + sizeof(eth), test_payload, TEST_PAYLOAD_LEN); - - ret = write(tap_fd, packet, sizeof(packet)); - if (!ASSERT_EQ(ret, sizeof(packet), "write packet")) + ret = write_test_packet(tap_fd); + if (!ASSERT_OK(ret, "write_test_packet")) goto close; assert_test_result(result_map); @@ -342,6 +350,77 @@ static void test_tuntap(struct bpf_program *xdp_prog, netns_free(ns); } +/* Write a packet to a tap dev and copy it to ingress of a dummy dev */ +static void test_tuntap_mirred(struct bpf_program *xdp_prog, + struct bpf_program *tc_prog, + bool *test_pass) +{ + LIBBPF_OPTS(bpf_tc_hook, tc_hook, .attach_point = BPF_TC_INGRESS); + LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1); + struct netns_obj *ns = NULL; + int dummy_ifindex; + int tap_fd = -1; + int tap_ifindex; + int ret; + + *test_pass = false; + + ns = netns_new(TAP_NETNS, true); + if (!ASSERT_OK_PTR(ns, "netns_new")) + return; + + /* Setup dummy interface */ + SYS(close, "ip link add name " DUMMY_NAME " type dummy"); + SYS(close, "ip link set dev " DUMMY_NAME " up"); + + dummy_ifindex = if_nametoindex(DUMMY_NAME); + if (!ASSERT_GE(dummy_ifindex, 0, "if_nametoindex")) + goto close; + + tc_hook.ifindex = dummy_ifindex; + ret = bpf_tc_hook_create(&tc_hook); + if (!ASSERT_OK(ret, "bpf_tc_hook_create")) + goto close; + + tc_opts.prog_fd = bpf_program__fd(tc_prog); + ret = bpf_tc_attach(&tc_hook, &tc_opts); + if (!ASSERT_OK(ret, "bpf_tc_attach")) + goto close; + + /* Setup TAP interface */ + tap_fd = open_tuntap(TAP_NAME, true); + if (!ASSERT_GE(tap_fd, 0, "open_tuntap")) + goto close; + + SYS(close, "ip link set dev " TAP_NAME " up"); + + tap_ifindex = if_nametoindex(TAP_NAME); + if (!ASSERT_GE(tap_ifindex, 0, "if_nametoindex")) + goto close; + + ret = bpf_xdp_attach(tap_ifindex, bpf_program__fd(xdp_prog), 0, NULL); + if (!ASSERT_GE(ret, 0, "bpf_xdp_attach")) + goto close; + + /* Copy all packets received from TAP to dummy ingress */ + SYS(close, "tc qdisc add dev " TAP_NAME " clsact"); + SYS(close, "tc filter add dev " TAP_NAME " ingress " + "protocol all matchall " + "action mirred ingress mirror dev " DUMMY_NAME); + + /* Receive a packet on TAP */ + ret = write_test_packet(tap_fd); + if (!ASSERT_OK(ret, "write_test_packet")) + goto close; + + ASSERT_TRUE(*test_pass, "test_pass"); + +close: + if (tap_fd >= 0) + close(tap_fd); + netns_free(ns); +} + void test_xdp_context_tuntap(void) { struct test_xdp_meta *skel = NULL; @@ -385,6 +464,30 @@ void test_xdp_context_tuntap(void) skel->progs.ing_cls_dynptr_offset_oob, skel->progs.ing_cls, skel->maps.test_result); + if (test__start_subtest("clone_data_meta_empty_on_data_write")) + test_tuntap_mirred(skel->progs.ing_xdp, + skel->progs.clone_data_meta_empty_on_data_write, + &skel->bss->test_pass); + if (test__start_subtest("clone_data_meta_empty_on_meta_write")) + test_tuntap_mirred(skel->progs.ing_xdp, + skel->progs.clone_data_meta_empty_on_meta_write, + &skel->bss->test_pass); + if (test__start_subtest("clone_dynptr_empty_on_data_slice_write")) + test_tuntap_mirred(skel->progs.ing_xdp, + skel->progs.clone_dynptr_empty_on_data_slice_write, + &skel->bss->test_pass); + if (test__start_subtest("clone_dynptr_empty_on_meta_slice_write")) + test_tuntap_mirred(skel->progs.ing_xdp, + skel->progs.clone_dynptr_empty_on_meta_slice_write, + &skel->bss->test_pass); + if (test__start_subtest("clone_dynptr_rdonly_before_data_dynptr_write")) + test_tuntap_mirred(skel->progs.ing_xdp, + skel->progs.clone_dynptr_rdonly_before_data_dynptr_write, + &skel->bss->test_pass); + if (test__start_subtest("clone_dynptr_rdonly_before_meta_dynptr_write")) + test_tuntap_mirred(skel->progs.ing_xdp, + skel->progs.clone_dynptr_rdonly_before_meta_dynptr_write, + &skel->bss->test_pass); test_xdp_meta__destroy(skel); } diff --git a/tools/testing/selftests/bpf/progs/test_xdp_meta.c b/tools/testing/selftests/bpf/progs/test_xdp_meta.c index ee3d8adf5e9c..d79cb74b571e 100644 --- a/tools/testing/selftests/bpf/progs/test_xdp_meta.c +++ b/tools/testing/selftests/bpf/progs/test_xdp_meta.c @@ -26,6 +26,8 @@ struct { __uint(value_size, META_SIZE); } test_result SEC(".maps"); +bool test_pass; + SEC("tc") int ing_cls(struct __sk_buff *ctx) { @@ -301,4 +303,193 @@ int ing_xdp(struct xdp_md *ctx) return XDP_PASS; } +/* + * Check that skb->data_meta..skb->data is empty if prog writes to packet + * _payload_ using packet pointers. Applies only to cloned skbs. + */ +SEC("tc") +int clone_data_meta_empty_on_data_write(struct __sk_buff *ctx) +{ + struct ethhdr *eth = ctx_ptr(ctx, data); + + if (eth + 1 > ctx_ptr(ctx, data_end)) + goto out; + /* Ignore non-test packets */ + if (eth->h_proto != 0) + goto out; + + /* Expect no metadata */ + if (ctx->data_meta != ctx->data) + goto out; + + /* Packet write to trigger unclone in prologue */ + eth->h_proto = 42; + + test_pass = true; +out: + return TC_ACT_SHOT; +} + +/* + * Check that skb->data_meta..skb->data is empty if prog writes to packet + * _metadata_ using packet pointers. Applies only to cloned skbs. + */ +SEC("tc") +int clone_data_meta_empty_on_meta_write(struct __sk_buff *ctx) +{ + struct ethhdr *eth = ctx_ptr(ctx, data); + __u8 *md = ctx_ptr(ctx, data_meta); + + if (eth + 1 > ctx_ptr(ctx, data_end)) + goto out; + /* Ignore non-test packets */ + if (eth->h_proto != 0) + goto out; + + if (md + 1 > ctx_ptr(ctx, data)) { + /* Expect no metadata */ + test_pass = true; + } else { + /* Metadata write to trigger unclone in prologue */ + *md = 42; + } +out: + return TC_ACT_SHOT; +} + +/* + * Check that skb_meta dynptr is writable but empty if prog writes to packet + * _payload_ using a dynptr slice. Applies only to cloned skbs. + */ +SEC("tc") +int clone_dynptr_empty_on_data_slice_write(struct __sk_buff *ctx) +{ + struct bpf_dynptr data, meta; + struct ethhdr *eth; + + bpf_dynptr_from_skb(ctx, 0, &data); + eth = bpf_dynptr_slice_rdwr(&data, 0, NULL, sizeof(*eth)); + if (!eth) + goto out; + /* Ignore non-test packets */ + if (eth->h_proto != 0) + goto out; + + /* Expect no metadata */ + bpf_dynptr_from_skb_meta(ctx, 0, &meta); + if (bpf_dynptr_is_rdonly(&meta) || bpf_dynptr_size(&meta) > 0) + goto out; + + /* Packet write to trigger unclone in prologue */ + eth->h_proto = 42; + + test_pass = true; +out: + return TC_ACT_SHOT; +} + +/* + * Check that skb_meta dynptr is writable but empty if prog writes to packet + * _metadata_ using a dynptr slice. Applies only to cloned skbs. + */ +SEC("tc") +int clone_dynptr_empty_on_meta_slice_write(struct __sk_buff *ctx) +{ + struct bpf_dynptr data, meta; + const struct ethhdr *eth; + __u8 *md; + + bpf_dynptr_from_skb(ctx, 0, &data); + eth = bpf_dynptr_slice(&data, 0, NULL, sizeof(*eth)); + if (!eth) + goto out; + /* Ignore non-test packets */ + if (eth->h_proto != 0) + goto out; + + /* Expect no metadata */ + bpf_dynptr_from_skb_meta(ctx, 0, &meta); + if (bpf_dynptr_is_rdonly(&meta) || bpf_dynptr_size(&meta) > 0) + goto out; + + /* Metadata write to trigger unclone in prologue */ + bpf_dynptr_from_skb_meta(ctx, 0, &meta); + md = bpf_dynptr_slice_rdwr(&meta, 0, NULL, sizeof(*md)); + if (md) + *md = 42; + + test_pass = true; +out: + return TC_ACT_SHOT; +} + +/* + * Check that skb_meta dynptr is read-only before prog writes to packet payload + * using dynptr_write helper. Applies only to cloned skbs. + */ +SEC("tc") +int clone_dynptr_rdonly_before_data_dynptr_write(struct __sk_buff *ctx) +{ + struct bpf_dynptr data, meta; + const struct ethhdr *eth; + + bpf_dynptr_from_skb(ctx, 0, &data); + eth = bpf_dynptr_slice(&data, 0, NULL, sizeof(*eth)); + if (!eth) + goto out; + /* Ignore non-test packets */ + if (eth->h_proto != 0) + goto out; + + /* Expect read-only metadata before unclone */ + bpf_dynptr_from_skb_meta(ctx, 0, &meta); + if (!bpf_dynptr_is_rdonly(&meta) || bpf_dynptr_size(&meta) != META_SIZE) + goto out; + + /* Helper write to payload will unclone the packet */ + bpf_dynptr_write(&data, offsetof(struct ethhdr, h_proto), "x", 1, 0); + + /* Expect no metadata after unclone */ + bpf_dynptr_from_skb_meta(ctx, 0, &meta); + if (bpf_dynptr_is_rdonly(&meta) || bpf_dynptr_size(&meta) != 0) + goto out; + + test_pass = true; +out: + return TC_ACT_SHOT; +} + +/* + * Check that skb_meta dynptr is read-only if prog writes to packet + * metadata using dynptr_write helper. Applies only to cloned skbs. + */ +SEC("tc") +int clone_dynptr_rdonly_before_meta_dynptr_write(struct __sk_buff *ctx) +{ + struct bpf_dynptr data, meta; + const struct ethhdr *eth; + + bpf_dynptr_from_skb(ctx, 0, &data); + eth = bpf_dynptr_slice(&data, 0, NULL, sizeof(*eth)); + if (!eth) + goto out; + /* Ignore non-test packets */ + if (eth->h_proto != 0) + goto out; + + /* Expect read-only metadata */ + bpf_dynptr_from_skb_meta(ctx, 0, &meta); + if (!bpf_dynptr_is_rdonly(&meta) || bpf_dynptr_size(&meta) != META_SIZE) + goto out; + + /* Metadata write. Expect failure. */ + bpf_dynptr_from_skb_meta(ctx, 0, &meta); + if (bpf_dynptr_write(&meta, 0, "x", 1, 0) != -EINVAL) + goto out; + + test_pass = true; +out: + return TC_ACT_SHOT; +} + char _license[] SEC("license") = "GPL"; From 2d0ec4a9319c5207fdd2359e8543ef35012e8d4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 13 Aug 2025 07:43:40 +0200 Subject: [PATCH 01229/11391] kbuild: userprogs: avoid duplication of flags inherited from kernel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The duplication makes maintenance harder. Changes need to be done in two places and the lines will grow overly long. Use an intermediary variable instead. Signed-off-by: Thomas Weißschuh Reviewed-by: Nicolas Schier Acked-by: Masahiro Yamada Link: https://lore.kernel.org/r/20250813-kbuild-userprogs-bits-v1-1-2d9f7f411083@linutronix.de Signed-off-by: Nathan Chancellor --- Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 6630a66659c6..3e8544b11520 100644 --- a/Makefile +++ b/Makefile @@ -1135,8 +1135,9 @@ LDFLAGS_vmlinux += --emit-relocs --discard-none endif # Align the bit size of userspace programs with the kernel -KBUILD_USERCFLAGS += $(filter -m32 -m64 --target=%, $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS)) -KBUILD_USERLDFLAGS += $(filter -m32 -m64 --target=%, $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS)) +USERFLAGS_FROM_KERNEL := -m32 -m64 --target=% +KBUILD_USERCFLAGS += $(filter $(USERFLAGS_FROM_KERNEL), $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS)) +KBUILD_USERLDFLAGS += $(filter $(USERFLAGS_FROM_KERNEL), $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS)) # userspace programs are linked via the compiler, use the correct linker ifdef CONFIG_CC_IS_CLANG From 35883b030c5f19f12c7fe53319c93cb740e476be Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 11 Aug 2025 18:16:48 +0200 Subject: [PATCH 01230/11391] kconfig: nconf: Format and print 'line' without a temporary copy Use "%.*s" as the format specifier and supply the 'line' length 'len' to mvwprintw() to format and print each line without making a temporary copy. Remove the temporary buffer. Signed-off-by: Thorsten Blum Reviewed-by: Nicolas Schier Link: https://lore.kernel.org/r/20250811161650.37428-2-thorsten.blum@linux.dev Signed-off-by: Nathan Chancellor --- scripts/kconfig/nconf.gui.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/scripts/kconfig/nconf.gui.c b/scripts/kconfig/nconf.gui.c index 7206437e784a..2d097bc7ef1a 100644 --- a/scripts/kconfig/nconf.gui.c +++ b/scripts/kconfig/nconf.gui.c @@ -173,12 +173,10 @@ void fill_window(WINDOW *win, const char *text) /* do not go over end of line */ total_lines = min(total_lines, y); for (i = 0; i < total_lines; i++) { - char tmp[x+10]; const char *line = get_line(text, i); - int len = get_line_length(line); - strncpy(tmp, line, min(len, x)); - tmp[len] = '\0'; - mvwprintw(win, i, 0, "%s", tmp); + int len = min(get_line_length(line), x); + + mvwprintw(win, i, 0, "%.*s", len, line); } } From 75a6b4595daa569bbc2899eef40372fc013b2d73 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 12 Aug 2025 15:35:02 -0700 Subject: [PATCH 01231/11391] kconfig: qconf/xconfig: show the OptionsMode radio button setting at startup When qconf (xconfig) exits, it saves the current Option settings for Show Name, Show Debug Info, and Show {Normal|All|Prompt} Options. When it is next run, it loads these Option settings from its config file. It correctly shows the flag settings for Show Name and Show Debug Info, but it does not show which of the 3 Show...Options is set. This can lead to confusing output, e.g., if the user thinks that xconfig is in Show All Options mode but kconfig options which have an unmet dependency are still being listed. Add code to show the radio button for the current Show...Options mode during startup so that it will reflect the current config setting. Signed-off-by: Randy Dunlap Tested-by: Nicolas Schier Acked-by: Nicolas Schier Link: https://lore.kernel.org/r/20250812223502.1356426-1-rdunlap@infradead.org Signed-off-by: Nathan Chancellor --- scripts/kconfig/qconf.cc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index f8992db1870a..b84c9f2485d1 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -1377,6 +1377,19 @@ ConfigMainWindow::ConfigMainWindow(void) ConfigList::showPromptAction = new QAction("Show Prompt Options", optGroup); ConfigList::showPromptAction->setCheckable(true); + switch (configList->optMode) { + case allOpt: + ConfigList::showAllAction->setChecked(true); + break; + case promptOpt: + ConfigList::showPromptAction->setChecked(true); + break; + case normalOpt: + default: + ConfigList::showNormalAction->setChecked(true); + break; + } + QAction *showDebugAction = new QAction("Show Debug Info", this); showDebugAction->setCheckable(true); connect(showDebugAction, &QAction::toggled, From f1bbfc405e3d36545f4fd1931c3e1d32396d1b63 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Mon, 18 Aug 2025 11:12:22 +0300 Subject: [PATCH 01232/11391] 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 01233/11391] 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 01234/11391] 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 01235/11391] 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 01236/11391] 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 e73f759d2e98c729ca6f98dad4ca6d7b9120e576 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Fri, 15 Aug 2025 11:56:03 +0800 Subject: [PATCH 01237/11391] security: use umax() to improve code Use umax() to reduce the code in update_mmap_min_addr() and improve its readability. Signed-off-by: Qianfeng Rong [PM: subj line tweak] Signed-off-by: Paul Moore --- security/min_addr.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/security/min_addr.c b/security/min_addr.c index df1bc643d886..c55bb84b8632 100644 --- a/security/min_addr.c +++ b/security/min_addr.c @@ -3,6 +3,7 @@ #include #include #include +#include /* amount of vm to protect from userspace access by both DAC and the LSM*/ unsigned long mmap_min_addr; @@ -16,10 +17,7 @@ unsigned long dac_mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR; static void update_mmap_min_addr(void) { #ifdef CONFIG_LSM_MMAP_MIN_ADDR - if (dac_mmap_min_addr > CONFIG_LSM_MMAP_MIN_ADDR) - mmap_min_addr = dac_mmap_min_addr; - else - mmap_min_addr = CONFIG_LSM_MMAP_MIN_ADDR; + mmap_min_addr = umax(dac_mmap_min_addr, CONFIG_LSM_MMAP_MIN_ADDR); #else mmap_min_addr = dac_mmap_min_addr; #endif From aaa75cbd5d4f63e4edf8b74118d367361dcf92f7 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Sat, 16 Aug 2025 16:44:44 +0800 Subject: [PATCH 01238/11391] 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 01239/11391] 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 01240/11391] 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 01241/11391] 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 01242/11391] 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 01243/11391] 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 7f059e47326746ceebe2a984bd6124459df3b458 Mon Sep 17 00:00:00 2001 From: Akhilesh Patil Date: Sat, 16 Aug 2025 11:49:54 +0530 Subject: [PATCH 01244/11391] fwctl/mlx5: Fix memory alloc/free in mlx5ctl_fw_rpc() Use kvfree() to free memory allocated by kvzalloc() instead of kfree(). Avoid potential memory management issue considering kvzalloc() can internally choose to use either kmalloc() or vmalloc() based on memory request and current system memory state. Hence, use more appropriate kvfree() which automatically determines correct free method to avoid potential hard to debug memory issues. Fix this issue discovered by running spatch static analysis tool using coccinelle script - scripts/coccinelle/api/kfree_mismatch.cocci Fixes: 52929c2142041 ("fwctl/mlx5: Support for communicating with mlx5 fw") Link: https://patch.msgid.link/r/aKAjCoF9cT3VEbSE@bhairav-test.ee.iitb.ac.in Signed-off-by: Akhilesh Patil Reviewed-by: Dave Jiang Reviewed-by: Alison Schofield Signed-off-by: Jason Gunthorpe --- drivers/fwctl/mlx5/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/fwctl/mlx5/main.c b/drivers/fwctl/mlx5/main.c index f93aa0cecdb9..4b379f695eb7 100644 --- a/drivers/fwctl/mlx5/main.c +++ b/drivers/fwctl/mlx5/main.c @@ -345,7 +345,7 @@ static void *mlx5ctl_fw_rpc(struct fwctl_uctx *uctx, enum fwctl_rpc_scope scope, */ if (ret && ret != -EREMOTEIO) { if (rpc_out != rpc_in) - kfree(rpc_out); + kvfree(rpc_out); return ERR_PTR(ret); } return rpc_out; From b826bf795564ddef6402cf2cb522ae035bd117ae Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 13 Aug 2025 11:04:45 +0100 Subject: [PATCH 01245/11391] net: phy: realtek: fix RTL8211F wake-on-lan support Implement Wake-on-Lan for RTL8211F correctly. The existing implementation has multiple issues: 1. It assumes that Wake-on-Lan can always be used, whether or not the interrupt is wired, and whether or not the interrupt is capable of waking the system. This breaks the ability for MAC drivers to detect whether the PHY WoL is functional. 2. switching the interrupt pin in the .set_wol() method to PMEB mode immediately silences link-state interrupts, which breaks phylib when interrupts are being used rather than polling mode. 3. the code claiming to "reset WOL status" was doing nothing of the sort. Bit 15 in page 0xd8a register 17 controls WoL reset, and needs to be pulsed low to reset the WoL state. This bit was always written as '1', resulting in no reset. 4. not resetting WoL state results in the PMEB pin remaining asserted, which in turn leads to an interrupt storm. Only resetting the WoL state in .set_wol() is not sufficient. 5. PMEB mode does not allow software detection of the wake-up event as there is no status bit to indicate we received the WoL packet. 6. across reboots of at least the Jetson Xavier NX system, the WoL configuration is preserved. Fix all of these issues by essentially rewriting the support. We: 1. clear the WoL event enable register at probe time. 2. detect whether we can support wake-up by having a valid interrupt, and the "wakeup-source" property in DT. If we can, then we mark the MDIO device as wakeup capable, and associate the interrupt with the wakeup source. 3. arrange for the get_wol() and set_wol() implementations to handle the case where the MDIO device has not been marked as wakeup capable (thereby returning no WoL support, and refusing to enable WoL support.) 4. avoid switching to PMEB mode, instead using INTB mode with the interrupt enable, reconfiguring the interrupt enables at suspend time, and restoring their original state at resume time (we track the state of the interrupt enable register in .config_intr() register.) 5. move WoL reset from .set_wol() to the suspend function to ensure that WoL state is cleared prior to suspend. This is necessary after the PME interrupt has been enabled as a second WoL packet will not re-raise a previously cleared PME interrupt. 6. when a PME interrupt (for wakeup) is asserted, pass this to the PM wakeup so it knows which device woke the system. This fixes WoL support in the Realtek RTL8211F driver when used on the nVidia Jetson Xavier NX platform, and needs to be applied before stmmac patches which allow these platforms to forward the ethtool WoL commands to the Realtek PHY. Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/E1um8Ld-008jxD-Mc@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/realtek/realtek_main.c | 172 ++++++++++++++++++++----- 1 file changed, 140 insertions(+), 32 deletions(-) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index a7541899e327..904fa8b1aa03 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -31,6 +32,7 @@ #define RTL821x_INER 0x12 #define RTL8211B_INER_INIT 0x6400 #define RTL8211E_INER_LINK_STATUS BIT(10) +#define RTL8211F_INER_PME BIT(7) #define RTL8211F_INER_LINK_STATUS BIT(4) #define RTL821x_INSR 0x13 @@ -96,17 +98,13 @@ #define RTL8211F_RXCR 0x15 #define RTL8211F_RX_DELAY BIT(3) -/* RTL8211F WOL interrupt configuration */ -#define RTL8211F_INTBCR_PAGE 0xd40 -#define RTL8211F_INTBCR 0x16 -#define RTL8211F_INTBCR_INTB_PMEB BIT(5) - /* RTL8211F WOL settings */ -#define RTL8211F_WOL_SETTINGS_PAGE 0xd8a +#define RTL8211F_WOL_PAGE 0xd8a #define RTL8211F_WOL_SETTINGS_EVENTS 16 #define RTL8211F_WOL_EVENT_MAGIC BIT(12) -#define RTL8211F_WOL_SETTINGS_STATUS 17 -#define RTL8211F_WOL_STATUS_RESET (BIT(15) | 0x1fff) +#define RTL8211F_WOL_RST_RMSQ 17 +#define RTL8211F_WOL_RG_RSTB BIT(15) +#define RTL8211F_WOL_RMSQ 0x1fff /* RTL8211F Unique phyiscal and multicast address (WOL) */ #define RTL8211F_PHYSICAL_ADDR_PAGE 0xd8c @@ -172,7 +170,8 @@ struct rtl821x_priv { u16 phycr2; bool has_phycr2; struct clk *clk; - u32 saved_wolopts; + /* rtl8211f */ + u16 iner; }; static int rtl821x_read_page(struct phy_device *phydev) @@ -255,6 +254,34 @@ static int rtl821x_probe(struct phy_device *phydev) return 0; } +static int rtl8211f_probe(struct phy_device *phydev) +{ + struct device *dev = &phydev->mdio.dev; + int ret; + + ret = rtl821x_probe(phydev); + if (ret < 0) + return ret; + + /* Disable all PME events */ + ret = phy_write_paged(phydev, RTL8211F_WOL_PAGE, + RTL8211F_WOL_SETTINGS_EVENTS, 0); + if (ret < 0) + return ret; + + /* Mark this PHY as wakeup capable and register the interrupt as a + * wakeup IRQ if the PHY is marked as a wakeup source in firmware, + * and the interrupt is valid. + */ + if (device_property_read_bool(dev, "wakeup-source") && + phy_interrupt_is_valid(phydev)) { + device_set_wakeup_capable(dev, true); + devm_pm_set_wake_irq(dev, phydev->irq); + } + + return ret; +} + static int rtl8201_ack_interrupt(struct phy_device *phydev) { int err; @@ -352,6 +379,7 @@ static int rtl8211e_config_intr(struct phy_device *phydev) static int rtl8211f_config_intr(struct phy_device *phydev) { + struct rtl821x_priv *priv = phydev->priv; u16 val; int err; @@ -362,8 +390,10 @@ static int rtl8211f_config_intr(struct phy_device *phydev) val = RTL8211F_INER_LINK_STATUS; err = phy_write_paged(phydev, 0xa42, RTL821x_INER, val); + if (err == 0) + priv->iner = val; } else { - val = 0; + priv->iner = val = 0; err = phy_write_paged(phydev, 0xa42, RTL821x_INER, val); if (err) return err; @@ -426,21 +456,34 @@ static irqreturn_t rtl8211f_handle_interrupt(struct phy_device *phydev) return IRQ_NONE; } - if (!(irq_status & RTL8211F_INER_LINK_STATUS)) - return IRQ_NONE; + if (irq_status & RTL8211F_INER_LINK_STATUS) { + phy_trigger_machine(phydev); + return IRQ_HANDLED; + } - phy_trigger_machine(phydev); + if (irq_status & RTL8211F_INER_PME) { + pm_wakeup_event(&phydev->mdio.dev, 0); + return IRQ_HANDLED; + } - return IRQ_HANDLED; + return IRQ_NONE; } static void rtl8211f_get_wol(struct phy_device *dev, struct ethtool_wolinfo *wol) { int wol_events; + /* If the PHY is not capable of waking the system, then WoL can not + * be supported. + */ + if (!device_can_wakeup(&dev->mdio.dev)) { + wol->supported = 0; + return; + } + wol->supported = WAKE_MAGIC; - wol_events = phy_read_paged(dev, RTL8211F_WOL_SETTINGS_PAGE, RTL8211F_WOL_SETTINGS_EVENTS); + wol_events = phy_read_paged(dev, RTL8211F_WOL_PAGE, RTL8211F_WOL_SETTINGS_EVENTS); if (wol_events < 0) return; @@ -453,6 +496,9 @@ static int rtl8211f_set_wol(struct phy_device *dev, struct ethtool_wolinfo *wol) const u8 *mac_addr = dev->attached_dev->dev_addr; int oldpage; + if (!device_can_wakeup(&dev->mdio.dev)) + return -EOPNOTSUPP; + oldpage = phy_save_page(dev); if (oldpage < 0) goto err; @@ -464,25 +510,23 @@ static int rtl8211f_set_wol(struct phy_device *dev, struct ethtool_wolinfo *wol) __phy_write(dev, RTL8211F_PHYSICAL_ADDR_WORD1, mac_addr[3] << 8 | (mac_addr[2])); __phy_write(dev, RTL8211F_PHYSICAL_ADDR_WORD2, mac_addr[5] << 8 | (mac_addr[4])); - /* Enable magic packet matching and reset WOL status */ - rtl821x_write_page(dev, RTL8211F_WOL_SETTINGS_PAGE); + /* Enable magic packet matching */ + rtl821x_write_page(dev, RTL8211F_WOL_PAGE); __phy_write(dev, RTL8211F_WOL_SETTINGS_EVENTS, RTL8211F_WOL_EVENT_MAGIC); - __phy_write(dev, RTL8211F_WOL_SETTINGS_STATUS, RTL8211F_WOL_STATUS_RESET); - - /* Enable the WOL interrupt */ - rtl821x_write_page(dev, RTL8211F_INTBCR_PAGE); - __phy_set_bits(dev, RTL8211F_INTBCR, RTL8211F_INTBCR_INTB_PMEB); + /* Set the maximum packet size, and assert WoL reset */ + __phy_write(dev, RTL8211F_WOL_RST_RMSQ, RTL8211F_WOL_RMSQ); } else { - /* Disable the WOL interrupt */ - rtl821x_write_page(dev, RTL8211F_INTBCR_PAGE); - __phy_clear_bits(dev, RTL8211F_INTBCR, RTL8211F_INTBCR_INTB_PMEB); - - /* Disable magic packet matching and reset WOL status */ - rtl821x_write_page(dev, RTL8211F_WOL_SETTINGS_PAGE); + /* Disable magic packet matching */ + rtl821x_write_page(dev, RTL8211F_WOL_PAGE); __phy_write(dev, RTL8211F_WOL_SETTINGS_EVENTS, 0); - __phy_write(dev, RTL8211F_WOL_SETTINGS_STATUS, RTL8211F_WOL_STATUS_RESET); + + /* Place WoL in reset */ + __phy_clear_bits(dev, RTL8211F_WOL_RST_RMSQ, + RTL8211F_WOL_RG_RSTB); } + device_set_wakeup_enable(&dev->mdio.dev, !!(wol->wolopts & WAKE_MAGIC)); + err: return phy_restore_page(dev, oldpage, 0); } @@ -628,6 +672,52 @@ static int rtl821x_suspend(struct phy_device *phydev) return ret; } +static int rtl8211f_suspend(struct phy_device *phydev) +{ + u16 wol_rst; + int ret; + + ret = rtl821x_suspend(phydev); + if (ret < 0) + return ret; + + /* If a PME event is enabled, then configure the interrupt for + * PME events only, disabling link interrupt. We avoid switching + * to PMEB mode as we don't have a status bit for that. + */ + if (device_may_wakeup(&phydev->mdio.dev)) { + ret = phy_write_paged(phydev, 0xa42, RTL821x_INER, + RTL8211F_INER_PME); + if (ret < 0) + goto err; + + /* Read the INSR to clear any pending interrupt */ + phy_read_paged(phydev, RTL8211F_INSR_PAGE, RTL8211F_INSR); + + /* Reset the WoL to ensure that an event is picked up. + * Unless we do this, even if we receive another packet, + * we may not have a PME interrupt raised. + */ + ret = phy_read_paged(phydev, RTL8211F_WOL_PAGE, + RTL8211F_WOL_RST_RMSQ); + if (ret < 0) + goto err; + + wol_rst = ret & ~RTL8211F_WOL_RG_RSTB; + ret = phy_write_paged(phydev, RTL8211F_WOL_PAGE, + RTL8211F_WOL_RST_RMSQ, wol_rst); + if (ret < 0) + goto err; + + wol_rst |= RTL8211F_WOL_RG_RSTB; + ret = phy_write_paged(phydev, RTL8211F_WOL_PAGE, + RTL8211F_WOL_RST_RMSQ, wol_rst); + } + +err: + return ret; +} + static int rtl821x_resume(struct phy_device *phydev) { struct rtl821x_priv *priv = phydev->priv; @@ -645,6 +735,24 @@ static int rtl821x_resume(struct phy_device *phydev) return 0; } +static int rtl8211f_resume(struct phy_device *phydev) +{ + struct rtl821x_priv *priv = phydev->priv; + int ret; + + ret = rtl821x_resume(phydev); + if (ret < 0) + return ret; + + /* If the device was programmed for a PME event, restore the interrupt + * enable so phylib can receive link state interrupts. + */ + if (device_may_wakeup(&phydev->mdio.dev)) + ret = phy_write_paged(phydev, 0xa42, RTL821x_INER, priv->iner); + + return ret; +} + static int rtl8211x_led_hw_is_supported(struct phy_device *phydev, u8 index, unsigned long rules) { @@ -1627,15 +1735,15 @@ static struct phy_driver realtek_drvs[] = { }, { PHY_ID_MATCH_EXACT(0x001cc916), .name = "RTL8211F Gigabit Ethernet", - .probe = rtl821x_probe, + .probe = rtl8211f_probe, .config_init = &rtl8211f_config_init, .read_status = rtlgen_read_status, .config_intr = &rtl8211f_config_intr, .handle_interrupt = rtl8211f_handle_interrupt, .set_wol = rtl8211f_set_wol, .get_wol = rtl8211f_get_wol, - .suspend = rtl821x_suspend, - .resume = rtl821x_resume, + .suspend = rtl8211f_suspend, + .resume = rtl8211f_resume, .read_page = rtl821x_read_page, .write_page = rtl821x_write_page, .flags = PHY_ALWAYS_CALL_SUSPEND, From a510980e740cc58be5733d4c15b22c7822e84c71 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 13 Aug 2025 12:21:19 +0100 Subject: [PATCH 01246/11391] dt-bindings: net: realtek,rtl82xx: document wakeup-source property The RTL8211F PHY has two modes for a single INTB/PMEB pin: 1. INTB mode, where it signals interrupts to the CPU, which can include wake-on-LAN events. 2. PMEB mode, where it only signals a wake-on-LAN event, which may either be a latched logic low until software manually clears the WoL state, or pulsed mode. In the case of (1), there is no way to know whether the interrupt to which the PHY is connected is capable of waking the system. In the case of (2), there would be no interrupt property in the PHY's DT description, and thus there is nothing to describe whether the pin is even wired to anything such as a power management controller. There is a "wakeup-source" property which can be applied to any device - see Documentation/devicetree/bindings/power/wakeup-source.txt Case 1 above matches example 2 in this document, and case 2 above matches example 3. Therefore, it seems reasonable to make use of this existing specification, albiet it hasn't been converted to YAML. Document the wakeup-source property in the device description, which will indicate that the PHY has been wired up in such a way that it can wake the system from a low power state. We will use this in a rewrite of the existing broken Wake-on-Lan code that was merged during the 6.16 merge window to support case 1. Case 2 can be added to the driver later without needing to further alter the DT description. To be clear, the existing Wake-on-Lan code that was recently merged has multiple functional issues. Signed-off-by: Russell King (Oracle) Acked-by: Conor Dooley Link: https://patch.msgid.link/E1um9Xj-008kBx-72@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- Documentation/devicetree/bindings/net/realtek,rtl82xx.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/net/realtek,rtl82xx.yaml b/Documentation/devicetree/bindings/net/realtek,rtl82xx.yaml index d248a08a2136..2b5697bd7c5d 100644 --- a/Documentation/devicetree/bindings/net/realtek,rtl82xx.yaml +++ b/Documentation/devicetree/bindings/net/realtek,rtl82xx.yaml @@ -45,12 +45,16 @@ properties: description: Disable CLKOUT clock, CLKOUT clock default is enabled after hardware reset. - realtek,aldps-enable: type: boolean description: Enable ALDPS mode, ALDPS mode default is disabled after hardware reset. + wakeup-source: + type: boolean + description: + Enable Wake-on-LAN support for the RTL8211F PHY. + unevaluatedProperties: false allOf: From 60cbe71fdba16d39de24bd71e1638810da5ae7ee Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 13 Aug 2025 23:43:03 +0200 Subject: [PATCH 01247/11391] net: dsa: Move KS8995 to the DSA subsystem By reading the datasheets for the KS8995 it is obvious that this is a 100 Mbit DSA switch. Let us start the refactoring by moving it to the DSA subsystem to preserve development history. Verified that the chip still probes the same after this patch provided CONFIG_HAVE_NET_DSA, CONFIG_NET_DSA and CONFIG_DSA_KS8995 are selected. Signed-off-by: Linus Walleij Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20250813-ks8995-to-dsa-v1-1-75c359ede3a5@linaro.org Signed-off-by: Jakub Kicinski --- drivers/net/dsa/Kconfig | 7 +++++++ drivers/net/dsa/Makefile | 1 + drivers/net/{phy/spi_ks8995.c => dsa/ks8995.c} | 0 drivers/net/phy/Kconfig | 4 ---- drivers/net/phy/Makefile | 1 - 5 files changed, 8 insertions(+), 5 deletions(-) rename drivers/net/{phy/spi_ks8995.c => dsa/ks8995.c} (100%) diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig index ec759f8cb0e2..49326a9a0cff 100644 --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig @@ -99,6 +99,13 @@ config NET_DSA_RZN1_A5PSW This driver supports the A5PSW switch, which is embedded in Renesas RZ/N1 SoC. +config NET_DSA_KS8995 + tristate "Micrel KS8995 family 5-ports 10/100 Ethernet switches" + depends on SPI + help + This driver supports the Micrel KS8995 family of 10/100 Mbit ethernet + switches, managed over SPI. + config NET_DSA_SMSC_LAN9303 tristate select NET_DSA_TAG_LAN9303 diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile index cb9a97340e58..23dbdf1a36a8 100644 --- a/drivers/net/dsa/Makefile +++ b/drivers/net/dsa/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_NET_DSA_LOOP) += dsa_loop.o ifdef CONFIG_NET_DSA_LOOP obj-$(CONFIG_FIXED_PHY) += dsa_loop_bdinfo.o endif +obj-$(CONFIG_NET_DSA_KS8995) += ks8995.o obj-$(CONFIG_NET_DSA_LANTIQ_GSWIP) += lantiq_gswip.o obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o obj-$(CONFIG_NET_DSA_MT7530_MDIO) += mt7530-mdio.o diff --git a/drivers/net/phy/spi_ks8995.c b/drivers/net/dsa/ks8995.c similarity index 100% rename from drivers/net/phy/spi_ks8995.c rename to drivers/net/dsa/ks8995.c diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 28acc6392cfc..a7fb1d7cae94 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -465,7 +465,3 @@ config XILINX_GMII2RGMII Ethernet physical media devices and the Gigabit Ethernet controller. endif # PHYLIB - -config MICREL_KS8995MA - tristate "Micrel KS8995MA 5-ports 10/100 managed Ethernet switch" - depends on SPI diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index b4795aaf9c1c..402a33d559de 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -72,7 +72,6 @@ obj-$(CONFIG_MAXLINEAR_GPHY) += mxl-gpy.o obj-$(CONFIG_MAXLINEAR_86110_PHY) += mxl-86110.o obj-y += mediatek/ obj-$(CONFIG_MESON_GXL_PHY) += meson-gxl.o -obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o obj-$(CONFIG_MICREL_PHY) += micrel.o obj-$(CONFIG_MICROCHIP_PHY) += microchip.o obj-$(CONFIG_MICROCHIP_PHY_RDS_PTP) += microchip_rds_ptp.o From ccf29cb84972f97c98ac31f7d6fb1680dc5d3816 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 13 Aug 2025 23:43:04 +0200 Subject: [PATCH 01248/11391] net: dsa: ks8995: Add proper RESET delay According to the datasheet we need to wait 100us before accessing any registers in the KS8995 after a reset de-assertion. Add this delay, if and only if we obtained a GPIO descriptor, otherwise it is just a pointless delay. Signed-off-by: Linus Walleij Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20250813-ks8995-to-dsa-v1-2-75c359ede3a5@linaro.org Signed-off-by: Jakub Kicinski --- drivers/net/dsa/ks8995.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/net/dsa/ks8995.c b/drivers/net/dsa/ks8995.c index d135b061d810..bdee8c62315f 100644 --- a/drivers/net/dsa/ks8995.c +++ b/drivers/net/dsa/ks8995.c @@ -438,9 +438,15 @@ static int ks8995_probe(struct spi_device *spi) if (err) return err; - /* de-assert switch reset */ - /* FIXME: this likely requires a delay */ - gpiod_set_value_cansleep(ks->reset_gpio, 0); + if (ks->reset_gpio) { + /* + * If a reset line was obtained, wait for 100us after + * de-asserting RESET before accessing any registers, see + * the KS8995MA datasheet, page 44. + */ + gpiod_set_value_cansleep(ks->reset_gpio, 0); + udelay(100); + } spi_set_drvdata(spi, ks); From d3f2b604a1f92d9ee63dfd5a2313e0024d184682 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 13 Aug 2025 23:43:05 +0200 Subject: [PATCH 01249/11391] net: dsa: ks8995: Delete sysfs register access There is some sysfs file to read and write registers randomly in the ks8995 driver. The contemporary way to achieve the same thing is to implement regmap abstractions, if needed. Delete this and implement regmap later if we want to be able to inspect individual registers. Signed-off-by: Linus Walleij Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20250813-ks8995-to-dsa-v1-3-75c359ede3a5@linaro.org Signed-off-by: Jakub Kicinski --- drivers/net/dsa/ks8995.c | 47 ---------------------------------------- 1 file changed, 47 deletions(-) diff --git a/drivers/net/dsa/ks8995.c b/drivers/net/dsa/ks8995.c index bdee8c62315f..36f6b2d87712 100644 --- a/drivers/net/dsa/ks8995.c +++ b/drivers/net/dsa/ks8995.c @@ -288,30 +288,6 @@ static int ks8995_reset(struct ks8995_switch *ks) return ks8995_start(ks); } -static ssize_t ks8995_registers_read(struct file *filp, struct kobject *kobj, - const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) -{ - struct device *dev; - struct ks8995_switch *ks8995; - - dev = kobj_to_dev(kobj); - ks8995 = dev_get_drvdata(dev); - - return ks8995_read(ks8995, buf, off, count); -} - -static ssize_t ks8995_registers_write(struct file *filp, struct kobject *kobj, - const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) -{ - struct device *dev; - struct ks8995_switch *ks8995; - - dev = kobj_to_dev(kobj); - ks8995 = dev_get_drvdata(dev); - - return ks8995_write(ks8995, buf, off, count); -} - /* ks8995_get_revision - get chip revision * @ks: pointer to switch instance * @@ -395,16 +371,6 @@ static int ks8995_get_revision(struct ks8995_switch *ks) return err; } -static const struct bin_attribute ks8995_registers_attr = { - .attr = { - .name = "registers", - .mode = 0600, - }, - .size = KS8995_REGS_SIZE, - .read = ks8995_registers_read, - .write = ks8995_registers_write, -}; - /* ------------------------------------------------------------------------ */ static int ks8995_probe(struct spi_device *spi) { @@ -462,21 +428,10 @@ static int ks8995_probe(struct spi_device *spi) if (err) return err; - memcpy(&ks->regs_attr, &ks8995_registers_attr, sizeof(ks->regs_attr)); - ks->regs_attr.size = ks->chip->regs_size; - err = ks8995_reset(ks); if (err) return err; - sysfs_attr_init(&ks->regs_attr.attr); - err = sysfs_create_bin_file(&spi->dev.kobj, &ks->regs_attr); - if (err) { - dev_err(&spi->dev, "unable to create sysfs file, err=%d\n", - err); - return err; - } - dev_info(&spi->dev, "%s device found, Chip ID:%x, Revision:%x\n", ks->chip->name, ks->chip->chip_id, ks->revision_id); @@ -487,8 +442,6 @@ static void ks8995_remove(struct spi_device *spi) { struct ks8995_switch *ks = spi_get_drvdata(spi); - sysfs_remove_bin_file(&spi->dev.kobj, &ks->regs_attr); - /* assert reset */ gpiod_set_value_cansleep(ks->reset_gpio, 1); } From a7fe8b266f659624309c69208be0410584bb9980 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 13 Aug 2025 23:43:06 +0200 Subject: [PATCH 01250/11391] net: dsa: ks8995: Add basic switch set-up We start to extend the KS8995 driver by simply registering it as a DSA device and implementing a few switch callbacks for STP set-up and such to begin with. No special tags or other advanced stuff: we use DSA_TAG_NONE and rely on the default set-up in the switch with the special DSA tags turned off. This makes the switch wire up properly to all its PHY's and simple bridge traffic works properly. After this the bridge DT bindings are respected, ports and their PHYs get connected to the switch and react appropriately through the phylib when cables are plugged in etc. Tested like this in a hacky OpenWrt image: Bring up conduit interface manually: ixp4xx_eth c8009000.ethernet eth0: eth0: link up, speed 100 Mb/s, full duplex spi-ks8995 spi0.0: enable port 0 spi-ks8995 spi0.0: set KS8995_REG_PC2 for port 0 to 06 spi-ks8995 spi0.0 lan1: configuring for phy/mii link mode spi-ks8995 spi0.0 lan1: Link is Up - 100Mbps/Full - flow control rx/tx PING 169.254.1.1 (169.254.1.1): 56 data bytes 64 bytes from 169.254.1.1: seq=0 ttl=64 time=1.629 ms 64 bytes from 169.254.1.1: seq=1 ttl=64 time=0.951 ms I also tested SSH from the device to the host and it works fine. It also works fine to ping the device from the host and to SSH into the device from the host. This brings the ks8995 driver to a reasonable state where it can be used from the current device tree bindings and the existing device trees in the kernel. Signed-off-by: Linus Walleij Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20250813-ks8995-to-dsa-v1-4-75c359ede3a5@linaro.org Signed-off-by: Jakub Kicinski --- drivers/net/dsa/Kconfig | 1 + drivers/net/dsa/ks8995.c | 398 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 396 insertions(+), 3 deletions(-) diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig index 49326a9a0cff..202a35d8d061 100644 --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig @@ -102,6 +102,7 @@ config NET_DSA_RZN1_A5PSW config NET_DSA_KS8995 tristate "Micrel KS8995 family 5-ports 10/100 Ethernet switches" depends on SPI + select NET_DSA_TAG_NONE help This driver supports the Micrel KS8995 family of 10/100 Mbit ethernet switches, managed over SPI. diff --git a/drivers/net/dsa/ks8995.c b/drivers/net/dsa/ks8995.c index 36f6b2d87712..5c4c83e00477 100644 --- a/drivers/net/dsa/ks8995.c +++ b/drivers/net/dsa/ks8995.c @@ -3,6 +3,7 @@ * SPI driver for Micrel/Kendin KS8995M and KSZ8864RMN ethernet switches * * Copyright (C) 2008 Gabor Juhos + * Copyright (C) 2025 Linus Walleij * * This file was based on: drivers/spi/at25.c * Copyright (C) 2006 David Brownell @@ -10,6 +11,9 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include +#include +#include #include #include #include @@ -17,8 +21,8 @@ #include #include #include - #include +#include #define DRV_VERSION "0.1.1" #define DRV_DESC "Micrel KS8995 Ethernet switch SPI driver" @@ -29,18 +33,59 @@ #define KS8995_REG_ID1 0x01 /* Chip ID1 */ #define KS8995_REG_GC0 0x02 /* Global Control 0 */ + +#define KS8995_GC0_P5_PHY BIT(3) /* Port 5 PHY enabled */ + #define KS8995_REG_GC1 0x03 /* Global Control 1 */ #define KS8995_REG_GC2 0x04 /* Global Control 2 */ + +#define KS8995_GC2_HUGE BIT(2) /* Huge packet support */ +#define KS8995_GC2_LEGAL BIT(1) /* Legal size override */ + #define KS8995_REG_GC3 0x05 /* Global Control 3 */ #define KS8995_REG_GC4 0x06 /* Global Control 4 */ + +#define KS8995_GC4_10BT BIT(4) /* Force switch to 10Mbit */ +#define KS8995_GC4_MII_FLOW BIT(5) /* MII full-duplex flow control enable */ +#define KS8995_GC4_MII_HD BIT(6) /* MII half-duplex mode enable */ + #define KS8995_REG_GC5 0x07 /* Global Control 5 */ #define KS8995_REG_GC6 0x08 /* Global Control 6 */ #define KS8995_REG_GC7 0x09 /* Global Control 7 */ #define KS8995_REG_GC8 0x0a /* Global Control 8 */ #define KS8995_REG_GC9 0x0b /* Global Control 9 */ -#define KS8995_REG_PC(p, r) ((0x10 * p) + r) /* Port Control */ -#define KS8995_REG_PS(p, r) ((0x10 * p) + r + 0xe) /* Port Status */ +#define KS8995_GC9_SPECIAL BIT(0) /* Special tagging mode (DSA) */ + +/* In DSA the ports 1-4 are numbered 0-3 and the CPU port is port 4 */ +#define KS8995_REG_PC(p, r) (0x10 + (0x10 * (p)) + (r)) /* Port Control */ +#define KS8995_REG_PS(p, r) (0x1e + (0x10 * (p)) + (r)) /* Port Status */ + +#define KS8995_REG_PC0 0x00 /* Port Control 0 */ +#define KS8995_REG_PC1 0x01 /* Port Control 1 */ +#define KS8995_REG_PC2 0x02 /* Port Control 2 */ +#define KS8995_REG_PC3 0x03 /* Port Control 3 */ +#define KS8995_REG_PC4 0x04 /* Port Control 4 */ +#define KS8995_REG_PC5 0x05 /* Port Control 5 */ +#define KS8995_REG_PC6 0x06 /* Port Control 6 */ +#define KS8995_REG_PC7 0x07 /* Port Control 7 */ +#define KS8995_REG_PC8 0x08 /* Port Control 8 */ +#define KS8995_REG_PC9 0x09 /* Port Control 9 */ +#define KS8995_REG_PC10 0x0a /* Port Control 10 */ +#define KS8995_REG_PC11 0x0b /* Port Control 11 */ +#define KS8995_REG_PC12 0x0c /* Port Control 12 */ +#define KS8995_REG_PC13 0x0d /* Port Control 13 */ + +#define KS8995_PC0_TAG_INS BIT(2) /* Enable tag insertion on port */ +#define KS8995_PC0_TAG_REM BIT(1) /* Enable tag removal on port */ +#define KS8995_PC0_PRIO_EN BIT(0) /* Enable priority handling */ + +#define KS8995_PC2_TXEN BIT(2) /* Enable TX on port */ +#define KS8995_PC2_RXEN BIT(1) /* Enable RX on port */ +#define KS8995_PC2_LEARN_DIS BIT(0) /* Disable learning on port */ + +#define KS8995_PC13_TXDIS BIT(6) /* Disable transmitter */ +#define KS8995_PC13_PWDN BIT(3) /* Power down */ #define KS8995_REG_TPC0 0x60 /* TOS Priority Control 0 */ #define KS8995_REG_TPC1 0x61 /* TOS Priority Control 1 */ @@ -91,6 +136,8 @@ #define KS8995_CMD_WRITE 0x02U #define KS8995_CMD_READ 0x03U +#define KS8995_CPU_PORT 4 +#define KS8995_NUM_PORTS 5 /* 5 ports including the CPU port */ #define KS8995_RESET_DELAY 10 /* usec */ enum ks8995_chip_variant { @@ -138,11 +185,14 @@ static const struct ks8995_chip_params ks8995_chip[] = { struct ks8995_switch { struct spi_device *spi; + struct device *dev; + struct dsa_switch *ds; struct mutex lock; struct gpio_desc *reset_gpio; struct bin_attribute regs_attr; const struct ks8995_chip_params *chip; int revision_id; + unsigned int max_mtu[KS8995_NUM_PORTS]; }; static const struct spi_device_id ks8995_id[] = { @@ -371,6 +421,327 @@ static int ks8995_get_revision(struct ks8995_switch *ks) return err; } +static int ks8995_check_config(struct ks8995_switch *ks) +{ + int ret; + u8 val; + + ret = ks8995_read_reg(ks, KS8995_REG_GC0, &val); + if (ret) { + dev_err(ks->dev, "failed to read KS8995_REG_GC0\n"); + return ret; + } + + dev_dbg(ks->dev, "port 5 PHY %senabled\n", + (val & KS8995_GC0_P5_PHY) ? "" : "not "); + + val |= KS8995_GC0_P5_PHY; + ret = ks8995_write_reg(ks, KS8995_REG_GC0, val); + if (ret) + dev_err(ks->dev, "failed to set KS8995_REG_GC0\n"); + + dev_dbg(ks->dev, "set KS8995_REG_GC0 to 0x%02x\n", val); + + return 0; +} + +static void +ks8995_mac_config(struct phylink_config *config, unsigned int mode, + const struct phylink_link_state *state) +{ +} + +static void +ks8995_mac_link_up(struct phylink_config *config, struct phy_device *phydev, + unsigned int mode, phy_interface_t interface, + int speed, int duplex, bool tx_pause, bool rx_pause) +{ + struct dsa_port *dp = dsa_phylink_to_port(config); + struct ks8995_switch *ks = dp->ds->priv; + int port = dp->index; + int ret; + u8 val; + + /* Allow forcing the mode on the fixed CPU port, no autonegotiation. + * We assume autonegotiation works on the PHY-facing ports. + */ + if (port != KS8995_CPU_PORT) + return; + + dev_dbg(ks->dev, "MAC link up on CPU port (%d)\n", port); + + ret = ks8995_read_reg(ks, KS8995_REG_GC4, &val); + if (ret) { + dev_err(ks->dev, "failed to read KS8995_REG_GC4\n"); + return; + } + + /* Conjure port config */ + switch (speed) { + case SPEED_10: + dev_dbg(ks->dev, "set switch MII to 100Mbit mode\n"); + val |= KS8995_GC4_10BT; + break; + case SPEED_100: + default: + dev_dbg(ks->dev, "set switch MII to 100Mbit mode\n"); + val &= ~KS8995_GC4_10BT; + break; + } + + if (duplex == DUPLEX_HALF) { + dev_dbg(ks->dev, "set switch MII to half duplex\n"); + val |= KS8995_GC4_MII_HD; + } else { + dev_dbg(ks->dev, "set switch MII to full duplex\n"); + val &= ~KS8995_GC4_MII_HD; + } + + dev_dbg(ks->dev, "set KS8995_REG_GC4 to %02x\n", val); + + /* Enable the CPU port */ + ret = ks8995_write_reg(ks, KS8995_REG_GC4, val); + if (ret) + dev_err(ks->dev, "failed to set KS8995_REG_GC4\n"); +} + +static void +ks8995_mac_link_down(struct phylink_config *config, unsigned int mode, + phy_interface_t interface) +{ + struct dsa_port *dp = dsa_phylink_to_port(config); + struct ks8995_switch *ks = dp->ds->priv; + int port = dp->index; + + if (port != KS8995_CPU_PORT) + return; + + dev_dbg(ks->dev, "MAC link down on CPU port (%d)\n", port); + + /* Disable the CPU port */ +} + +static const struct phylink_mac_ops ks8995_phylink_mac_ops = { + .mac_config = ks8995_mac_config, + .mac_link_up = ks8995_mac_link_up, + .mac_link_down = ks8995_mac_link_down, +}; + +static enum +dsa_tag_protocol ks8995_get_tag_protocol(struct dsa_switch *ds, + int port, + enum dsa_tag_protocol mp) +{ + /* This switch actually uses the 6 byte KS8995 protocol */ + return DSA_TAG_PROTO_NONE; +} + +static int ks8995_setup(struct dsa_switch *ds) +{ + return 0; +} + +static int ks8995_port_enable(struct dsa_switch *ds, int port, + struct phy_device *phy) +{ + struct ks8995_switch *ks = ds->priv; + + dev_dbg(ks->dev, "enable port %d\n", port); + + return 0; +} + +static void ks8995_port_disable(struct dsa_switch *ds, int port) +{ + struct ks8995_switch *ks = ds->priv; + + dev_dbg(ks->dev, "disable port %d\n", port); +} + +static int ks8995_port_pre_bridge_flags(struct dsa_switch *ds, int port, + struct switchdev_brport_flags flags, + struct netlink_ext_ack *extack) +{ + /* We support enabling/disabling learning */ + if (flags.mask & ~(BR_LEARNING)) + return -EINVAL; + + return 0; +} + +static int ks8995_port_bridge_flags(struct dsa_switch *ds, int port, + struct switchdev_brport_flags flags, + struct netlink_ext_ack *extack) +{ + struct ks8995_switch *ks = ds->priv; + int ret; + u8 val; + + if (flags.mask & BR_LEARNING) { + ret = ks8995_read_reg(ks, KS8995_REG_PC(port, KS8995_REG_PC2), &val); + if (ret) { + dev_err(ks->dev, "failed to read KS8995_REG_PC2 on port %d\n", port); + return ret; + } + + if (flags.val & BR_LEARNING) + val &= ~KS8995_PC2_LEARN_DIS; + else + val |= KS8995_PC2_LEARN_DIS; + + ret = ks8995_write_reg(ks, KS8995_REG_PC(port, KS8995_REG_PC2), val); + if (ret) { + dev_err(ks->dev, "failed to write KS8995_REG_PC2 on port %d\n", port); + return ret; + } + } + + return 0; +} + +static void ks8995_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) +{ + struct ks8995_switch *ks = ds->priv; + int ret; + u8 val; + + ret = ks8995_read_reg(ks, KS8995_REG_PC(port, KS8995_REG_PC2), &val); + if (ret) { + dev_err(ks->dev, "failed to read KS8995_REG_PC2 on port %d\n", port); + return; + } + + /* Set the bits for the different STP states in accordance with + * the datasheet, pages 36-37 "Spanning tree support". + */ + switch (state) { + case BR_STATE_DISABLED: + case BR_STATE_BLOCKING: + case BR_STATE_LISTENING: + val &= ~KS8995_PC2_TXEN; + val &= ~KS8995_PC2_RXEN; + val |= KS8995_PC2_LEARN_DIS; + break; + case BR_STATE_LEARNING: + val &= ~KS8995_PC2_TXEN; + val &= ~KS8995_PC2_RXEN; + val &= ~KS8995_PC2_LEARN_DIS; + break; + case BR_STATE_FORWARDING: + val |= KS8995_PC2_TXEN; + val |= KS8995_PC2_RXEN; + val &= ~KS8995_PC2_LEARN_DIS; + break; + default: + dev_err(ks->dev, "unknown bridge state requested\n"); + return; + } + + ret = ks8995_write_reg(ks, KS8995_REG_PC(port, KS8995_REG_PC2), val); + if (ret) { + dev_err(ks->dev, "failed to write KS8995_REG_PC2 on port %d\n", port); + return; + } + + dev_dbg(ks->dev, "set KS8995_REG_PC2 for port %d to %02x\n", port, val); +} + +static void ks8995_phylink_get_caps(struct dsa_switch *dsa, int port, + struct phylink_config *config) +{ + unsigned long *interfaces = config->supported_interfaces; + + if (port == KS8995_CPU_PORT) + __set_bit(PHY_INTERFACE_MODE_MII, interfaces); + + if (port <= 3) { + /* Internal PHYs */ + __set_bit(PHY_INTERFACE_MODE_INTERNAL, interfaces); + /* phylib default */ + __set_bit(PHY_INTERFACE_MODE_MII, interfaces); + } + + config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100; +} + +/* Huge packet support up to 1916 byte packages "inclusive" + * which means that tags are included. If the bit is not set + * it is 1536 bytes "inclusive". We present the length without + * tags or ethernet headers. The setting affects all ports. + */ +static int ks8995_change_mtu(struct dsa_switch *ds, int port, int new_mtu) +{ + struct ks8995_switch *ks = ds->priv; + unsigned int max_mtu; + int ret; + u8 val; + int i; + + ks->max_mtu[port] = new_mtu; + + /* Roof out the MTU for the entire switch to the greatest + * common denominator: the biggest set for any one port will + * be the biggest MTU for the switch. + */ + max_mtu = ETH_DATA_LEN; + for (i = 0; i < KS8995_NUM_PORTS; i++) { + if (ks->max_mtu[i] > max_mtu) + max_mtu = ks->max_mtu[i]; + } + + /* Translate to layer 2 size. + * Add ethernet and (possible) VLAN headers, and checksum to the size. + * For ETH_DATA_LEN (1500 bytes) this will add up to 1522 bytes. + */ + max_mtu += VLAN_ETH_HLEN; + max_mtu += ETH_FCS_LEN; + + ret = ks8995_read_reg(ks, KS8995_REG_GC2, &val); + if (ret) { + dev_err(ks->dev, "failed to read KS8995_REG_GC2\n"); + return ret; + } + + if (max_mtu <= 1522) { + val &= ~KS8995_GC2_HUGE; + val &= ~KS8995_GC2_LEGAL; + } else if (max_mtu > 1522 && max_mtu <= 1536) { + /* This accepts packets up to 1536 bytes */ + val &= ~KS8995_GC2_HUGE; + val |= KS8995_GC2_LEGAL; + } else { + /* This accepts packets up to 1916 bytes */ + val |= KS8995_GC2_HUGE; + val |= KS8995_GC2_LEGAL; + } + + dev_dbg(ks->dev, "new max MTU %d bytes (inclusive)\n", max_mtu); + + ret = ks8995_write_reg(ks, KS8995_REG_GC2, val); + if (ret) + dev_err(ks->dev, "failed to set KS8995_REG_GC2\n"); + + return ret; +} + +static int ks8995_get_max_mtu(struct dsa_switch *ds, int port) +{ + return 1916 - ETH_HLEN - ETH_FCS_LEN; +} + +static const struct dsa_switch_ops ks8995_ds_ops = { + .get_tag_protocol = ks8995_get_tag_protocol, + .setup = ks8995_setup, + .port_pre_bridge_flags = ks8995_port_pre_bridge_flags, + .port_bridge_flags = ks8995_port_bridge_flags, + .port_enable = ks8995_port_enable, + .port_disable = ks8995_port_disable, + .port_stp_state_set = ks8995_port_stp_state_set, + .port_change_mtu = ks8995_change_mtu, + .port_max_mtu = ks8995_get_max_mtu, + .phylink_get_caps = ks8995_phylink_get_caps, +}; + /* ------------------------------------------------------------------------ */ static int ks8995_probe(struct spi_device *spi) { @@ -389,6 +760,7 @@ static int ks8995_probe(struct spi_device *spi) mutex_init(&ks->lock); ks->spi = spi; + ks->dev = &spi->dev; ks->chip = &ks8995_chip[variant]; ks->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset", @@ -435,6 +807,25 @@ static int ks8995_probe(struct spi_device *spi) dev_info(&spi->dev, "%s device found, Chip ID:%x, Revision:%x\n", ks->chip->name, ks->chip->chip_id, ks->revision_id); + err = ks8995_check_config(ks); + if (err) + return err; + + ks->ds = devm_kzalloc(&spi->dev, sizeof(*ks->ds), GFP_KERNEL); + if (!ks->ds) + return -ENOMEM; + + ks->ds->dev = &spi->dev; + ks->ds->num_ports = KS8995_NUM_PORTS; + ks->ds->ops = &ks8995_ds_ops; + ks->ds->phylink_mac_ops = &ks8995_phylink_mac_ops; + ks->ds->priv = ks; + + err = dsa_register_switch(ks->ds); + if (err) + return dev_err_probe(&spi->dev, err, + "unable to register DSA switch\n"); + return 0; } @@ -442,6 +833,7 @@ static void ks8995_remove(struct spi_device *spi) { struct ks8995_switch *ks = spi_get_drvdata(spi); + dsa_unregister_switch(ks->ds); /* assert reset */ gpiod_set_value_cansleep(ks->reset_gpio, 1); } From 661bfb4699f8cb283014861d3fc35195df4eead0 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 14 Aug 2025 19:23:29 -0700 Subject: [PATCH 01251/11391] nfc: s3fwrn5: Use SHA-1 library instead of crypto_shash Now that a SHA-1 library API is available, use it instead of crypto_shash. This is simpler and faster. Signed-off-by: Eric Biggers Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250815022329.28672-1-ebiggers@kernel.org Signed-off-by: Jakub Kicinski --- drivers/nfc/s3fwrn5/Kconfig | 3 +-- drivers/nfc/s3fwrn5/firmware.c | 17 +---------------- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/drivers/nfc/s3fwrn5/Kconfig b/drivers/nfc/s3fwrn5/Kconfig index 8a6b1a79de25..96386b73fa2b 100644 --- a/drivers/nfc/s3fwrn5/Kconfig +++ b/drivers/nfc/s3fwrn5/Kconfig @@ -1,8 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config NFC_S3FWRN5 tristate - select CRYPTO - select CRYPTO_HASH + select CRYPTO_LIB_SHA1 help Core driver for Samsung S3FWRN5 NFC chip. Contains core utilities of chip. It's intended to be used by PHYs to avoid duplicating lots diff --git a/drivers/nfc/s3fwrn5/firmware.c b/drivers/nfc/s3fwrn5/firmware.c index 781cdbcac104..64d61b2a715a 100644 --- a/drivers/nfc/s3fwrn5/firmware.c +++ b/drivers/nfc/s3fwrn5/firmware.c @@ -8,7 +8,6 @@ #include #include -#include #include #include "s3fwrn5.h" @@ -411,27 +410,13 @@ int s3fwrn5_fw_download(struct s3fwrn5_fw_info *fw_info) struct device *dev = &fw_info->ndev->nfc_dev->dev; struct s3fwrn5_fw_image *fw = &fw_info->fw; u8 hash_data[SHA1_DIGEST_SIZE]; - struct crypto_shash *tfm; u32 image_size, off; int ret; image_size = fw_info->sector_size * fw->image_sectors; /* Compute SHA of firmware data */ - - tfm = crypto_alloc_shash("sha1", 0, 0); - if (IS_ERR(tfm)) { - dev_err(dev, "Cannot allocate shash (code=%pe)\n", tfm); - return PTR_ERR(tfm); - } - - ret = crypto_shash_tfm_digest(tfm, fw->image, image_size, hash_data); - - crypto_free_shash(tfm); - if (ret) { - dev_err(dev, "Cannot compute hash (code=%d)\n", ret); - return ret; - } + sha1(fw->image, image_size, hash_data); /* Firmware update process */ From 1fb39d4c23b1e2b16bfd46261f4e83d42c1ff0a4 Mon Sep 17 00:00:00 2001 From: Li RongQing Date: Fri, 15 Aug 2025 09:56:19 +0800 Subject: [PATCH 01252/11391] eth: nfp: Remove u64_stats_update_begin()/end() for stats fetch This place is fetching the stats, u64_stats_update_begin()/end() should not be used, and the fetcher of stats is in the same context as the updater of the stats, so don't need any protection Signed-off-by: Li RongQing Link: https://patch.msgid.link/20250815015619.2713-1-lirongqing@baidu.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/netronome/nfp/nfd3/dp.c | 16 ++++------------ drivers/net/ethernet/netronome/nfp/nfdk/dp.c | 16 ++++------------ 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/nfd3/dp.c b/drivers/net/ethernet/netronome/nfp/nfd3/dp.c index 08086eb76996..91a227929a5f 100644 --- a/drivers/net/ethernet/netronome/nfp/nfd3/dp.c +++ b/drivers/net/ethernet/netronome/nfp/nfd3/dp.c @@ -1169,14 +1169,10 @@ int nfp_nfd3_poll(struct napi_struct *napi, int budget) if (r_vec->nfp_net->rx_coalesce_adapt_on && r_vec->rx_ring) { struct dim_sample dim_sample = {}; - unsigned int start; u64 pkts, bytes; - do { - start = u64_stats_fetch_begin(&r_vec->rx_sync); - pkts = r_vec->rx_pkts; - bytes = r_vec->rx_bytes; - } while (u64_stats_fetch_retry(&r_vec->rx_sync, start)); + pkts = r_vec->rx_pkts; + bytes = r_vec->rx_bytes; dim_update_sample(r_vec->event_ctr, pkts, bytes, &dim_sample); net_dim(&r_vec->rx_dim, &dim_sample); @@ -1184,14 +1180,10 @@ int nfp_nfd3_poll(struct napi_struct *napi, int budget) if (r_vec->nfp_net->tx_coalesce_adapt_on && r_vec->tx_ring) { struct dim_sample dim_sample = {}; - unsigned int start; u64 pkts, bytes; - do { - start = u64_stats_fetch_begin(&r_vec->tx_sync); - pkts = r_vec->tx_pkts; - bytes = r_vec->tx_bytes; - } while (u64_stats_fetch_retry(&r_vec->tx_sync, start)); + pkts = r_vec->tx_pkts; + bytes = r_vec->tx_bytes; dim_update_sample(r_vec->event_ctr, pkts, bytes, &dim_sample); net_dim(&r_vec->tx_dim, &dim_sample); diff --git a/drivers/net/ethernet/netronome/nfp/nfdk/dp.c b/drivers/net/ethernet/netronome/nfp/nfdk/dp.c index ab3cd06ed63e..ee0db3d5fd66 100644 --- a/drivers/net/ethernet/netronome/nfp/nfdk/dp.c +++ b/drivers/net/ethernet/netronome/nfp/nfdk/dp.c @@ -1279,14 +1279,10 @@ int nfp_nfdk_poll(struct napi_struct *napi, int budget) if (r_vec->nfp_net->rx_coalesce_adapt_on && r_vec->rx_ring) { struct dim_sample dim_sample = {}; - unsigned int start; u64 pkts, bytes; - do { - start = u64_stats_fetch_begin(&r_vec->rx_sync); - pkts = r_vec->rx_pkts; - bytes = r_vec->rx_bytes; - } while (u64_stats_fetch_retry(&r_vec->rx_sync, start)); + pkts = r_vec->rx_pkts; + bytes = r_vec->rx_bytes; dim_update_sample(r_vec->event_ctr, pkts, bytes, &dim_sample); net_dim(&r_vec->rx_dim, &dim_sample); @@ -1294,14 +1290,10 @@ int nfp_nfdk_poll(struct napi_struct *napi, int budget) if (r_vec->nfp_net->tx_coalesce_adapt_on && r_vec->tx_ring) { struct dim_sample dim_sample = {}; - unsigned int start; u64 pkts, bytes; - do { - start = u64_stats_fetch_begin(&r_vec->tx_sync); - pkts = r_vec->tx_pkts; - bytes = r_vec->tx_bytes; - } while (u64_stats_fetch_retry(&r_vec->tx_sync, start)); + pkts = r_vec->tx_pkts; + bytes = r_vec->tx_bytes; dim_update_sample(r_vec->event_ctr, pkts, bytes, &dim_sample); net_dim(&r_vec->tx_dim, &dim_sample); From b55f7295d600b4cd487ef2e9332e30d6933be78c Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 14 Aug 2025 19:07:05 -0700 Subject: [PATCH 01253/11391] ppp: mppe: Use SHA-1 library instead of crypto_shash Now that a SHA-1 library API is available, use it instead of crypto_shash. This is simpler and faster. Signed-off-by: Eric Biggers Link: https://patch.msgid.link/20250815020705.23055-1-ebiggers@kernel.org Signed-off-by: Jakub Kicinski --- drivers/net/ppp/Kconfig | 3 +- drivers/net/ppp/ppp_mppe.c | 108 +++++++------------------------------ 2 files changed, 19 insertions(+), 92 deletions(-) diff --git a/drivers/net/ppp/Kconfig b/drivers/net/ppp/Kconfig index 8c9ed1889d1a..a1806b4b84be 100644 --- a/drivers/net/ppp/Kconfig +++ b/drivers/net/ppp/Kconfig @@ -85,9 +85,8 @@ config PPP_FILTER config PPP_MPPE tristate "PPP MPPE compression (encryption)" depends on PPP - select CRYPTO - select CRYPTO_SHA1 select CRYPTO_LIB_ARC4 + select CRYPTO_LIB_SHA1 help Support for the MPPE Encryption protocol, as employed by the Microsoft Point-to-Point Tunneling Protocol. diff --git a/drivers/net/ppp/ppp_mppe.c b/drivers/net/ppp/ppp_mppe.c index bcc1eaedf58f..630cbf71c147 100644 --- a/drivers/net/ppp/ppp_mppe.c +++ b/drivers/net/ppp/ppp_mppe.c @@ -43,7 +43,7 @@ */ #include -#include +#include #include #include #include @@ -55,7 +55,6 @@ #include #include #include -#include #include #include "ppp_mppe.h" @@ -67,31 +66,15 @@ MODULE_ALIAS("ppp-compress-" __stringify(CI_MPPE)); MODULE_VERSION("1.0.2"); #define SHA1_PAD_SIZE 40 - -/* - * kernel crypto API needs its arguments to be in kmalloc'd memory, not in the module - * static data area. That means sha_pad needs to be kmalloc'd. - */ - -struct sha_pad { - unsigned char sha_pad1[SHA1_PAD_SIZE]; - unsigned char sha_pad2[SHA1_PAD_SIZE]; -}; -static struct sha_pad *sha_pad; - -static inline void sha_pad_init(struct sha_pad *shapad) -{ - memset(shapad->sha_pad1, 0x00, sizeof(shapad->sha_pad1)); - memset(shapad->sha_pad2, 0xF2, sizeof(shapad->sha_pad2)); -} +static const u8 sha_pad1[SHA1_PAD_SIZE] = { 0 }; +static const u8 sha_pad2[SHA1_PAD_SIZE] = { [0 ... SHA1_PAD_SIZE - 1] = 0xF2 }; /* * State for an MPPE (de)compressor. */ struct ppp_mppe_state { struct arc4_ctx arc4; - struct shash_desc *sha1; - unsigned char *sha1_digest; + unsigned char sha1_digest[SHA1_DIGEST_SIZE]; unsigned char master_key[MPPE_MAX_KEY_LEN]; unsigned char session_key[MPPE_MAX_KEY_LEN]; unsigned keylen; /* key length in bytes */ @@ -130,16 +113,14 @@ struct ppp_mppe_state { */ static void get_new_key_from_sha(struct ppp_mppe_state * state) { - crypto_shash_init(state->sha1); - crypto_shash_update(state->sha1, state->master_key, - state->keylen); - crypto_shash_update(state->sha1, sha_pad->sha_pad1, - sizeof(sha_pad->sha_pad1)); - crypto_shash_update(state->sha1, state->session_key, - state->keylen); - crypto_shash_update(state->sha1, sha_pad->sha_pad2, - sizeof(sha_pad->sha_pad2)); - crypto_shash_final(state->sha1, state->sha1_digest); + struct sha1_ctx ctx; + + sha1_init(&ctx); + sha1_update(&ctx, state->master_key, state->keylen); + sha1_update(&ctx, sha_pad1, sizeof(sha_pad1)); + sha1_update(&ctx, state->session_key, state->keylen); + sha1_update(&ctx, sha_pad2, sizeof(sha_pad2)); + sha1_final(&ctx, state->sha1_digest); } /* @@ -171,39 +152,15 @@ static void mppe_rekey(struct ppp_mppe_state * state, int initial_key) static void *mppe_alloc(unsigned char *options, int optlen) { struct ppp_mppe_state *state; - struct crypto_shash *shash; - unsigned int digestsize; if (optlen != CILEN_MPPE + sizeof(state->master_key) || options[0] != CI_MPPE || options[1] != CILEN_MPPE || fips_enabled) - goto out; + return NULL; state = kzalloc(sizeof(*state), GFP_KERNEL); if (state == NULL) - goto out; - - - shash = crypto_alloc_shash("sha1", 0, 0); - if (IS_ERR(shash)) - goto out_free; - - state->sha1 = kmalloc(sizeof(*state->sha1) + - crypto_shash_descsize(shash), - GFP_KERNEL); - if (!state->sha1) { - crypto_free_shash(shash); - goto out_free; - } - state->sha1->tfm = shash; - - digestsize = crypto_shash_digestsize(shash); - if (digestsize < MPPE_MAX_KEY_LEN) - goto out_free; - - state->sha1_digest = kmalloc(digestsize, GFP_KERNEL); - if (!state->sha1_digest) - goto out_free; + return NULL; /* Save keys. */ memcpy(state->master_key, &options[CILEN_MPPE], @@ -217,16 +174,6 @@ static void *mppe_alloc(unsigned char *options, int optlen) */ return (void *)state; - -out_free: - kfree(state->sha1_digest); - if (state->sha1) { - crypto_free_shash(state->sha1->tfm); - kfree_sensitive(state->sha1); - } - kfree(state); -out: - return NULL; } /* @@ -235,12 +182,8 @@ static void *mppe_alloc(unsigned char *options, int optlen) static void mppe_free(void *arg) { struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; - if (state) { - kfree(state->sha1_digest); - crypto_free_shash(state->sha1->tfm); - kfree_sensitive(state->sha1); - kfree_sensitive(state); - } + + kfree_sensitive(state); } /* @@ -649,31 +592,17 @@ static struct compressor ppp_mppe = { .comp_extra = MPPE_PAD, }; -/* - * ppp_mppe_init() - * - * Prior to allowing load, try to load the arc4 and sha1 crypto - * libraries. The actual use will be allocated later, but - * this way the module will fail to insmod if they aren't available. - */ - static int __init ppp_mppe_init(void) { int answer; - if (fips_enabled || !crypto_has_ahash("sha1", 0, CRYPTO_ALG_ASYNC)) - return -ENODEV; - sha_pad = kmalloc(sizeof(struct sha_pad), GFP_KERNEL); - if (!sha_pad) - return -ENOMEM; - sha_pad_init(sha_pad); + if (fips_enabled) + return -ENODEV; answer = ppp_register_compressor(&ppp_mppe); if (answer == 0) printk(KERN_INFO "PPP MPPE Compression module registered\n"); - else - kfree(sha_pad); return answer; } @@ -681,7 +610,6 @@ static int __init ppp_mppe_init(void) static void __exit ppp_mppe_cleanup(void) { ppp_unregister_compressor(&ppp_mppe); - kfree(sha_pad); } module_init(ppp_mppe_init); From ab4ee77ed9bddfc1c3461b42ef4875068928d2e6 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 15 Aug 2025 09:52:42 -0700 Subject: [PATCH 01254/11391] docs: netdev: refine the clean-up patch examples We discourage sending trivial patches to clean up checkpatch warnings. There are other tools which lead to patches of similarly low value like some coccicheck warnings. The warnings are useful for new code but fixing them in the existing code base is a waste of review time. Broaden the example given in the doc a little bit. Link: https://patch.msgid.link/20250815165242.124240-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- Documentation/process/maintainer-netdev.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/process/maintainer-netdev.rst b/Documentation/process/maintainer-netdev.rst index e1755610b4bc..989192421cc9 100644 --- a/Documentation/process/maintainer-netdev.rst +++ b/Documentation/process/maintainer-netdev.rst @@ -407,7 +407,7 @@ Clean-up patches Netdev discourages patches which perform simple clean-ups, which are not in the context of other work. For example: -* Addressing ``checkpatch.pl`` warnings +* Addressing ``checkpatch.pl``, and other trivial coding style warnings * Addressing :ref:`Local variable ordering` issues * Conversions to device-managed APIs (``devm_`` helpers) From 4490d075c2d989f3403059cbd30775ae21dbd754 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Sat, 16 Aug 2025 17:06:52 +0800 Subject: [PATCH 01255/11391] eth: intel: use vmalloc_array() to simplify code Remove array_size() calls and replace vmalloc() with vmalloc_array() to simplify the code and maintain consistency with existing kmalloc_array() usage. vmalloc_array() is also optimized better, resulting in less instructions being used. Signed-off-by: Qianfeng Rong Link: https://patch.msgid.link/20250816090659.117699-2-rongqianfeng@vivo.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c | 2 +- drivers/net/ethernet/intel/igb/igb_ethtool.c | 8 ++++---- drivers/net/ethernet/intel/igc/igc_ethtool.c | 8 ++++---- drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 2 +- drivers/net/ethernet/intel/ixgbevf/ethtool.c | 6 +++--- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c b/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c index 1954a04460d1..bf2029144c1d 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c @@ -560,7 +560,7 @@ static int fm10k_set_ringparam(struct net_device *netdev, /* allocate temporary buffer to store rings in */ i = max_t(int, interface->num_tx_queues, interface->num_rx_queues); - temp_ring = vmalloc(array_size(i, sizeof(struct fm10k_ring))); + temp_ring = vmalloc_array(i, sizeof(struct fm10k_ring)); if (!temp_ring) { err = -ENOMEM; diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index 92ef33459aec..51d5cb6599ed 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -920,11 +920,11 @@ static int igb_set_ringparam(struct net_device *netdev, } if (adapter->num_tx_queues > adapter->num_rx_queues) - temp_ring = vmalloc(array_size(sizeof(struct igb_ring), - adapter->num_tx_queues)); + temp_ring = vmalloc_array(adapter->num_tx_queues, + sizeof(struct igb_ring)); else - temp_ring = vmalloc(array_size(sizeof(struct igb_ring), - adapter->num_rx_queues)); + temp_ring = vmalloc_array(adapter->num_rx_queues, + sizeof(struct igb_ring)); if (!temp_ring) { err = -ENOMEM; diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c index ecb35b693ce5..f3e7218ba6f3 100644 --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c @@ -627,11 +627,11 @@ igc_ethtool_set_ringparam(struct net_device *netdev, } if (adapter->num_tx_queues > adapter->num_rx_queues) - temp_ring = vmalloc(array_size(sizeof(struct igc_ring), - adapter->num_tx_queues)); + temp_ring = vmalloc_array(adapter->num_tx_queues, + sizeof(struct igc_ring)); else - temp_ring = vmalloc(array_size(sizeof(struct igc_ring), - adapter->num_rx_queues)); + temp_ring = vmalloc_array(adapter->num_rx_queues, + sizeof(struct igc_ring)); if (!temp_ring) { err = -ENOMEM; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index 25c3a09ad7f1..2c5d774f1ec1 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -1278,7 +1278,7 @@ static int ixgbe_set_ringparam(struct net_device *netdev, /* allocate temporary buffer to store rings in */ i = max_t(int, adapter->num_tx_queues + adapter->num_xdp_queues, adapter->num_rx_queues); - temp_ring = vmalloc(array_size(i, sizeof(struct ixgbe_ring))); + temp_ring = vmalloc_array(i, sizeof(struct ixgbe_ring)); if (!temp_ring) { err = -ENOMEM; diff --git a/drivers/net/ethernet/intel/ixgbevf/ethtool.c b/drivers/net/ethernet/intel/ixgbevf/ethtool.c index 7ac53171b041..bebad564188e 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ethtool.c +++ b/drivers/net/ethernet/intel/ixgbevf/ethtool.c @@ -276,9 +276,9 @@ static int ixgbevf_set_ringparam(struct net_device *netdev, } if (new_tx_count != adapter->tx_ring_count) { - tx_ring = vmalloc(array_size(sizeof(*tx_ring), - adapter->num_tx_queues + - adapter->num_xdp_queues)); + tx_ring = vmalloc_array(adapter->num_tx_queues + + adapter->num_xdp_queues, + sizeof(*tx_ring)); if (!tx_ring) { err = -ENOMEM; goto clear_reset; From fce214586f99fe971a78ff1342cc331eecc74855 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Sat, 16 Aug 2025 17:06:53 +0800 Subject: [PATCH 01256/11391] nfp: flower: use vmalloc_array() to simplify code Remove array_size() calls and replace vmalloc() with vmalloc_array() in nfp_flower_metadata_init(). vmalloc_array() is also optimized better, resulting in less instructions being used. Place 'NFP_FL_STATS_ELEM_RS' with the sizeof() parameter as the second argument to vmalloc_array() to avoid -Wcalloc-transposed-args compilation warnings. Signed-off-by: Qianfeng Rong Link: https://patch.msgid.link/20250816090659.117699-3-rongqianfeng@vivo.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/netronome/nfp/flower/metadata.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/flower/metadata.c b/drivers/net/ethernet/netronome/nfp/flower/metadata.c index 80e4675582bf..dde60c4572fa 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/metadata.c +++ b/drivers/net/ethernet/netronome/nfp/flower/metadata.c @@ -564,8 +564,8 @@ int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count, /* Init ring buffer and unallocated stats_ids. */ priv->stats_ids.free_list.buf = - vmalloc(array_size(NFP_FL_STATS_ELEM_RS, - priv->stats_ring_size)); + vmalloc_array(priv->stats_ring_size, + NFP_FL_STATS_ELEM_RS); if (!priv->stats_ids.free_list.buf) goto err_free_last_used; From dad3280591abde4c100e8185e3e47bfe72ae53c5 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Sat, 16 Aug 2025 17:06:54 +0800 Subject: [PATCH 01257/11391] ppp: use vmalloc_array() to simplify code Remove array_size() calls and replace vmalloc() with vmalloc_array() in bsd_alloc(). vmalloc_array() is also optimized better, resulting in less instructions being used. Signed-off-by: Qianfeng Rong Link: https://patch.msgid.link/20250816090659.117699-4-rongqianfeng@vivo.com Signed-off-by: Jakub Kicinski --- drivers/net/ppp/bsd_comp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ppp/bsd_comp.c b/drivers/net/ppp/bsd_comp.c index 55954594e157..f385b759d5cf 100644 --- a/drivers/net/ppp/bsd_comp.c +++ b/drivers/net/ppp/bsd_comp.c @@ -406,7 +406,7 @@ static void *bsd_alloc (unsigned char *options, int opt_len, int decomp) * Allocate space for the dictionary. This may be more than one page in * length. */ - db->dict = vmalloc(array_size(hsize, sizeof(struct bsd_dict))); + db->dict = vmalloc_array(hsize, sizeof(struct bsd_dict)); if (!db->dict) { bsd_free (db); @@ -425,7 +425,7 @@ static void *bsd_alloc (unsigned char *options, int opt_len, int decomp) */ else { - db->lens = vmalloc(array_size(sizeof(db->lens[0]), (maxmaxcode + 1))); + db->lens = vmalloc_array(maxmaxcode + 1, sizeof(db->lens[0])); if (!db->lens) { bsd_free (db); From 5883cb32fcea4471da242c9147427038625eee04 Mon Sep 17 00:00:00 2001 From: Vishal Badole Date: Sat, 16 Aug 2025 19:49:41 +0530 Subject: [PATCH 01258/11391] amd-xgbe: Configure and retrieve 'tx-usecs' for Tx coalescing Ethtool has advanced with additional configurable options, but the current driver does not support tx-usecs configuration using Ethtool. Add support to configure and retrieve 'tx-usecs' using ethtool, which specifies the wait time before servicing an interrupt for Tx coalescing. Signed-off-by: Vishal Badole Acked-by: Shyam Sundar S K Link: https://patch.msgid.link/20250816141941.126054-1-Vishal.Badole@amd.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c | 28 ++++++++++++++++++-- drivers/net/ethernet/amd/xgbe/xgbe.h | 1 + 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c index be0d2c7d08dc..35d73306a2d6 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c @@ -329,6 +329,7 @@ static int xgbe_get_coalesce(struct net_device *netdev, ec->rx_coalesce_usecs = pdata->rx_usecs; ec->rx_max_coalesced_frames = pdata->rx_frames; + ec->tx_coalesce_usecs = pdata->tx_usecs; ec->tx_max_coalesced_frames = pdata->tx_frames; return 0; @@ -342,7 +343,8 @@ static int xgbe_set_coalesce(struct net_device *netdev, struct xgbe_prv_data *pdata = netdev_priv(netdev); struct xgbe_hw_if *hw_if = &pdata->hw_if; unsigned int rx_frames, rx_riwt, rx_usecs; - unsigned int tx_frames; + unsigned int tx_frames, tx_usecs; + unsigned int jiffy_us = jiffies_to_usecs(1); rx_riwt = hw_if->usec_to_riwt(pdata, ec->rx_coalesce_usecs); rx_usecs = ec->rx_coalesce_usecs; @@ -364,20 +366,42 @@ static int xgbe_set_coalesce(struct net_device *netdev, return -EINVAL; } + tx_usecs = ec->tx_coalesce_usecs; tx_frames = ec->tx_max_coalesced_frames; /* Check the bounds of values for Tx */ + if (!tx_usecs) { + NL_SET_ERR_MSG_FMT_MOD(extack, + "tx-usecs must not be 0"); + return -EINVAL; + } + if (tx_usecs > XGMAC_MAX_COAL_TX_TICK) { + NL_SET_ERR_MSG_FMT_MOD(extack, "tx-usecs is limited to %d usec", + XGMAC_MAX_COAL_TX_TICK); + return -EINVAL; + } if (tx_frames > pdata->tx_desc_count) { netdev_err(netdev, "tx-frames is limited to %d frames\n", pdata->tx_desc_count); return -EINVAL; } + /* Round tx-usecs to nearest multiple of jiffy granularity */ + if (tx_usecs % jiffy_us) { + tx_usecs = rounddown(tx_usecs, jiffy_us); + if (!tx_usecs) + tx_usecs = jiffy_us; + NL_SET_ERR_MSG_FMT_MOD(extack, + "tx-usecs rounded to %u usec due to jiffy granularity (%u usec)", + tx_usecs, jiffy_us); + } + pdata->rx_riwt = rx_riwt; pdata->rx_usecs = rx_usecs; pdata->rx_frames = rx_frames; hw_if->config_rx_coalesce(pdata); + pdata->tx_usecs = tx_usecs; pdata->tx_frames = tx_frames; hw_if->config_tx_coalesce(pdata); @@ -709,7 +733,7 @@ static int xgbe_set_channels(struct net_device *netdev, } static const struct ethtool_ops xgbe_ethtool_ops = { - .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS | + .supported_coalesce_params = ETHTOOL_COALESCE_USECS | ETHTOOL_COALESCE_MAX_FRAMES, .get_drvinfo = xgbe_get_drvinfo, .get_msglevel = xgbe_get_msglevel, diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index d7e03e292ec4..0fa80a238ac5 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -168,6 +168,7 @@ /* Default coalescing parameters */ #define XGMAC_INIT_DMA_TX_USECS 1000 #define XGMAC_INIT_DMA_TX_FRAMES 25 +#define XGMAC_MAX_COAL_TX_TICK 100000 #define XGMAC_MAX_DMA_RIWT 0xff #define XGMAC_INIT_DMA_RX_USECS 30 From d360551f265e3c942ce06cd6f4d2f7f67741bcbd Mon Sep 17 00:00:00 2001 From: Kuan-Chung Chen Date: Mon, 11 Aug 2025 20:37:37 +0800 Subject: [PATCH 01259/11391] wifi: rtw89: introduce beacon tracking to improve connection stability In ideal scenario, AP's beacon should transmit at the Target Beacon Transmission Time (TBTT). However, in practice, beacon may be slightly off-schedule. This beacon "drift" prevents the firmware from receiving beacon at the expected TBTT, leading to connection disruptions. To address this, we introduce beacon tracking mechanism to enhance overall connection stability. This mechanism executes the following steps in each cycle (2 seconds): 1) Based on the last 32 received beacons, compute the minimum TBTT offset to use for the next cycle 2) Using the same 32 beacons, calculate the drift of each. A histogram is plotted, and outliers are identified using a boxplot. 3) According to the statistical results from the second step, a maximum receive window size (beacon timeout) is selected to cover approximately 80% of the beacons and applied to the next cycle. Signed-off-by: Kuan-Chung Chen Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250811123744.15361-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 457 +++++++++++++++++++++- drivers/net/wireless/realtek/rtw89/core.h | 50 ++- drivers/net/wireless/realtek/rtw89/fw.c | 90 +++++ drivers/net/wireless/realtek/rtw89/fw.h | 27 ++ drivers/net/wireless/realtek/rtw89/mac.c | 22 -- drivers/net/wireless/realtek/rtw89/phy.c | 2 +- drivers/net/wireless/realtek/rtw89/ps.c | 3 + 7 files changed, 619 insertions(+), 32 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 57590f5577a3..7d522031dfa1 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -2,6 +2,7 @@ /* Copyright(c) 2019-2020 Realtek Corporation */ #include +#include #include #include "cam.h" @@ -272,17 +273,18 @@ rtw89_get_6ghz_span(struct rtw89_dev *rtwdev, u32 center_freq) return NULL; } -bool rtw89_ra_report_to_bitrate(struct rtw89_dev *rtwdev, u8 rpt_rate, u16 *bitrate) +bool rtw89_legacy_rate_to_bitrate(struct rtw89_dev *rtwdev, u8 legacy_rate, u16 *bitrate) { - struct ieee80211_rate rate; + const struct ieee80211_rate *rate; - if (unlikely(rpt_rate >= ARRAY_SIZE(rtw89_bitrates))) { - rtw89_debug(rtwdev, RTW89_DBG_UNEXP, "invalid rpt rate %d\n", rpt_rate); + if (unlikely(legacy_rate >= ARRAY_SIZE(rtw89_bitrates))) { + rtw89_debug(rtwdev, RTW89_DBG_UNEXP, + "invalid legacy rate %d\n", legacy_rate); return false; } - rate = rtw89_bitrates[rpt_rate]; - *bitrate = rate.bitrate; + rate = &rtw89_bitrates[legacy_rate]; + *bitrate = rate->bitrate; return true; } @@ -2221,6 +2223,435 @@ static void rtw89_vif_sync_bcn_tsf(struct rtw89_vif_link *rtwvif_link, WRITE_ONCE(rtwvif_link->sync_bcn_tsf, le64_to_cpu(mgmt->u.beacon.timestamp)); } +static u32 rtw89_bcn_calc_min_tbtt(struct rtw89_dev *rtwdev, u32 tbtt1, u32 tbtt2) +{ + struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track; + u32 close_bcn_intvl_th = bcn_track->close_bcn_intvl_th; + u32 tbtt_diff_th = bcn_track->tbtt_diff_th; + + if (tbtt2 > tbtt1) + swap(tbtt1, tbtt2); + + if (tbtt1 - tbtt2 > tbtt_diff_th) + return tbtt1; + else if (tbtt2 > close_bcn_intvl_th) + return tbtt2; + else if (tbtt1 > close_bcn_intvl_th) + return tbtt1; + else + return tbtt2; +} + +static void rtw89_bcn_cfg_tbtt_offset(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ + struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track; + enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; + u32 offset = bcn_track->tbtt_offset; + + if (chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + const struct rtw89_port_reg *p = mac->port_base; + u32 bcnspc, val; + + bcnspc = rtw89_read32_port_mask(rtwdev, rtwvif_link, + p->bcn_space, B_AX_BCN_SPACE_MASK); + val = bcnspc - (offset / 1024); + val = u32_encode_bits(val, B_AX_TBTT_SHIFT_OFST_MAG) | + B_AX_TBTT_SHIFT_OFST_SIGN; + + rtw89_write16_port_mask(rtwdev, rtwvif_link, p->tbtt_shift, + B_AX_TBTT_SHIFT_OFST_MASK, val); + + return; + } + + rtw89_fw_h2c_tbtt_tuning(rtwdev, rtwvif_link, offset); +} + +static void rtw89_bcn_update_tbtt_offset(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ + struct rtw89_beacon_stat *bcn_stat = &rtwdev->phystat.bcn_stat; + struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track; + u32 *tbtt_us = bcn_stat->tbtt_us; + u32 offset = tbtt_us[0]; + u8 i; + + for (i = 1; i < RTW89_BCN_TRACK_STAT_NR; i++) + offset = rtw89_bcn_calc_min_tbtt(rtwdev, tbtt_us[i], offset); + + if (bcn_track->tbtt_offset == offset) + return; + + bcn_track->tbtt_offset = offset; + rtw89_bcn_cfg_tbtt_offset(rtwdev, rtwvif_link); +} + +static int cmp_u16(const void *a, const void *b) +{ + return *(const u16 *)a - *(const u16 *)b; +} + +static u16 _rtw89_bcn_calc_drift(u16 tbtt, u16 offset, u16 beacon_int) +{ + if (tbtt < offset) + return beacon_int - offset + tbtt; + + return tbtt - offset; +} + +static void rtw89_bcn_calc_drift(struct rtw89_dev *rtwdev) +{ + struct rtw89_beacon_stat *bcn_stat = &rtwdev->phystat.bcn_stat; + struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track; + u16 offset_tu = bcn_track->tbtt_offset / 1024; + u16 *tbtt_tu = bcn_stat->tbtt_tu; + u16 *drift = bcn_stat->drift; + u8 i; + + bcn_stat->tbtt_tu_min = U16_MAX; + bcn_stat->tbtt_tu_max = 0; + for (i = 0; i < RTW89_BCN_TRACK_STAT_NR; i++) { + drift[i] = _rtw89_bcn_calc_drift(tbtt_tu[i], offset_tu, + bcn_track->beacon_int); + + bcn_stat->tbtt_tu_min = min(bcn_stat->tbtt_tu_min, tbtt_tu[i]); + bcn_stat->tbtt_tu_max = max(bcn_stat->tbtt_tu_max, tbtt_tu[i]); + } + + sort(drift, RTW89_BCN_TRACK_STAT_NR, sizeof(*drift), cmp_u16, NULL); +} + +static void rtw89_bcn_calc_distribution(struct rtw89_dev *rtwdev) +{ + struct rtw89_beacon_stat *bcn_stat = &rtwdev->phystat.bcn_stat; + struct rtw89_beacon_dist *bcn_dist = &bcn_stat->bcn_dist; + u16 lower_bound, upper_bound, outlier_count = 0; + u16 *drift = bcn_stat->drift; + u16 *bins = bcn_dist->bins; + u16 q1, q3, iqr, tmp; + u8 i; + + BUILD_BUG_ON(RTW89_BCN_TRACK_STAT_NR % 4 != 0); + + memset(bcn_dist, 0, sizeof(*bcn_dist)); + + bcn_dist->min = drift[0]; + bcn_dist->max = drift[RTW89_BCN_TRACK_STAT_NR - 1]; + + tmp = RTW89_BCN_TRACK_STAT_NR / 4; + q1 = ((drift[tmp] + drift[tmp - 1]) * RTW89_BCN_TRACK_SCALE_FACTOR) / 2; + + tmp = (RTW89_BCN_TRACK_STAT_NR * 3) / 4; + q3 = ((drift[tmp] + drift[tmp - 1]) * RTW89_BCN_TRACK_SCALE_FACTOR) / 2; + + iqr = q3 - q1; + tmp = (3 * iqr) / 2; + + if (bcn_dist->min <= 5) + lower_bound = bcn_dist->min; + else if (q1 > tmp) + lower_bound = (q1 - tmp) / RTW89_BCN_TRACK_SCALE_FACTOR; + else + lower_bound = 0; + + upper_bound = (q3 + tmp) / RTW89_BCN_TRACK_SCALE_FACTOR; + + for (i = 0; i < RTW89_BCN_TRACK_STAT_NR; i++) { + u16 tbtt = bcn_stat->tbtt_tu[i]; + u16 min = bcn_stat->tbtt_tu_min; + u8 bin_idx; + + /* histogram */ + bin_idx = min((tbtt - min) / RTW89_BCN_TRACK_BIN_WIDTH, + RTW89_BCN_TRACK_MAX_BIN_NUM - 1); + bins[bin_idx]++; + + /* boxplot outlier */ + if (drift[i] < lower_bound || drift[i] > upper_bound) + outlier_count++; + } + + bcn_dist->outlier_count = outlier_count; + bcn_dist->lower_bound = lower_bound; + bcn_dist->upper_bound = upper_bound; +} + +static u8 rtw89_bcn_get_coverage(struct rtw89_dev *rtwdev, u16 threshold) +{ + struct rtw89_beacon_stat *bcn_stat = &rtwdev->phystat.bcn_stat; + int l = 0, r = RTW89_BCN_TRACK_STAT_NR - 1, m; + u16 *drift = bcn_stat->drift; + int index = -1; + u8 count = 0; + + while (l <= r) { + m = l + (r - l) / 2; + + if (drift[m] <= threshold) { + index = m; + l = m + 1; + } else { + r = m - 1; + } + } + + count = (index == -1) ? 0 : (index + 1); + + return (count * PERCENT) / RTW89_BCN_TRACK_STAT_NR; +} + +static u16 rtw89_bcn_get_histogram_bound(struct rtw89_dev *rtwdev, u8 target) +{ + struct rtw89_beacon_stat *bcn_stat = &rtwdev->phystat.bcn_stat; + struct rtw89_beacon_dist *bcn_dist = &bcn_stat->bcn_dist; + u16 tbtt_tu_max = bcn_stat->tbtt_tu_max; + u16 upper, lower = bcn_stat->tbtt_tu_min; + u8 i, count = 0; + + for (i = 0; i < RTW89_BCN_TRACK_MAX_BIN_NUM; i++) { + upper = lower + RTW89_BCN_TRACK_BIN_WIDTH - 1; + if (i == RTW89_BCN_TRACK_MAX_BIN_NUM - 1) + upper = max(upper, tbtt_tu_max); + + count += bcn_dist->bins[i]; + if (count > target) + break; + + lower = upper + 1; + } + + return upper; +} + +static u16 rtw89_bcn_get_rx_time(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan) +{ +#define RTW89_SYMBOL_TIME_2GHZ 192 +#define RTW89_SYMBOL_TIME_5GHZ 20 +#define RTW89_SYMBOL_TIME_6GHZ 20 + struct rtw89_pkt_stat *pkt_stat = &rtwdev->phystat.cur_pkt_stat; + u16 bitrate, val; + + if (!rtw89_legacy_rate_to_bitrate(rtwdev, pkt_stat->beacon_rate, &bitrate)) + return 0; + + val = (pkt_stat->beacon_len * 8 * RTW89_BCN_TRACK_SCALE_FACTOR) / bitrate; + + switch (chan->band_type) { + default: + case RTW89_BAND_2G: + val += RTW89_SYMBOL_TIME_2GHZ; + break; + case RTW89_BAND_5G: + val += RTW89_SYMBOL_TIME_5GHZ; + break; + case RTW89_BAND_6G: + val += RTW89_SYMBOL_TIME_6GHZ; + break; + } + + /* convert to millisecond */ + return DIV_ROUND_UP(val, 1000); +} + +static void rtw89_bcn_calc_timeout(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ +#define RTW89_BCN_TRACK_EXTEND_TIMEOUT 5 +#define RTW89_BCN_TRACK_COVERAGE_TH 0 /* unit: TU */ +#define RTW89_BCN_TRACK_STRONG_RSSI 80 + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx); + struct rtw89_pkt_stat *pkt_stat = &rtwdev->phystat.cur_pkt_stat; + struct rtw89_beacon_stat *bcn_stat = &rtwdev->phystat.bcn_stat; + struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track; + struct rtw89_beacon_dist *bcn_dist = &bcn_stat->bcn_dist; + u16 outlier_high_bcn_th = bcn_track->outlier_high_bcn_th; + u16 outlier_low_bcn_th = bcn_track->outlier_low_bcn_th; + u8 rssi = ewma_rssi_read(&rtwdev->phystat.bcn_rssi); + u16 target_bcn_th = bcn_track->target_bcn_th; + u16 low_bcn_th = bcn_track->low_bcn_th; + u16 med_bcn_th = bcn_track->med_bcn_th; + u16 beacon_int = bcn_track->beacon_int; + u16 bcn_timeout; + + if (pkt_stat->beacon_nr < low_bcn_th) { + bcn_timeout = (RTW89_BCN_TRACK_TARGET_BCN * beacon_int) / PERCENT; + goto out; + } + + if (bcn_dist->outlier_count >= outlier_high_bcn_th) { + bcn_timeout = bcn_dist->max; + goto out; + } + + if (pkt_stat->beacon_nr < med_bcn_th) { + if (bcn_dist->outlier_count > outlier_low_bcn_th) + bcn_timeout = (bcn_dist->max + bcn_dist->upper_bound) / 2; + else + bcn_timeout = bcn_dist->upper_bound + + RTW89_BCN_TRACK_EXTEND_TIMEOUT; + + goto out; + } + + if (rssi >= RTW89_BCN_TRACK_STRONG_RSSI) { + if (rtw89_bcn_get_coverage(rtwdev, RTW89_BCN_TRACK_COVERAGE_TH) >= 90) { + /* ideal case */ + bcn_timeout = 0; + } else { + u16 offset_tu = bcn_track->tbtt_offset / 1024; + u16 upper_bound; + + upper_bound = + rtw89_bcn_get_histogram_bound(rtwdev, target_bcn_th); + bcn_timeout = + _rtw89_bcn_calc_drift(upper_bound, offset_tu, beacon_int); + } + + goto out; + } + + bcn_timeout = bcn_stat->drift[target_bcn_th]; + +out: + bcn_track->bcn_timeout = bcn_timeout + rtw89_bcn_get_rx_time(rtwdev, chan); +} + +static void rtw89_bcn_update_timeout(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ + rtw89_bcn_calc_drift(rtwdev); + rtw89_bcn_calc_distribution(rtwdev); + rtw89_bcn_calc_timeout(rtwdev, rtwvif_link); +} + +static void rtw89_core_bcn_track(struct rtw89_dev *rtwdev) +{ + struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track; + struct rtw89_vif_link *rtwvif_link; + struct rtw89_vif *rtwvif; + unsigned int link_id; + + if (!RTW89_CHK_FW_FEATURE(BEACON_TRACKING, &rtwdev->fw)) + return; + + if (!rtwdev->lps_enabled) + return; + + if (!bcn_track->is_data_ready) + return; + + rtw89_for_each_rtwvif(rtwdev, rtwvif) { + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) { + if (!(rtwvif_link->wifi_role == RTW89_WIFI_ROLE_STATION || + rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT)) + continue; + + rtw89_bcn_update_tbtt_offset(rtwdev, rtwvif_link); + rtw89_bcn_update_timeout(rtwdev, rtwvif_link); + } + } +} + +static bool rtw89_core_bcn_track_can_lps(struct rtw89_dev *rtwdev) +{ + struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track; + + if (!RTW89_CHK_FW_FEATURE(BEACON_TRACKING, &rtwdev->fw)) + return true; + + return bcn_track->is_data_ready; +} + +static void rtw89_core_bcn_track_assoc(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ +#define RTW89_BCN_TRACK_MED_BCN 70 +#define RTW89_BCN_TRACK_LOW_BCN 30 +#define RTW89_BCN_TRACK_OUTLIER_HIGH_BCN 30 +#define RTW89_BCN_TRACK_OUTLIER_LOW_BCN 20 + struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track; + u32 period = jiffies_to_msecs(RTW89_TRACK_WORK_PERIOD); + struct ieee80211_bss_conf *bss_conf; + u32 beacons_in_period; + u32 bcn_intvl_us; + u16 beacon_int; + u8 dtim; + + rcu_read_lock(); + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + beacon_int = bss_conf->beacon_int; + dtim = bss_conf->dtim_period; + rcu_read_unlock(); + + beacons_in_period = period / beacon_int / dtim; + bcn_intvl_us = ieee80211_tu_to_usec(beacon_int); + + bcn_track->low_bcn_th = + (beacons_in_period * RTW89_BCN_TRACK_LOW_BCN) / PERCENT; + bcn_track->med_bcn_th = + (beacons_in_period * RTW89_BCN_TRACK_MED_BCN) / PERCENT; + bcn_track->outlier_low_bcn_th = + (RTW89_BCN_TRACK_STAT_NR * RTW89_BCN_TRACK_OUTLIER_LOW_BCN) / PERCENT; + bcn_track->outlier_high_bcn_th = + (RTW89_BCN_TRACK_STAT_NR * RTW89_BCN_TRACK_OUTLIER_HIGH_BCN) / PERCENT; + bcn_track->target_bcn_th = + (RTW89_BCN_TRACK_STAT_NR * RTW89_BCN_TRACK_TARGET_BCN) / PERCENT; + + bcn_track->close_bcn_intvl_th = ieee80211_tu_to_usec(beacon_int - 3); + bcn_track->tbtt_diff_th = (bcn_intvl_us * 85) / PERCENT; + bcn_track->beacon_int = beacon_int; + bcn_track->dtim = dtim; +} + +static void rtw89_core_bcn_track_reset(struct rtw89_dev *rtwdev) +{ + memset(&rtwdev->phystat.bcn_stat, 0, sizeof(rtwdev->phystat.bcn_stat)); + memset(&rtwdev->bcn_track, 0, sizeof(rtwdev->bcn_track)); +} + +static void rtw89_vif_rx_bcn_stat(struct rtw89_dev *rtwdev, + struct ieee80211_bss_conf *bss_conf, + struct sk_buff *skb) +{ +#define RTW89_APPEND_TSF_2GHZ 384 +#define RTW89_APPEND_TSF_5GHZ 52 +#define RTW89_APPEND_TSF_6GHZ 52 + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; + struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); + struct rtw89_beacon_stat *bcn_stat = &rtwdev->phystat.bcn_stat; + struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track; + u32 bcn_intvl_us = ieee80211_tu_to_usec(bss_conf->beacon_int); + u64 tsf = le64_to_cpu(mgmt->u.beacon.timestamp); + u8 wp, num = bcn_stat->num; + u16 append; + + if (!RTW89_CHK_FW_FEATURE(BEACON_TRACKING, &rtwdev->fw)) + return; + + switch (rx_status->band) { + default: + case NL80211_BAND_2GHZ: + append = RTW89_APPEND_TSF_2GHZ; + break; + case NL80211_BAND_5GHZ: + append = RTW89_APPEND_TSF_5GHZ; + break; + case NL80211_BAND_6GHZ: + append = RTW89_APPEND_TSF_6GHZ; + break; + } + + wp = bcn_stat->wp; + div_u64_rem(tsf - append, bcn_intvl_us, &bcn_stat->tbtt_us[wp]); + bcn_stat->tbtt_tu[wp] = bcn_stat->tbtt_us[wp] / 1024; + bcn_stat->wp = (wp + 1) % RTW89_BCN_TRACK_STAT_NR; + bcn_stat->num = umin(num + 1, RTW89_BCN_TRACK_STAT_NR); + bcn_track->is_data_ready = bcn_stat->num == RTW89_BCN_TRACK_STAT_NR; +} + static void rtw89_vif_rx_stats_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { @@ -2272,7 +2703,6 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac, rtw89_vif_sync_bcn_tsf(rtwvif_link, hdr, skb->len); rtw89_fw_h2c_rssi_offload(rtwdev, phy_ppdu); } - pkt_stat->beacon_nr++; if (phy_ppdu) { ewma_rssi_add(&rtwdev->phystat.bcn_rssi, phy_ppdu->rssi_avg); @@ -2280,7 +2710,11 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac, rtwvif_link->bcn_bw_idx = phy_ppdu->bw_idx; } + pkt_stat->beacon_nr++; pkt_stat->beacon_rate = desc_info->data_rate; + pkt_stat->beacon_len = skb->len; + + rtw89_vif_rx_bcn_stat(rtwdev, bss_conf, skb); } if (!ether_addr_equal(bss_conf->addr, hdr->addr1)) @@ -3697,6 +4131,9 @@ static void rtw89_enter_lps_track(struct rtw89_dev *rtwdev) vif->type == NL80211_IFTYPE_P2P_CLIENT)) continue; + if (!rtw89_core_bcn_track_can_lps(rtwdev)) + continue; + rtw89_enter_lps(rtwdev, rtwvif, true); } } @@ -3883,6 +4320,7 @@ static void rtw89_track_work(struct wiphy *wiphy, struct wiphy_work *work) rtw89_btc_ntfy_wl_sta(rtwdev); } rtw89_mac_bf_monitor_track(rtwdev); + rtw89_core_bcn_track(rtwdev); rtw89_phy_stat_track(rtwdev); rtw89_phy_env_monitor_track(rtwdev); rtw89_phy_dig(rtwdev); @@ -4129,8 +4567,10 @@ int rtw89_core_sta_link_disassoc(struct rtw89_dev *rtwdev, rtw89_assoc_link_clr(rtwsta_link); - if (vif->type == NL80211_IFTYPE_STATION) + if (vif->type == NL80211_IFTYPE_STATION) { rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, false); + rtw89_core_bcn_track_reset(rtwdev); + } if (rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT) rtw89_p2p_noa_once_deinit(rtwvif_link); @@ -4271,6 +4711,7 @@ int rtw89_core_sta_link_assoc(struct rtw89_dev *rtwdev, BTC_ROLE_MSTS_STA_CONN_END); rtw89_core_get_no_ul_ofdma_htc(rtwdev, &rtwsta_link->htc_template, chan); rtw89_phy_ul_tb_assoc(rtwdev, rtwvif_link); + rtw89_core_bcn_track_assoc(rtwdev, rtwvif_link); ret = rtw89_fw_h2c_general_pkt(rtwdev, rtwvif_link, rtwsta_link->mac_id); if (ret) { diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 43e10278e14d..ca48426c577f 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4622,6 +4622,7 @@ enum rtw89_fw_feature { RTW89_FW_FEATURE_SCAN_OFFLOAD_EXTRA_OP, RTW89_FW_FEATURE_RFK_NTFY_MCC_V0, RTW89_FW_FEATURE_LPS_DACK_BY_C2H_REG, + RTW89_FW_FEATURE_BEACON_TRACKING, }; struct rtw89_fw_suit { @@ -5074,9 +5075,36 @@ struct rtw89_pkt_drop_params { struct rtw89_pkt_stat { u16 beacon_nr; u8 beacon_rate; + u32 beacon_len; u32 rx_rate_cnt[RTW89_HW_RATE_NR]; }; +#define RTW89_BCN_TRACK_STAT_NR 32 +#define RTW89_BCN_TRACK_SCALE_FACTOR 10 +#define RTW89_BCN_TRACK_MAX_BIN_NUM 6 +#define RTW89_BCN_TRACK_BIN_WIDTH 5 +#define RTW89_BCN_TRACK_TARGET_BCN 80 + +struct rtw89_beacon_dist { + u16 min; + u16 max; + u16 outlier_count; + u16 lower_bound; + u16 upper_bound; + u16 bins[RTW89_BCN_TRACK_MAX_BIN_NUM]; +}; + +struct rtw89_beacon_stat { + u8 num; + u8 wp; + u16 tbtt_tu_min; + u16 tbtt_tu_max; + u16 drift[RTW89_BCN_TRACK_STAT_NR]; + u32 tbtt_us[RTW89_BCN_TRACK_STAT_NR]; + u16 tbtt_tu[RTW89_BCN_TRACK_STAT_NR]; + struct rtw89_beacon_dist bcn_dist; +}; + DECLARE_EWMA(thermal, 4, 4); struct rtw89_phy_stat { @@ -5085,6 +5113,7 @@ struct rtw89_phy_stat { struct ewma_rssi bcn_rssi; struct rtw89_pkt_stat cur_pkt_stat; struct rtw89_pkt_stat last_pkt_stat; + struct rtw89_beacon_stat bcn_stat; }; enum rtw89_rfk_report_state { @@ -5882,6 +5911,24 @@ struct rtw89_mlo_info { struct rtw89_wait_info wait; }; +struct rtw89_beacon_track_info { + bool is_data_ready; + u32 tbtt_offset; /* in unit of microsecond */ + u16 bcn_timeout; /* in unit of millisecond */ + + /* The following are constant and set at association. */ + u8 dtim; + u16 beacon_int; + u16 low_bcn_th; + u16 med_bcn_th; + u16 high_bcn_th; + u16 target_bcn_th; + u16 outlier_low_bcn_th; + u16 outlier_high_bcn_th; + u32 close_bcn_intvl_th; + u32 tbtt_diff_th; +}; + struct rtw89_dev { struct ieee80211_hw *hw; struct device *dev; @@ -5896,6 +5943,7 @@ struct rtw89_dev { const struct rtw89_pci_info *pci_info; const struct rtw89_rfe_parms *rfe_parms; struct rtw89_hal hal; + struct rtw89_beacon_track_info bcn_track; struct rtw89_mcc_info mcc; struct rtw89_mlo_info mlo; struct rtw89_mac_info mac; @@ -7454,7 +7502,7 @@ void rtw89_vif_type_mapping(struct rtw89_vif_link *rtwvif_link, bool assoc); int rtw89_chip_info_setup(struct rtw89_dev *rtwdev); void rtw89_chip_cfg_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link); -bool rtw89_ra_report_to_bitrate(struct rtw89_dev *rtwdev, u8 rpt_rate, u16 *bitrate); +bool rtw89_legacy_rate_to_bitrate(struct rtw89_dev *rtwdev, u8 legacy_rate, u16 *bitrate); int rtw89_regd_setup(struct rtw89_dev *rtwdev); int rtw89_regd_init_hint(struct rtw89_dev *rtwdev); const char *rtw89_regd_get_string(enum rtw89_regulation_type regd); diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 16e59a4a486e..cc1956245f9b 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -835,6 +835,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 90, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 91, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 110, 0, BEACON_FILTER), + __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 122, 0, BEACON_TRACKING), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, SCAN_OFFLOAD_EXTRA_OP), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, LPS_DACK_BY_C2H_REG), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, CRASH_TRIGGER_TYPE_1), @@ -846,6 +847,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 56, 10, BEACON_FILTER), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 80, 0, WOW_REASON_V1), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 128, 0, BEACON_LOSS_COUNT_V1), + __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 129, 1, BEACON_TRACKING), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 30, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 11, 0, MACID_PAUSE_SLEEP), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 35, 0, SCAN_OFFLOAD), @@ -864,6 +866,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 71, 0, BEACON_LOSS_COUNT_V1), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 76, 0, LPS_DACK_BY_C2H_REG), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 79, 0, CRASH_TRIGGER_TYPE_1), + __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 80, 0, BEACON_TRACKING), }; static void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw, @@ -3990,6 +3993,93 @@ int rtw89_fw_h2c_update_beacon_be(struct rtw89_dev *rtwdev, } EXPORT_SYMBOL(rtw89_fw_h2c_update_beacon_be); +int rtw89_fw_h2c_tbtt_tuning(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, u32 offset) +{ + struct rtw89_h2c_tbtt_tuning *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c tbtt tuning\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_tbtt_tuning *)skb->data; + + h2c->w0 = le32_encode_bits(rtwvif_link->phy_idx, RTW89_H2C_TBTT_TUNING_W0_BAND) | + le32_encode_bits(rtwvif_link->port, RTW89_H2C_TBTT_TUNING_W0_PORT); + h2c->w1 = le32_encode_bits(offset, RTW89_H2C_TBTT_TUNING_W1_SHIFT); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, H2C_CL_MAC_PS, + H2C_FUNC_TBTT_TUNING, 0, 0, + len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} + +int rtw89_fw_h2c_pwr_lvl(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) +{ +#define RTW89_BCN_TO_VAL_MIN 4 +#define RTW89_BCN_TO_VAL_MAX 64 +#define RTW89_DTIM_TO_VAL_MIN 7 +#define RTW89_DTIM_TO_VAL_MAX 15 + struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track; + struct rtw89_h2c_pwr_lvl *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + u8 bcn_to_val; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c pwr lvl\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_pwr_lvl *)skb->data; + + bcn_to_val = clamp_t(u8, bcn_track->bcn_timeout, + RTW89_BCN_TO_VAL_MIN, RTW89_BCN_TO_VAL_MAX); + + h2c->w0 = le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_PWR_LVL_W0_MACID) | + le32_encode_bits(bcn_to_val, RTW89_H2C_PWR_LVL_W0_BCN_TO_VAL) | + le32_encode_bits(0, RTW89_H2C_PWR_LVL_W0_PS_LVL) | + le32_encode_bits(0, RTW89_H2C_PWR_LVL_W0_TRX_LVL) | + le32_encode_bits(RTW89_DTIM_TO_VAL_MIN, + RTW89_H2C_PWR_LVL_W0_DTIM_TO_VAL); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, H2C_CL_MAC_PS, + H2C_FUNC_PS_POWER_LEVEL, 0, 0, + len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} + int rtw89_fw_h2c_role_maintain(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link, diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 3de29137b113..fad9d87d3e56 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -1602,6 +1602,28 @@ struct rtw89_h2c_bcn_upd_be { #define RTW89_H2C_BCN_UPD_BE_W7_ECSA_OFST GENMASK(30, 16) #define RTW89_H2C_BCN_UPD_BE_W7_PROTECTION_KEY_ID BIT(31) +struct rtw89_h2c_tbtt_tuning { + __le32 w0; + __le32 w1; +} __packed; + +#define RTW89_H2C_TBTT_TUNING_W0_BAND GENMASK(3, 0) +#define RTW89_H2C_TBTT_TUNING_W0_PORT GENMASK(7, 4) +#define RTW89_H2C_TBTT_TUNING_W1_SHIFT GENMASK(31, 0) + +struct rtw89_h2c_pwr_lvl { + __le32 w0; + __le32 w1; +} __packed; + +#define RTW89_H2C_PWR_LVL_W0_MACID GENMASK(7, 0) +#define RTW89_H2C_PWR_LVL_W0_BCN_TO_VAL GENMASK(15, 8) +#define RTW89_H2C_PWR_LVL_W0_PS_LVL GENMASK(19, 16) +#define RTW89_H2C_PWR_LVL_W0_TRX_LVL GENMASK(23, 20) +#define RTW89_H2C_PWR_LVL_W0_BCN_TO_LVL GENMASK(27, 24) +#define RTW89_H2C_PWR_LVL_W0_DTIM_TO_VAL GENMASK(31, 28) +#define RTW89_H2C_PWR_LVL_W1_MACID_EXT GENMASK(7, 0) + struct rtw89_h2c_role_maintain { __le32 w0; }; @@ -4201,6 +4223,8 @@ enum rtw89_ps_h2c_func { H2C_FUNC_MAC_LPS_PARM = 0x0, H2C_FUNC_P2P_ACT = 0x1, H2C_FUNC_IPS_CFG = 0x3, + H2C_FUNC_PS_POWER_LEVEL = 0x7, + H2C_FUNC_TBTT_TUNING = 0xA, NUM_OF_RTW89_PS_H2C_FUNC, }; @@ -4750,6 +4774,9 @@ int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link); int rtw89_fw_h2c_update_beacon_be(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link); +int rtw89_fw_h2c_tbtt_tuning(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, u32 offset); +int rtw89_fw_h2c_pwr_lvl(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link); int rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif_link *vif, struct rtw89_sta_link *rtwsta_link, const u8 *scan_mac_addr); int rtw89_fw_h2c_dctl_sec_cam_v1(struct rtw89_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 33a7dd9d6f0e..e4f9d251d5ef 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -4649,27 +4649,6 @@ static void rtw89_mac_port_cfg_bcn_early(struct rtw89_dev *rtwdev, BCN_ERLY_DEF); } -static void rtw89_mac_port_cfg_tbtt_shift(struct rtw89_dev *rtwdev, - struct rtw89_vif_link *rtwvif_link) -{ - const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; - const struct rtw89_port_reg *p = mac->port_base; - u16 val; - - if (rtwdev->chip->chip_id != RTL8852C) - return; - - if (rtwvif_link->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT && - rtwvif_link->wifi_role != RTW89_WIFI_ROLE_STATION) - return; - - val = FIELD_PREP(B_AX_TBTT_SHIFT_OFST_MAG, 1) | - B_AX_TBTT_SHIFT_OFST_SIGN; - - rtw89_write16_port_mask(rtwdev, rtwvif_link, p->tbtt_shift, - B_AX_TBTT_SHIFT_OFST_MASK, val); -} - void rtw89_mac_port_tsf_sync(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_vif_link *rtwvif_src, @@ -4820,7 +4799,6 @@ int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvi rtw89_mac_port_cfg_bcn_hold_time(rtwdev, rtwvif_link); rtw89_mac_port_cfg_bcn_mask_area(rtwdev, rtwvif_link); rtw89_mac_port_cfg_tbtt_early(rtwdev, rtwvif_link); - rtw89_mac_port_cfg_tbtt_shift(rtwdev, rtwvif_link); rtw89_mac_port_cfg_bss_color(rtwdev, rtwvif_link); rtw89_mac_port_cfg_mbssid(rtwdev, rtwvif_link); rtw89_mac_port_cfg_func_en(rtwdev, rtwvif_link, true); diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 01a03d2de3ff..06598723074e 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -2943,7 +2943,7 @@ static void __rtw89_phy_c2h_ra_rpt_iter(struct rtw89_sta_link *rtwsta_link, } if (mode == RTW89_RA_RPT_MODE_LEGACY) { - valid = rtw89_ra_report_to_bitrate(rtwdev, rate, &legacy_bitrate); + valid = rtw89_legacy_rate_to_bitrate(rtwdev, rate, &legacy_bitrate); if (!valid) return; } diff --git a/drivers/net/wireless/realtek/rtw89/ps.c b/drivers/net/wireless/realtek/rtw89/ps.c index 652f8fc81b79..cf58121eb541 100644 --- a/drivers/net/wireless/realtek/rtw89/ps.c +++ b/drivers/net/wireless/realtek/rtw89/ps.c @@ -119,6 +119,9 @@ static void __rtw89_enter_lps_link(struct rtw89_dev *rtwdev, rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_FW_CTRL); rtw89_fw_h2c_lps_parm(rtwdev, &lps_param); + + if (RTW89_CHK_FW_FEATURE(BEACON_TRACKING, &rtwdev->fw)) + rtw89_fw_h2c_pwr_lvl(rtwdev, rtwvif_link); } static void __rtw89_leave_lps(struct rtw89_dev *rtwdev, From 194b7ce982471468569299991b110049c4617163 Mon Sep 17 00:00:00 2001 From: Kuan-Chung Chen Date: Mon, 11 Aug 2025 20:37:38 +0800 Subject: [PATCH 01260/11391] wifi: rtw89: debug: add beacon_info debugfs Add debugfs beacon_info to display the information of beacon tracking. The screenshot as below: [Beacon info] count: 15 interval: 100 dtim: 1 raw rssi: 146 hw rate: 0 length: 407 [Distribution] tbtt 00 - 04: 26 05 - 09: 5 10 - 14: 1 15 - 19: 0 20 - 24: 0 25 - 29: 0 drift 0: 9 1: 7 2: 3 3: 3 4: 4 5: 1 6: 1 7: 2 8: 1 11: 1 lower bound: 0 upper bound: 10 outlier count: 1 [Tracking] tbtt offset: 20 bcn timeout: 19 Signed-off-by: Kuan-Chung Chen Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250811123744.15361-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/debug.c | 61 ++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c index afdfb9647fc1..a37cdd73ddc3 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.c +++ b/drivers/net/wireless/realtek/rtw89/debug.c @@ -86,6 +86,7 @@ struct rtw89_debugfs { struct rtw89_debugfs_priv stations; struct rtw89_debugfs_priv disable_dm; struct rtw89_debugfs_priv mlo_mode; + struct rtw89_debugfs_priv beacon_info; }; struct rtw89_debugfs_iter_data { @@ -4298,6 +4299,64 @@ rtw89_debug_priv_mlo_mode_set(struct rtw89_dev *rtwdev, return count; } +static ssize_t +rtw89_debug_priv_beacon_info_get(struct rtw89_dev *rtwdev, + struct rtw89_debugfs_priv *debugfs_priv, + char *buf, size_t bufsz) +{ + struct rtw89_pkt_stat *pkt_stat = &rtwdev->phystat.last_pkt_stat; + struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track; + struct rtw89_beacon_stat *bcn_stat = &rtwdev->phystat.bcn_stat; + struct rtw89_beacon_dist *bcn_dist = &bcn_stat->bcn_dist; + u16 upper, lower = bcn_stat->tbtt_tu_min; + char *p = buf, *end = buf + bufsz; + u16 *drift = bcn_stat->drift; + u8 bcn_num = bcn_stat->num; + u8 count; + u8 i; + + p += scnprintf(p, end - p, "[Beacon info]\n"); + p += scnprintf(p, end - p, "count: %u\n", pkt_stat->beacon_nr); + p += scnprintf(p, end - p, "interval: %u\n", bcn_track->beacon_int); + p += scnprintf(p, end - p, "dtim: %u\n", bcn_track->dtim); + p += scnprintf(p, end - p, "raw rssi: %lu\n", + ewma_rssi_read(&rtwdev->phystat.bcn_rssi)); + p += scnprintf(p, end - p, "hw rate: %u\n", pkt_stat->beacon_rate); + p += scnprintf(p, end - p, "length: %u\n", pkt_stat->beacon_len); + + p += scnprintf(p, end - p, "\n[Distribution]\n"); + p += scnprintf(p, end - p, "tbtt\n"); + for (i = 0; i < RTW89_BCN_TRACK_MAX_BIN_NUM; i++) { + upper = lower + RTW89_BCN_TRACK_BIN_WIDTH - 1; + if (i == RTW89_BCN_TRACK_MAX_BIN_NUM - 1) + upper = max(upper, bcn_stat->tbtt_tu_max); + + p += scnprintf(p, end - p, "%02u - %02u: %u\n", + lower, upper, bcn_dist->bins[i]); + + lower = upper + 1; + } + + p += scnprintf(p, end - p, "\ndrift\n"); + + for (i = 0; i < bcn_num; i += count) { + count = 1; + while (i + count < bcn_num && drift[i] == drift[i + count]) + count++; + + p += scnprintf(p, end - p, "%u: %u\n", drift[i], count); + } + p += scnprintf(p, end - p, "\nlower bound: %u\n", bcn_dist->lower_bound); + p += scnprintf(p, end - p, "upper bound: %u\n", bcn_dist->upper_bound); + p += scnprintf(p, end - p, "outlier count: %u\n", bcn_dist->outlier_count); + + p += scnprintf(p, end - p, "\n[Tracking]\n"); + p += scnprintf(p, end - p, "tbtt offset: %u\n", bcn_track->tbtt_offset); + p += scnprintf(p, end - p, "bcn timeout: %u\n", bcn_track->bcn_timeout); + + return p - buf; +} + #define rtw89_debug_priv_get(name, opts...) \ { \ .cb_read = rtw89_debug_priv_ ##name## _get, \ @@ -4356,6 +4415,7 @@ static const struct rtw89_debugfs rtw89_debugfs_templ = { .stations = rtw89_debug_priv_get(stations, RLOCK), .disable_dm = rtw89_debug_priv_set_and_get(disable_dm, RWLOCK), .mlo_mode = rtw89_debug_priv_set_and_get(mlo_mode, RWLOCK), + .beacon_info = rtw89_debug_priv_get(beacon_info), }; #define rtw89_debugfs_add(name, mode, fopname, parent) \ @@ -4401,6 +4461,7 @@ void rtw89_debugfs_add_sec1(struct rtw89_dev *rtwdev, struct dentry *debugfs_top rtw89_debugfs_add_r(stations); rtw89_debugfs_add_rw(disable_dm); rtw89_debugfs_add_rw(mlo_mode); + rtw89_debugfs_add_r(beacon_info); } void rtw89_debugfs_init(struct rtw89_dev *rtwdev) From 38846585f9df9af1f7261d85134a5510fc079458 Mon Sep 17 00:00:00 2001 From: Kuan-Chung Chen Date: Mon, 11 Aug 2025 20:37:39 +0800 Subject: [PATCH 01261/11391] wifi: rtw89: wow: remove notify during WoWLAN net-detect In WoWLAN net-detect mode, the firmware periodically performs scans and sends scan reports via C2H, which driver does not need. These unnecessary C2H events cause firmware watchdog timeout, leading to unexpected wakeups and SER 0x2599 on 8922AE. Signed-off-by: Kuan-Chung Chen Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250811123744.15361-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index cc1956245f9b..398d8ab98f63 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -7213,7 +7213,6 @@ static void rtw89_pno_scan_add_chan_ax(struct rtw89_dev *rtwdev, struct rtw89_pktofld_info *info; u8 probe_count = 0; - ch_info->notify_action = RTW89_SCANOFLD_DEBUG_MASK; ch_info->dfs_ch = chan_type == RTW89_CHAN_DFS; ch_info->bw = RTW89_SCAN_WIDTH; ch_info->tx_pkt = true; @@ -7354,7 +7353,6 @@ static void rtw89_pno_scan_add_chan_be(struct rtw89_dev *rtwdev, int chan_type, struct rtw89_pktofld_info *info; u8 probe_count = 0, i; - ch_info->notify_action = RTW89_SCANOFLD_DEBUG_MASK; ch_info->dfs_ch = chan_type == RTW89_CHAN_DFS; ch_info->bw = RTW89_SCAN_WIDTH; ch_info->tx_null = false; From b521685da35ebf091e51f9ea9ad2896a4ddb6e98 Mon Sep 17 00:00:00 2001 From: Kuan-Chung Chen Date: Mon, 11 Aug 2025 20:37:40 +0800 Subject: [PATCH 01262/11391] wifi: rtw89: 8851b: rfk: update IQK TIA setting With the new TIA setting of RX IQK, unstable RX throughput can be avoided, especially in medium-high attenuation environments. Signed-off-by: Kuan-Chung Chen Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250811123744.15361-5-pkshih@realtek.com --- .../net/wireless/realtek/rtw89/rtw8851b_rfk.c | 85 ++++++++++++------- 1 file changed, 54 insertions(+), 31 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c index 7a319a6c838a..a7867b0e083a 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c @@ -17,7 +17,7 @@ #define DPK_RF_REG_NUM_8851B 4 #define DPK_KSET_NUM 4 #define RTW8851B_RXK_GROUP_NR 4 -#define RTW8851B_RXK_GROUP_IDX_NR 2 +#define RTW8851B_RXK_GROUP_IDX_NR 4 #define RTW8851B_TXK_GROUP_NR 1 #define RTW8851B_IQK_VER 0x14 #define RTW8851B_IQK_SS 1 @@ -114,9 +114,9 @@ static const u32 _tssi_de_mcs_10m[RF_PATH_NUM_8851B] = {0x5830}; static const u32 g_idxrxgain[RTW8851B_RXK_GROUP_NR] = {0x10e, 0x116, 0x28e, 0x296}; static const u32 g_idxattc2[RTW8851B_RXK_GROUP_NR] = {0x0, 0xf, 0x0, 0xf}; static const u32 g_idxrxagc[RTW8851B_RXK_GROUP_NR] = {0x0, 0x1, 0x2, 0x3}; -static const u32 a_idxrxgain[RTW8851B_RXK_GROUP_IDX_NR] = {0x10C, 0x28c}; -static const u32 a_idxattc2[RTW8851B_RXK_GROUP_IDX_NR] = {0xf, 0xf}; -static const u32 a_idxrxagc[RTW8851B_RXK_GROUP_IDX_NR] = {0x4, 0x6}; +static const u32 a_idxrxgain[RTW8851B_RXK_GROUP_IDX_NR] = {0x10C, 0x112, 0x28c, 0x292}; +static const u32 a_idxattc2[RTW8851B_RXK_GROUP_IDX_NR] = {0xf, 0xf, 0xf, 0xf}; +static const u32 a_idxrxagc[RTW8851B_RXK_GROUP_IDX_NR] = {0x4, 0x5, 0x6, 0x7}; static const u32 a_power_range[RTW8851B_TXK_GROUP_NR] = {0x0}; static const u32 a_track_range[RTW8851B_TXK_GROUP_NR] = {0x6}; static const u32 a_gain_bb[RTW8851B_TXK_GROUP_NR] = {0x0a}; @@ -139,17 +139,6 @@ static const u32 dpk_rf_reg[DPK_RF_REG_NUM_8851B] = {0xde, 0x8f, 0x5, 0x10005}; static void _set_ch(struct rtw89_dev *rtwdev, u32 val); -static u8 _rxk_5ghz_group_from_idx(u8 idx) -{ - /* There are four RXK groups (RTW8851B_RXK_GROUP_NR), but only group 0 - * and 2 are used in 5 GHz band, so reduce elements to 2. - */ - if (idx < RTW8851B_RXK_GROUP_IDX_NR) - return idx * 2; - - return 0; -} - static u8 _kpath(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { return RF_A; @@ -196,7 +185,7 @@ static void _txck_force(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, static void _rxck_force(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, bool force, enum adc_ck ck) { - static const u32 ck960_8851b[] = {0x8, 0x2, 0x2, 0x4, 0xf, 0xa, 0x93}; + static const u32 ck960_8851b[] = {0x8, 0x2, 0x2, 0x4, 0xf, 0xa, 0x92}; static const u32 ck1920_8851b[] = {0x9, 0x0, 0x0, 0x3, 0xf, 0xa, 0x49}; const u32 *data; @@ -905,18 +894,27 @@ static bool _rxk_5g_group_sel(struct rtw89_dev *rtwdev, bool kfail = false; bool notready; u32 rf_0; - u8 idx; + u32 val; u8 gp; rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); - for (idx = 0; idx < RTW8851B_RXK_GROUP_IDX_NR; idx++) { - gp = _rxk_5ghz_group_from_idx(idx); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWE, RFREG_MASK, 0x1000); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWA, RFREG_MASK, 0x4); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWD0, RFREG_MASK, 0x17); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWA, RFREG_MASK, 0x5); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWD0, RFREG_MASK, 0x27); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWE, RFREG_MASK, 0x0); + val = rtw89_read_rf(rtwdev, RF_PATH_A, RR_RXA2, 0x20); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, RR_MOD_MASK, 0xc); + + for (gp = 0; gp < RTW8851B_RXK_GROUP_IDX_NR; gp++) { rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, gp = %x\n", path, gp); - rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, RR_MOD_RGM, a_idxrxgain[idx]); - rtw89_write_rf(rtwdev, RF_PATH_A, RR_RXA2, RR_RXA2_ATT, a_idxattc2[idx]); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, RR_MOD_RGM, a_idxrxgain[gp]); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_RXA2, RR_RXA2_ATT, a_idxattc2[gp]); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_RXA2, 0x20, 0x1); rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_SEL, 0x1); rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G3, 0x0); @@ -926,7 +924,7 @@ static bool _rxk_5g_group_sel(struct rtw89_dev *rtwdev, fsleep(100); rf_0 = rtw89_read_rf(rtwdev, path, RR_MOD, RFREG_MASK); rtw89_phy_write32_mask(rtwdev, R_IQK_DIF2, B_IQK_DIF2_RXPI, rf_0); - rtw89_phy_write32_mask(rtwdev, R_IQK_RXA, B_IQK_RXAGC, a_idxrxagc[idx]); + rtw89_phy_write32_mask(rtwdev, R_IQK_RXA, B_IQK_RXAGC, a_idxrxagc[gp]); rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, 0x11); notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_RXAGC); @@ -959,6 +957,7 @@ static bool _rxk_5g_group_sel(struct rtw89_dev *rtwdev, _iqk_sram(rtwdev, path); if (kfail) { + rtw89_phy_write32_mask(rtwdev, R_IQK_RES, B_IQK_RES_RXCFIR, 0x0); rtw89_phy_write32_mask(rtwdev, R_RXIQC + (path << 8), MASKDWORD, iqk_info->nb_rxcfir[path] | 0x2); iqk_info->is_wb_txiqk[path] = false; @@ -968,6 +967,14 @@ static bool _rxk_5g_group_sel(struct rtw89_dev *rtwdev, iqk_info->is_wb_txiqk[path] = true; } + rtw89_write_rf(rtwdev, RF_PATH_A, RR_RXA2, 0x20, val); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWE, RFREG_MASK, 0x1000); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWA, RFREG_MASK, 0x4); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWD0, RFREG_MASK, 0x37); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWA, RFREG_MASK, 0x5); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWD0, RFREG_MASK, 0x27); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWE, RFREG_MASK, 0x0); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, kfail = 0x%x, 0x8%x3c = 0x%x\n", path, kfail, 1 << path, iqk_info->nb_rxcfir[path]); @@ -980,17 +987,26 @@ static bool _iqk_5g_nbrxk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; bool kfail = false; bool notready; - u8 idx = 0x1; + u8 gp = 2; u32 rf_0; - u8 gp; - - gp = _rxk_5ghz_group_from_idx(idx); + u32 val; rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, gp = %x\n", path, gp); - rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, RR_MOD_RGM, a_idxrxgain[idx]); - rtw89_write_rf(rtwdev, RF_PATH_A, RR_RXA2, RR_RXA2_ATT, a_idxattc2[idx]); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWE, RFREG_MASK, 0x1000); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWA, RFREG_MASK, 0x4); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWD0, RFREG_MASK, 0x17); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWA, RFREG_MASK, 0x5); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWD0, RFREG_MASK, 0x27); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWE, RFREG_MASK, 0x0); + + val = rtw89_read_rf(rtwdev, RF_PATH_A, RR_RXA2, 0x20); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, RR_MOD_MASK, 0xc); + + rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, RR_MOD_RGM, a_idxrxgain[gp]); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_RXA2, RR_RXA2_ATT, a_idxattc2[gp]); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_RXA2, 0x20, 0x1); rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_SEL, 0x1); rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G3, 0x0); @@ -1000,7 +1016,7 @@ static bool _iqk_5g_nbrxk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, fsleep(100); rf_0 = rtw89_read_rf(rtwdev, path, RR_MOD, RFREG_MASK); rtw89_phy_write32_mask(rtwdev, R_IQK_DIF2, B_IQK_DIF2_RXPI, rf_0); - rtw89_phy_write32_mask(rtwdev, R_IQK_RXA, B_IQK_RXAGC, a_idxrxagc[idx]); + rtw89_phy_write32_mask(rtwdev, R_IQK_RXA, B_IQK_RXAGC, a_idxrxagc[gp]); rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, 0x11); notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_RXAGC); @@ -1026,6 +1042,7 @@ static bool _iqk_5g_nbrxk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, kfail = !!rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, B_NCTL_RPT_FLG); if (kfail) { + rtw89_phy_write32_mask(rtwdev, R_IQK_RES + (path << 8), 0xf, 0x0); rtw89_phy_write32_mask(rtwdev, R_RXIQC + (path << 8), MASKDWORD, 0x40000002); iqk_info->is_wb_rxiqk[path] = false; @@ -1033,6 +1050,14 @@ static bool _iqk_5g_nbrxk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, iqk_info->is_wb_rxiqk[path] = false; } + rtw89_write_rf(rtwdev, RF_PATH_A, RR_RXA2, 0x20, val); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWE, RFREG_MASK, 0x1000); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWA, RFREG_MASK, 0x4); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWD0, RFREG_MASK, 0x37); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWA, RFREG_MASK, 0x5); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWD0, RFREG_MASK, 0x27); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWE, RFREG_MASK, 0x0); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, kfail = 0x%x, 0x8%x3c = 0x%x\n", path, kfail, 1 << path, iqk_info->nb_rxcfir[path]); @@ -1664,8 +1689,6 @@ static void _iqk_init(struct rtw89_dev *rtwdev) struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; u8 idx, path; - rtw89_phy_write32_mask(rtwdev, R_IQKINF, MASKDWORD, 0x0); - if (iqk_info->is_iqk_init) return; From 5b2341efbb7af974925985f7798321fe92b4f8af Mon Sep 17 00:00:00 2001 From: Kuan-Chung Chen Date: Mon, 11 Aug 2025 20:39:13 +0800 Subject: [PATCH 01263/11391] wifi: rtw89: 8851b: rfk: update TX wideband IQK Adjust TX wideband calibration from 1 to 2 loop gain settings. This can reflect in better performance in 5 GHz medium-high attenuation environments. Signed-off-by: Kuan-Chung Chen Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250811123913.15524-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/reg.h | 1 + .../net/wireless/realtek/rtw89/rtw8851b_rfk.c | 72 +++++++++++-------- 2 files changed, 42 insertions(+), 31 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index de81103a072f..0aad9dc91736 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -9126,6 +9126,7 @@ #define B_COEF_SEL_MDPD BIT(8) #define B_COEF_SEL_MDPD_V1 GENMASK(9, 8) #define B_COEF_SEL_EN BIT(31) +#define R_CFIR_COEF 0x810c #define R_CFIR_SYS 0x8120 #define R_IQK_RES 0x8124 #define B_IQK_RES_K BIT(28) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c index a7867b0e083a..84c46d2f4d85 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c @@ -18,7 +18,8 @@ #define DPK_KSET_NUM 4 #define RTW8851B_RXK_GROUP_NR 4 #define RTW8851B_RXK_GROUP_IDX_NR 4 -#define RTW8851B_TXK_GROUP_NR 1 +#define RTW8851B_A_TXK_GROUP_NR 2 +#define RTW8851B_G_TXK_GROUP_NR 1 #define RTW8851B_IQK_VER 0x14 #define RTW8851B_IQK_SS 1 #define RTW8851B_LOK_GRAM 10 @@ -117,16 +118,18 @@ static const u32 g_idxrxagc[RTW8851B_RXK_GROUP_NR] = {0x0, 0x1, 0x2, 0x3}; static const u32 a_idxrxgain[RTW8851B_RXK_GROUP_IDX_NR] = {0x10C, 0x112, 0x28c, 0x292}; static const u32 a_idxattc2[RTW8851B_RXK_GROUP_IDX_NR] = {0xf, 0xf, 0xf, 0xf}; static const u32 a_idxrxagc[RTW8851B_RXK_GROUP_IDX_NR] = {0x4, 0x5, 0x6, 0x7}; -static const u32 a_power_range[RTW8851B_TXK_GROUP_NR] = {0x0}; -static const u32 a_track_range[RTW8851B_TXK_GROUP_NR] = {0x6}; -static const u32 a_gain_bb[RTW8851B_TXK_GROUP_NR] = {0x0a}; -static const u32 a_itqt[RTW8851B_TXK_GROUP_NR] = {0x12}; -static const u32 g_power_range[RTW8851B_TXK_GROUP_NR] = {0x0}; -static const u32 g_track_range[RTW8851B_TXK_GROUP_NR] = {0x6}; -static const u32 g_gain_bb[RTW8851B_TXK_GROUP_NR] = {0x10}; -static const u32 g_itqt[RTW8851B_TXK_GROUP_NR] = {0x12}; +static const u32 a_power_range[RTW8851B_A_TXK_GROUP_NR] = {0x0, 0x0}; +static const u32 a_track_range[RTW8851B_A_TXK_GROUP_NR] = {0x7, 0x7}; +static const u32 a_gain_bb[RTW8851B_A_TXK_GROUP_NR] = {0x08, 0x0d}; +static const u32 a_itqt[RTW8851B_A_TXK_GROUP_NR] = {0x12, 0x12}; +static const u32 a_att_smxr[RTW8851B_A_TXK_GROUP_NR] = {0x0, 0x2}; +static const u32 g_power_range[RTW8851B_G_TXK_GROUP_NR] = {0x0}; +static const u32 g_track_range[RTW8851B_G_TXK_GROUP_NR] = {0x6}; +static const u32 g_gain_bb[RTW8851B_G_TXK_GROUP_NR] = {0x10}; +static const u32 g_itqt[RTW8851B_G_TXK_GROUP_NR] = {0x12}; -static const u32 rtw8851b_backup_bb_regs[] = {0xc0d4, 0xc0d8, 0xc0c4, 0xc0ec, 0xc0e8}; +static const u32 rtw8851b_backup_bb_regs[] = { + 0xc0d4, 0xc0d8, 0xc0c4, 0xc0ec, 0xc0e8, 0x12a0, 0xc0f0}; static const u32 rtw8851b_backup_rf_regs[] = { 0xef, 0xde, 0x0, 0x1e, 0x2, 0x85, 0x90, 0x5}; @@ -789,7 +792,7 @@ static bool _iqk_one_shot(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, "[IQK]============ S%d ID_NBTXK ============\n", path); rtw89_phy_write32_mask(rtwdev, R_UPD_CLK, B_IQK_RFC_ON, 0x0); rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_TXT, - 0x00b); + 0x11); iqk_cmd = 0x408 | (1 << (4 + path)); break; case ID_NBRXK: @@ -807,7 +810,7 @@ static bool _iqk_one_shot(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, rtw89_phy_write32_mask(rtwdev, R_NCTL_CFG, MASKDWORD, iqk_cmd + 1); notready = _iqk_check_cal(rtwdev, path); if (iqk_info->iqk_sram_en && - (ktype == ID_NBRXK || ktype == ID_RXK)) + (ktype == ID_NBRXK || ktype == ID_RXK || ktype == ID_NBTXK)) _iqk_sram(rtwdev, path); rtw89_phy_write32_mask(rtwdev, R_UPD_CLK, B_IQK_RFC_ON, 0x0); @@ -1174,6 +1177,7 @@ static void _iqk_rxclk_setting(struct rtw89_dev *rtwdev, u8 path) static bool _txk_5g_group_sel(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u8 path) { + static const u8 a_idx[RTW8851B_A_TXK_GROUP_NR] = {2, 3}; struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; bool kfail = false; bool notready; @@ -1181,16 +1185,20 @@ static bool _txk_5g_group_sel(struct rtw89_dev *rtwdev, rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); - for (gp = 0x0; gp < RTW8851B_TXK_GROUP_NR; gp++) { + rtw89_phy_write32_mask(rtwdev, R_CFIR_COEF, MASKDWORD, 0x33332222); + + for (gp = 0x0; gp < RTW8851B_A_TXK_GROUP_NR; gp++) { rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR0, a_power_range[gp]); rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR1, a_track_range[gp]); rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, a_gain_bb[gp]); + rtw89_write_rf(rtwdev, path, RR_BIASA, RR_BIASA_A, a_att_smxr[gp]); rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_SEL, 0x1); rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G3, 0x1); rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G2, 0x0); - rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_GP, gp); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_GP, a_idx[gp]); rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_TXT, 0x11); rtw89_phy_write32_mask(rtwdev, R_KIP_IQP, MASKDWORD, a_itqt[gp]); notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_NBTXK); @@ -1231,7 +1239,9 @@ static bool _txk_2g_group_sel(struct rtw89_dev *rtwdev, rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); - for (gp = 0x0; gp < RTW8851B_TXK_GROUP_NR; gp++) { + rtw89_phy_write32_mask(rtwdev, R_CFIR_COEF, MASKDWORD, 0x0); + + for (gp = 0x0; gp < RTW8851B_G_TXK_GROUP_NR; gp++) { rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR0, g_power_range[gp]); rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR1, g_track_range[gp]); rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, g_gain_bb[gp]); @@ -1274,29 +1284,29 @@ static bool _txk_2g_group_sel(struct rtw89_dev *rtwdev, static bool _iqk_5g_nbtxk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u8 path) { + static const u8 a_idx[RTW8851B_A_TXK_GROUP_NR] = {2, 3}; struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; bool kfail = false; bool notready; - u8 gp; + u8 gp = 0; rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); - for (gp = 0x0; gp < RTW8851B_TXK_GROUP_NR; gp++) { - rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR0, a_power_range[gp]); - rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR1, a_track_range[gp]); - rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, a_gain_bb[gp]); + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR0, a_power_range[gp]); + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR1, a_track_range[gp]); + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, a_gain_bb[gp]); + rtw89_write_rf(rtwdev, path, RR_BIASA, RR_BIASA_A, a_att_smxr[gp]); - rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_SEL, 0x1); - rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G3, 0x1); - rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G2, 0x0); - rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_GP, gp); - rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); - rtw89_phy_write32_mask(rtwdev, R_KIP_IQP, MASKDWORD, a_itqt[gp]); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_SEL, 0x1); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G3, 0x1); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G2, 0x0); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_GP, a_idx[gp]); + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); + rtw89_phy_write32_mask(rtwdev, R_KIP_IQP, MASKDWORD, a_itqt[gp]); - notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_NBTXK); - iqk_info->nb_txcfir[path] = - rtw89_phy_read32_mask(rtwdev, R_TXIQC, MASKDWORD) | 0x2; - } + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_NBTXK); + iqk_info->nb_txcfir[path] = + rtw89_phy_read32_mask(rtwdev, R_TXIQC, MASKDWORD) | 0x2; if (!notready) kfail = !!rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, B_NCTL_RPT_FLG); @@ -1325,7 +1335,7 @@ static bool _iqk_2g_nbtxk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); - for (gp = 0x0; gp < RTW8851B_TXK_GROUP_NR; gp++) { + for (gp = 0x0; gp < RTW8851B_G_TXK_GROUP_NR; gp++) { rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR0, g_power_range[gp]); rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR1, g_track_range[gp]); rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, g_gain_bb[gp]); From 46ac5412e406f63149f199e38279f21f87f3701a Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Mon, 11 Aug 2025 20:39:34 +0800 Subject: [PATCH 01264/11391] wifi: rtw89: 8852c: check LPS H2C command complete by C2H reg instead of done ack 8852C after FW 0.27.128.0 driver check LPS H2C command received by FW using C2H reg instead of done ack. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250811123934.15614-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 398d8ab98f63..ede4c15314a8 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -847,6 +847,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 56, 10, BEACON_FILTER), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 80, 0, WOW_REASON_V1), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 128, 0, BEACON_LOSS_COUNT_V1), + __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 128, 0, LPS_DACK_BY_C2H_REG), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 129, 1, BEACON_TRACKING), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 30, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 11, 0, MACID_PAUSE_SLEEP), From c4c16c88e78417424b4e3f33177e84baf0bc9a99 Mon Sep 17 00:00:00 2001 From: Kuan-Chung Chen Date: Mon, 11 Aug 2025 20:39:50 +0800 Subject: [PATCH 01265/11391] wifi: rtw89: fix BSSID comparison for non-transmitted BSSID For non-transmitted connections, beacons are received from the transmitted BSSID. Fix this to avoid missing beacon statistics. Signed-off-by: Kuan-Chung Chen Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250811123950.15697-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 7d522031dfa1..0ad7562632a5 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -2668,6 +2668,7 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac, struct ieee80211_bss_conf *bss_conf; struct rtw89_vif_link *rtwvif_link; const u8 *bssid = iter_data->bssid; + const u8 *target_bssid; if (rtwdev->scanning && (ieee80211_is_beacon(hdr->frame_control) || @@ -2689,7 +2690,10 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac, goto out; } - if (!ether_addr_equal(bss_conf->bssid, bssid)) + target_bssid = ieee80211_is_beacon(hdr->frame_control) && + bss_conf->nontransmitted ? + bss_conf->transmitter_bssid : bss_conf->bssid; + if (!ether_addr_equal(target_bssid, bssid)) goto out; if (is_mld) { From bf02a01d1dd5bfe76ad8db3b588a39ecac96ebee Mon Sep 17 00:00:00 2001 From: Kuan-Chung Chen Date: Mon, 11 Aug 2025 20:40:01 +0800 Subject: [PATCH 01266/11391] wifi: rtw89: fix group frames loss when connected to non-transmitted BSSID When STA connects to AP with dot11MultiBSSIDImplemented set to true, the layout of the TIM element's Partial Virtual Bitmap changes. Bits 1 to (2^n - 1) are used to indicate buffered group addressed frames (e.g., broadcast/multicast) for non-transmitted BSSIDs. Fix the interpretation of this field to ensure group addressed frames are correctly received. Signed-off-by: Kuan-Chung Chen Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250811124001.15774-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/mac.c | 26 +++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/mac_be.c | 1 + drivers/net/wireless/realtek/rtw89/reg.h | 8 +++++++ 4 files changed, 36 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index ca48426c577f..d8c40ce3ec61 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -1011,6 +1011,7 @@ struct rtw89_port_reg { u32 ptcl_dbg; u32 ptcl_dbg_info; u32 bcn_drop_all; + u32 bcn_psr_rpt; u32 hiq_win[RTW89_PORT_NUM]; }; diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index e4f9d251d5ef..48712a2994b6 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -4197,6 +4197,7 @@ static const struct rtw89_port_reg rtw89_port_base_ax = { .ptcl_dbg = R_AX_PTCL_DBG, .ptcl_dbg_info = R_AX_PTCL_DBG_INFO, .bcn_drop_all = R_AX_BCN_DROP_ALL0, + .bcn_psr_rpt = R_AX_BCN_PSR_RPT_P0, .hiq_win = {R_AX_P0MB_HGQ_WINDOW_CFG_0, R_AX_PORT_HGQ_WINDOW_CFG, R_AX_PORT_HGQ_WINDOW_CFG + 1, R_AX_PORT_HGQ_WINDOW_CFG + 2, R_AX_PORT_HGQ_WINDOW_CFG + 3}, @@ -4649,6 +4650,30 @@ static void rtw89_mac_port_cfg_bcn_early(struct rtw89_dev *rtwdev, BCN_ERLY_DEF); } +static void rtw89_mac_port_cfg_bcn_psr_rpt(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + const struct rtw89_port_reg *p = mac->port_base; + struct ieee80211_bss_conf *bss_conf; + u8 bssid_index; + u32 reg; + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + if (bss_conf->nontransmitted) + bssid_index = bss_conf->bssid_index; + else + bssid_index = 0; + + rcu_read_unlock(); + + reg = rtw89_mac_reg_by_idx(rtwdev, p->bcn_psr_rpt + rtwvif_link->port * 4, + rtwvif_link->mac_idx); + rtw89_write32_mask(rtwdev, reg, B_AX_BCAID_P0_MASK, bssid_index); +} + void rtw89_mac_port_tsf_sync(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_vif_link *rtwvif_src, @@ -4805,6 +4830,7 @@ int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvi rtw89_mac_port_tsf_resync_all(rtwdev); fsleep(BCN_ERLY_SET_DLY); rtw89_mac_port_cfg_bcn_early(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_bcn_psr_rpt(rtwdev, rtwvif_link); return 0; } diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 0078080b3999..ef69672b6862 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -56,6 +56,7 @@ static const struct rtw89_port_reg rtw89_port_base_be = { .ptcl_dbg = R_BE_PTCL_DBG, .ptcl_dbg_info = R_BE_PTCL_DBG_INFO, .bcn_drop_all = R_BE_BCN_DROP_ALL0, + .bcn_psr_rpt = R_BE_BCN_PSR_RPT_P0, .hiq_win = {R_BE_P0MB_HGQ_WINDOW_CFG_0, R_BE_PORT_HGQ_WINDOW_CFG, R_BE_PORT_HGQ_WINDOW_CFG + 1, R_BE_PORT_HGQ_WINDOW_CFG + 2, R_BE_PORT_HGQ_WINDOW_CFG + 3}, diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 0aad9dc91736..bfed0bbcfb7e 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -3370,6 +3370,10 @@ #define B_AX_CSIPRT_HESU_AID_EN BIT(25) #define B_AX_CSIPRT_VHTSU_AID_EN BIT(24) +#define R_AX_BCN_PSR_RPT_P0 0xCE84 +#define R_AX_BCN_PSR_RPT_P0_C1 0xEE84 +#define B_AX_BCAID_P0_MASK GENMASK(10, 0) + #define R_AX_RX_STATE_MONITOR 0xCEF0 #define R_AX_RX_STATE_MONITOR_C1 0xEEF0 #define B_AX_RX_STATE_MONITOR_MASK GENMASK(31, 0) @@ -7494,6 +7498,10 @@ #define R_BE_DRV_INFO_OPTION_C1 0x15470 #define B_BE_DRV_INFO_PHYRPT_EN BIT(0) +#define R_BE_BCN_PSR_RPT_P0 0x11484 +#define R_BE_BCN_PSR_RPT_P0_C1 0x15484 +#define B_BE_BCAID_P0_MASK GENMASK(10, 0) + #define R_BE_RX_ERR_ISR 0x114F4 #define R_BE_RX_ERR_ISR_C1 0x154F4 #define B_BE_RX_ERR_TRIG_ACT_TO BIT(9) From 6d598e856d10317412898cb841ee9df5779bc57d Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 15 Aug 2025 12:31:50 +0100 Subject: [PATCH 01267/11391] net: stmmac: remove unnecessary checks in ethtool eee ops Phylink will check whether the MAC supports the LPI methods in struct phylink_mac_ops, and return -EOPNOTSUPP if the LPI capabilities are not provided. stmmac doesn't provide LPI capabilities if priv->dma_cap.eee is not set. Therefore, checking the state of priv->dma_cap.eee in the ethtool ops and returning -EOPNOTSUPP is redundant - let phylink handle this. Reviewed-by: Andrew Lunn Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1umsf0-008vKK-A3@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index 77758a7299b4..dda7ba1f524d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -852,9 +852,6 @@ static int stmmac_ethtool_op_get_eee(struct net_device *dev, { struct stmmac_priv *priv = netdev_priv(dev); - if (!priv->dma_cap.eee) - return -EOPNOTSUPP; - return phylink_ethtool_get_eee(priv->phylink, edata); } @@ -863,9 +860,6 @@ static int stmmac_ethtool_op_set_eee(struct net_device *dev, { struct stmmac_priv *priv = netdev_priv(dev); - if (!priv->dma_cap.eee) - return -EOPNOTSUPP; - return phylink_ethtool_set_eee(priv->phylink, edata); } From 49b97bc52affb8c800a3b266c8d64482f7b5caf2 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 15 Aug 2025 12:31:55 +0100 Subject: [PATCH 01268/11391] net: stmmac: remove write-only mac->pmt mac_device_info->pmt is only ever written, nothing reads it. Remove this struct member. Reviewed-by: Andrew Lunn Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1umsf5-008vKQ-DT@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/common.h | 1 - drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index cbffccb3b9af..eaa1f2e1c5a5 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -602,7 +602,6 @@ struct mac_device_info { unsigned int mcast_bits_log2; unsigned int rx_csum; unsigned int pcs; - unsigned int pmt; unsigned int ps; unsigned int xlgmac; unsigned int num_vlan; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 9a77390b7f9d..cff75367311e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -7240,7 +7240,6 @@ static int stmmac_hw_init(struct stmmac_priv *priv) priv->plat->enh_desc = priv->dma_cap.enh_desc; priv->plat->pmt = priv->dma_cap.pmt_remote_wake_up && !(priv->plat->flags & STMMAC_FLAG_USE_PHY_WOL); - priv->hw->pmt = priv->plat->pmt; if (priv->dma_cap.hash_tb_sz) { priv->hw->multicast_filter_bins = (BIT(priv->dma_cap.hash_tb_sz) << 5); From b181306e5e6877f4330081821437ae10ee4a10f6 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 15 Aug 2025 12:32:00 +0100 Subject: [PATCH 01269/11391] net: stmmac: remove redundant WoL option validation The core ethtool API validates the WoL options passed from userspace against the support which the driver reports from its get_wol() method, returning EINVAL if an unsupported mode is requested. Therefore, there is no need for stmmac to implement its own validation. Remove this unnecessary code. See ethnl_set_wol() in net/ethtool/wol.c and ethtool_set_wol() in net/ethtool/ioctl.c. Reviewed-by: Andrew Lunn Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1umsfA-008vKW-H1@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index dda7ba1f524d..cd2fb92ac84c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -803,7 +803,6 @@ static void stmmac_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct stmmac_priv *priv = netdev_priv(dev); - u32 support = WAKE_MAGIC | WAKE_UCAST; if (!device_can_wakeup(priv->device)) return -EOPNOTSUPP; @@ -816,15 +815,6 @@ static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) return ret; } - /* By default almost all GMAC devices support the WoL via - * magic frame but we can disable it if the HW capability - * register shows no support for pmt_magic_frame. */ - if ((priv->hw_cap_support) && (!priv->dma_cap.pmt_magic_frame)) - wol->wolopts &= ~WAKE_MAGIC; - - if (wol->wolopts & ~support) - return -EINVAL; - if (wol->wolopts) { pr_info("stmmac: wakeup enable\n"); device_set_wakeup_enable(priv->device, 1); From f17bd297bb833e6f1cae9d3cadad8f334bc3cb8b Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 15 Aug 2025 12:32:05 +0100 Subject: [PATCH 01270/11391] net: stmmac: remove unnecessary "stmmac: wakeup enable" print Printing "stmmac: wakeup enable" to the kernel log isn't useful - it doesn't identify the adapter, and is effectively nothing more than a debugging print. This information can be discovered by looking at /sys/device.../power/wakeup as the device_set_wakeup_enable() call updates this sysfs file. Reviewed-by: Andrew Lunn Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1umsfF-008vKc-Kt@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index cd2fb92ac84c..58542b72cc01 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -816,7 +816,6 @@ static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) } if (wol->wolopts) { - pr_info("stmmac: wakeup enable\n"); device_set_wakeup_enable(priv->device, 1); /* Avoid unbalanced enable_irq_wake calls */ if (priv->wol_irq_disabled) From d09413dd2577953f671136d572932b91a0293db4 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 15 Aug 2025 12:32:10 +0100 Subject: [PATCH 01271/11391] net: stmmac: use core wake IRQ support The PM core provides management of wake IRQs along side setting the device wake enable state. In order to use this, we need to register the interrupt used to wakeup the system using devm_pm_set_wake_irq() or dev_pm_set_wake_irq(). The core will then enable or disable IRQ wake state on this interrupt as appropriate, depending on the device_set_wakeup_enable() state. device_set_wakeup_enable() does not care about having balanced enable/disable calls. Make use of this functionality, rather than explicitly managing the IRQ enable state in the set_wol() ethtool op. This removes the IRQ wake state management from stmmac. Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/E1umsfK-008vKj-Pw@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/stmmac.h | 1 - .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 14 +------------- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 4 ++-- 3 files changed, 3 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index bf95f03dd33f..b16b8aeeb583 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -289,7 +289,6 @@ struct stmmac_priv { u32 msg_enable; int wolopts; int wol_irq; - bool wol_irq_disabled; int clk_csr; struct timer_list eee_ctrl_timer; int lpi_irq; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index 58542b72cc01..39fa1ec92f82 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -815,19 +815,7 @@ static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) return ret; } - if (wol->wolopts) { - device_set_wakeup_enable(priv->device, 1); - /* Avoid unbalanced enable_irq_wake calls */ - if (priv->wol_irq_disabled) - enable_irq_wake(priv->wol_irq); - priv->wol_irq_disabled = false; - } else { - device_set_wakeup_enable(priv->device, 0); - /* Avoid unbalanced disable_irq_wake calls */ - if (!priv->wol_irq_disabled) - disable_irq_wake(priv->wol_irq); - priv->wol_irq_disabled = true; - } + device_set_wakeup_enable(priv->device, !!wol->wolopts); mutex_lock(&priv->lock); priv->wolopts = wol->wolopts; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index cff75367311e..db0433d0ce40 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #ifdef CONFIG_DEBUG_FS @@ -3724,7 +3725,6 @@ static int stmmac_request_irq_multi_msi(struct net_device *dev) /* Request the Wake IRQ in case of another line * is used for WoL */ - priv->wol_irq_disabled = true; if (priv->wol_irq > 0 && priv->wol_irq != dev->irq) { int_name = priv->int_name_wol; sprintf(int_name, "%s:%s", dev->name, "wol"); @@ -3885,7 +3885,6 @@ static int stmmac_request_irq_single(struct net_device *dev) /* Request the Wake IRQ in case of another line * is used for WoL */ - priv->wol_irq_disabled = true; if (priv->wol_irq > 0 && priv->wol_irq != dev->irq) { ret = request_irq(priv->wol_irq, stmmac_interrupt, IRQF_SHARED, dev->name, dev); @@ -7277,6 +7276,7 @@ static int stmmac_hw_init(struct stmmac_priv *priv) if (priv->plat->pmt) { dev_info(priv->device, "Wake-Up On Lan supported\n"); device_set_wakeup_capable(priv->device, 1); + devm_pm_set_wake_irq(priv->device, priv->wol_irq); } if (priv->dma_cap.tsoen) From 6a9a6ce962292b2cf31049f02a9360ca2ef25676 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 15 Aug 2025 12:32:15 +0100 Subject: [PATCH 01272/11391] net: stmmac: add helpers to indicate WoL enable status Add two helpers to abstract the WoL enable status at the PHY and MAC to make the code easier to read. Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/E1umsfP-008vKp-U1@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/stmmac.h | 10 ++++++++++ drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 11 +++++------ drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 4 ++-- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index b16b8aeeb583..78d6b3737a26 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -375,6 +375,16 @@ enum stmmac_state { extern const struct dev_pm_ops stmmac_simple_pm_ops; +static inline bool stmmac_wol_enabled_mac(struct stmmac_priv *priv) +{ + return priv->plat->pmt && device_may_wakeup(priv->device); +} + +static inline bool stmmac_wol_enabled_phy(struct stmmac_priv *priv) +{ + return !priv->plat->pmt && device_may_wakeup(priv->device); +} + int stmmac_mdio_unregister(struct net_device *ndev); int stmmac_mdio_register(struct net_device *ndev); int stmmac_mdio_reset(struct mii_bus *mii); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index db0433d0ce40..b9e8df90e7b5 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -7857,7 +7857,7 @@ int stmmac_suspend(struct device *dev) priv->plat->serdes_powerdown(ndev, priv->plat->bsp_priv); /* Enable Power down mode by programming the PMT regs */ - if (device_may_wakeup(priv->device) && priv->plat->pmt) { + if (stmmac_wol_enabled_mac(priv)) { stmmac_pmt(priv, priv->hw, priv->wolopts); priv->irq_wake = 1; } else { @@ -7868,11 +7868,10 @@ int stmmac_suspend(struct device *dev) mutex_unlock(&priv->lock); rtnl_lock(); - if (device_may_wakeup(priv->device) && !priv->plat->pmt) + if (stmmac_wol_enabled_phy(priv)) phylink_speed_down(priv->phylink, false); - phylink_suspend(priv->phylink, - device_may_wakeup(priv->device) && priv->plat->pmt); + phylink_suspend(priv->phylink, stmmac_wol_enabled_mac(priv)); rtnl_unlock(); if (stmmac_fpe_supported(priv)) @@ -7948,7 +7947,7 @@ int stmmac_resume(struct device *dev) * this bit because it can generate problems while resuming * from another devices (e.g. serial console). */ - if (device_may_wakeup(priv->device) && priv->plat->pmt) { + if (stmmac_wol_enabled_mac(priv)) { mutex_lock(&priv->lock); stmmac_pmt(priv, priv->hw, 0); mutex_unlock(&priv->lock); @@ -8008,7 +8007,7 @@ int stmmac_resume(struct device *dev) * workqueue thread, which will race with initialisation. */ phylink_resume(priv->phylink); - if (device_may_wakeup(priv->device) && !priv->plat->pmt) + if (stmmac_wol_enabled_phy(priv)) phylink_speed_up(priv->phylink); rtnl_unlock(); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index c849676d98e8..a3e077f225d1 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -934,7 +934,7 @@ static int __maybe_unused stmmac_pltfr_noirq_suspend(struct device *dev) if (!netif_running(ndev)) return 0; - if (!device_may_wakeup(priv->device) || !priv->plat->pmt) { + if (!stmmac_wol_enabled_mac(priv)) { /* Disable clock in case of PWM is off */ clk_disable_unprepare(priv->plat->clk_ptp_ref); @@ -955,7 +955,7 @@ static int __maybe_unused stmmac_pltfr_noirq_resume(struct device *dev) if (!netif_running(ndev)) return 0; - if (!device_may_wakeup(priv->device) || !priv->plat->pmt) { + if (!stmmac_wol_enabled_mac(priv)) { /* enable the clk previously disabled */ ret = pm_runtime_force_resume(dev); if (ret) From 5e5b39aa6f82e74a2b4caa79005b2e673f657809 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 15 Aug 2025 12:32:21 +0100 Subject: [PATCH 01273/11391] net: stmmac: explain the phylink_speed_down() call in stmmac_release() The call to phylink_speed_down() looks odd on the face of it. Add a comment to explain why this call is there. phylink_speed_up() is always called in __stmmac_open(), and already has a comment. Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/E1umsfV-008vKv-1O@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index b9e8df90e7b5..0bbdc1f1a691 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -4138,8 +4138,13 @@ static int stmmac_release(struct net_device *dev) struct stmmac_priv *priv = netdev_priv(dev); u32 chan; + /* If the PHY or MAC has WoL enabled, then the PHY will not be + * suspended when phylink_stop() is called below. Set the PHY + * to its slowest speed to save power. + */ if (device_may_wakeup(priv->device)) phylink_speed_down(priv->phylink, false); + /* Stop and disconnect the PHY */ phylink_stop(priv->phylink); phylink_disconnect_phy(priv->phylink); From e798f2ac6040f46a04795d7de977341fa9aeabae Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 11 Aug 2025 18:32:55 +0300 Subject: [PATCH 01274/11391] wifi: rtlwifi: rtl8192cu: Don't claim USB ID 07b8:8188 This ID appears to be RTL8188SU, not RTL8188CU. This is the wrong driver for RTL8188SU. The r8712u driver from staging used to handle this ID. Closes: https://lore.kernel.org/linux-wireless/ee0acfef-a753-4f90-87df-15f8eaa9c3a8@gmx.de/ Cc: stable@vger.kernel.org Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/2e5e2348-bdb3-44b2-92b2-0231dbf464b0@gmail.com --- drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c index 00a6778df704..9480823af838 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c @@ -291,7 +291,6 @@ static const struct usb_device_id rtl8192c_usb_ids[] = { {RTL_USB_DEVICE(0x050d, 0x1102, rtl92cu_hal_cfg)}, /*Belkin - Edimax*/ {RTL_USB_DEVICE(0x050d, 0x11f2, rtl92cu_hal_cfg)}, /*Belkin - ISY*/ {RTL_USB_DEVICE(0x06f8, 0xe033, rtl92cu_hal_cfg)}, /*Hercules - Edimax*/ - {RTL_USB_DEVICE(0x07b8, 0x8188, rtl92cu_hal_cfg)}, /*Abocom - Abocom*/ {RTL_USB_DEVICE(0x07b8, 0x8189, rtl92cu_hal_cfg)}, /*Funai - Abocom*/ {RTL_USB_DEVICE(0x0846, 0x9041, rtl92cu_hal_cfg)}, /*NetGear WNA1000M*/ {RTL_USB_DEVICE(0x0846, 0x9043, rtl92cu_hal_cfg)}, /*NG WNA1000Mv2*/ From ec0b44736b1d22b763ee94f1aee856f9e793f3fe Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Mon, 11 Aug 2025 18:33:28 +0300 Subject: [PATCH 01275/11391] wifi: rtl8xxxu: Don't claim USB ID 07b8:8188 This ID appears to be RTL8188SU, not RTL8188CU. This is the wrong driver for RTL8188SU. The r8712u driver from staging used to handle this ID. Closes: https://lore.kernel.org/linux-wireless/ee0acfef-a753-4f90-87df-15f8eaa9c3a8@gmx.de/ Cc: stable@vger.kernel.org Signed-off-by: Bitterblue Smith Reviewed-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/f147b2ab-4505-435a-aa32-62964e4f1f1e@gmail.com --- drivers/net/wireless/realtek/rtl8xxxu/core.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/core.c b/drivers/net/wireless/realtek/rtl8xxxu/core.c index 831b5025c634..018f5afcd50d 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/core.c @@ -8172,8 +8172,6 @@ static const struct usb_device_id dev_table[] = { .driver_info = (unsigned long)&rtl8192cu_fops}, {USB_DEVICE_AND_INTERFACE_INFO(0x06f8, 0xe033, 0xff, 0xff, 0xff), .driver_info = (unsigned long)&rtl8192cu_fops}, -{USB_DEVICE_AND_INTERFACE_INFO(0x07b8, 0x8188, 0xff, 0xff, 0xff), - .driver_info = (unsigned long)&rtl8192cu_fops}, {USB_DEVICE_AND_INTERFACE_INFO(0x07b8, 0x8189, 0xff, 0xff, 0xff), .driver_info = (unsigned long)&rtl8192cu_fops}, {USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9041, 0xff, 0xff, 0xff), From 33319e8fd7ac2631eef89c770940fa5f96a93063 Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Mon, 18 Aug 2025 14:42:19 +0800 Subject: [PATCH 01276/11391] wifi: rtw89: 8852bt: Simplify unnecessary if-else conditions in _dpk_onoff() Some simple if-else logic can be simplified using the ! operator to improve code readability. Signed-off-by: Liao Yuanhong Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250818064219.448066-1-liaoyuanhong@vivo.com --- drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c index b01f921b4224..99cb6a973de2 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c @@ -1803,10 +1803,7 @@ static void _dpk_onoff(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, bool o val = dpk->is_dpk_enable && !off && dpk->bp[path][kidx].path_ok; - if (off) - off_reverse = false; - else - off_reverse = true; + off_reverse = !off; val = dpk->is_dpk_enable & off_reverse & dpk->bp[path][kidx].path_ok; From dc60a408a1dc29974bc82239b07b70c5f7fcfd31 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 13 Aug 2025 10:10:41 -0700 Subject: [PATCH 01277/11391] scsi: ufs: core: Improve IOPS Measurements have shown that IOPS improve by 2% - 3% on my UFS 4 test setup every time a ktime_get() call is removed from the UFS driver command processing path. Hence this patch that modifies ufshcd_clk_scaling_start_busy() such that ktime_get() is only called if the returned value will be used. Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20250813171049.3399387-1-bvanassche@acm.org Reviewed-by: Bean Huo Reviewed-by: Peter Wang Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 96ad57c3144b..daae452a1d25 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -2230,11 +2230,13 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba) static void ufshcd_clk_scaling_start_busy(struct ufs_hba *hba) { bool queue_resume_work = false; - ktime_t curr_t = ktime_get(); + ktime_t curr_t; if (!ufshcd_is_clkscaling_supported(hba)) return; + curr_t = ktime_get(); + guard(spinlock_irqsave)(&hba->clk_scaling.lock); if (!hba->clk_scaling.active_reqs++) From eeee1086073e0058243c8554738271561bde81f1 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Thu, 14 Aug 2025 19:32:16 +0200 Subject: [PATCH 01278/11391] scsi: pm80xx: Restore support for expanders Commit 0f630c58e31a ("scsi: pm80xx: Do not use libsas port ID") broke support for expanders. After the commit, devices behind an expander are no longer detected. Simply reverting the commit restores support for devices behind an expander. Instead of reverting the commit (and reintroducing a helper to get the port), get the port directly from the lldd_port pointer in struct asd_sas_port. Fixes: 0f630c58e31a ("scsi: pm80xx: Do not use libsas port ID") Suggested-by: Igor Pylypiv Reviewed-by: Igor Pylypiv Signed-off-by: Niklas Cassel Link: https://lore.kernel.org/r/20250814173215.1765055-13-cassel@kernel.org Reviewed-by: Damien Le Moal Tested-by: Damien Le Moal Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_sas.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index f7067878b34f..753c09363cbb 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -477,7 +477,7 @@ int pm8001_queue_command(struct sas_task *task, gfp_t gfp_flags) struct pm8001_device *pm8001_dev = dev->lldd_dev; bool internal_abort = sas_is_internal_abort(task); struct pm8001_hba_info *pm8001_ha; - struct pm8001_port *port = NULL; + struct pm8001_port *port; struct pm8001_ccb_info *ccb; unsigned long flags; u32 n_elem = 0; @@ -502,8 +502,7 @@ int pm8001_queue_command(struct sas_task *task, gfp_t gfp_flags) spin_lock_irqsave(&pm8001_ha->lock, flags); - pm8001_dev = dev->lldd_dev; - port = pm8001_ha->phy[pm8001_dev->attached_phy].port; + port = dev->port->lldd_port; if (!internal_abort && (DEV_IS_GONE(pm8001_dev) || !port || !port->port_attached)) { From 251be2f6037fb7ab399f68cd7428ff274133d693 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Thu, 14 Aug 2025 19:32:17 +0200 Subject: [PATCH 01279/11391] scsi: pm80xx: Fix array-index-out-of-of-bounds on rmmod Since commit f7b705c238d1 ("scsi: pm80xx: Set phy_attached to zero when device is gone") UBSAN reports: UBSAN: array-index-out-of-bounds in drivers/scsi/pm8001/pm8001_sas.c:786:17 index 28 is out of range for type 'pm8001_phy [16]' on rmmod when using an expander. For a direct attached device, attached_phy contains the local phy id. For a device behind an expander, attached_phy contains the remote phy id, not the local phy id. I.e. while pm8001_ha will have pm8001_ha->chip->n_phy local phys, for a device behind an expander, attached_phy can be much larger than pm8001_ha->chip->n_phy (depending on the amount of phys of the expander). E.g. on my system pm8001_ha has 8 phys with phy ids 0-7. One of the ports has an expander connected. The expander has 31 phys with phy ids 0-30. The pm8001_ha->phy array only contains the phys of the HBA. It does not contain the phys of the expander. Thus, it is wrong to use attached_phy to index the pm8001_ha->phy array for a device behind an expander. Thus, we can only clear phy_attached for devices that are directly attached. Fixes: f7b705c238d1 ("scsi: pm80xx: Set phy_attached to zero when device is gone") Reviewed-by: Igor Pylypiv Signed-off-by: Niklas Cassel Link: https://lore.kernel.org/r/20250814173215.1765055-14-cassel@kernel.org Reviewed-by: Damien Le Moal Tested-by: Damien Le Moal Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_sas.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 753c09363cbb..3e1dac4b820f 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -749,6 +749,7 @@ static void pm8001_dev_gone_notify(struct domain_device *dev) unsigned long flags = 0; struct pm8001_hba_info *pm8001_ha; struct pm8001_device *pm8001_dev = dev->lldd_dev; + struct domain_device *parent_dev = dev->parent; pm8001_ha = pm8001_find_ha_by_dev(dev); spin_lock_irqsave(&pm8001_ha->lock, flags); @@ -765,7 +766,13 @@ static void pm8001_dev_gone_notify(struct domain_device *dev) spin_lock_irqsave(&pm8001_ha->lock, flags); } PM8001_CHIP_DISP->dereg_dev_req(pm8001_ha, device_id); - pm8001_ha->phy[pm8001_dev->attached_phy].phy_attached = 0; + + /* + * The phy array only contains local phys. Thus, we cannot clear + * phy_attached for a device behind an expander. + */ + if (!(parent_dev && dev_is_expander(parent_dev->dev_type))) + pm8001_ha->phy[pm8001_dev->attached_phy].phy_attached = 0; pm8001_free_dev(pm8001_dev); } else { pm8001_dbg(pm8001_ha, DISC, "Found dev has gone.\n"); From e5eb72c92eb724aa14c50c7d92d1a576dd50d7e6 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Thu, 14 Aug 2025 19:32:18 +0200 Subject: [PATCH 01280/11391] scsi: libsas: Add dev_parent_is_expander() helper Many libsas drivers check if the parent of the device is an expander. Create a helper that the libsas drivers will use in follow up commits. Suggested-by: Damien Le Moal Signed-off-by: Niklas Cassel Link: https://lore.kernel.org/r/20250814173215.1765055-15-cassel@kernel.org Reviewed-by: Damien Le Moal Reviewed-by: John Garry Reviewed-by: Jason Yan Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_expander.c | 5 +---- include/scsi/libsas.h | 8 ++++++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 869b5d4db44c..d953225f6cc2 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -1313,10 +1313,7 @@ static int sas_check_parent_topology(struct domain_device *child) int i; int res = 0; - if (!child->parent) - return 0; - - if (!dev_is_expander(child->parent->dev_type)) + if (!dev_parent_is_expander(child)) return 0; parent_ex = &child->parent->ex_dev; diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index ba460b6c0374..8d38565e99fa 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -203,6 +203,14 @@ static inline bool dev_is_expander(enum sas_device_type type) type == SAS_FANOUT_EXPANDER_DEVICE; } +static inline bool dev_parent_is_expander(struct domain_device *dev) +{ + if (!dev->parent) + return false; + + return dev_is_expander(dev->parent->dev_type); +} + static inline void INIT_SAS_WORK(struct sas_work *sw, void (*fn)(struct work_struct *)) { INIT_WORK(&sw->work, fn); From 0c0188dd200e4709da72cc3d65c012f34030b950 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Thu, 14 Aug 2025 19:32:19 +0200 Subject: [PATCH 01281/11391] scsi: hisi_sas: Use dev_parent_is_expander() helper Make use of the dev_parent_is_expander() helper. Signed-off-by: Niklas Cassel Link: https://lore.kernel.org/r/20250814173215.1765055-16-cassel@kernel.org Reviewed-by: Damien Le Moal Reviewed-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 2 +- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 6 ++---- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 6 ++---- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index d1a4cc69d408..30a9c6612651 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -876,7 +876,7 @@ static int hisi_sas_dev_found(struct domain_device *device) device->lldd_dev = sas_dev; hisi_hba->hw->setup_itct(hisi_hba, sas_dev); - if (parent_dev && dev_is_expander(parent_dev->dev_type)) { + if (dev_parent_is_expander(device)) { int phy_no; phy_no = sas_find_attached_phy_id(&parent_dev->ex_dev, device); diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 4431698a5d78..f3516a0611dd 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -925,7 +925,6 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba, struct device *dev = hisi_hba->dev; u64 qw0, device_id = sas_dev->device_id; struct hisi_sas_itct *itct = &hisi_hba->itct[device_id]; - struct domain_device *parent_dev = device->parent; struct asd_sas_port *sas_port = device->port; struct hisi_sas_port *port = to_hisi_sas_port(sas_port); u64 sas_addr; @@ -942,7 +941,7 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba, break; case SAS_SATA_DEV: case SAS_SATA_PENDING: - if (parent_dev && dev_is_expander(parent_dev->dev_type)) + if (dev_parent_is_expander(device)) qw0 = HISI_SAS_DEV_TYPE_STP << ITCT_HDR_DEV_TYPE_OFF; else qw0 = HISI_SAS_DEV_TYPE_SATA << ITCT_HDR_DEV_TYPE_OFF; @@ -2494,7 +2493,6 @@ static void prep_ata_v2_hw(struct hisi_hba *hisi_hba, { struct sas_task *task = slot->task; struct domain_device *device = task->dev; - struct domain_device *parent_dev = device->parent; struct hisi_sas_device *sas_dev = device->lldd_dev; struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr; struct asd_sas_port *sas_port = device->port; @@ -2509,7 +2507,7 @@ static void prep_ata_v2_hw(struct hisi_hba *hisi_hba, /* create header */ /* dw0 */ dw0 = port->id << CMD_HDR_PORT_OFF; - if (parent_dev && dev_is_expander(parent_dev->dev_type)) { + if (dev_parent_is_expander(device)) { dw0 |= 3 << CMD_HDR_CMD_OFF; } else { phy_id = device->phy->identify.phy_identifier; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 2f3d61abab3a..2f9e01717ef3 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -874,7 +874,6 @@ static void setup_itct_v3_hw(struct hisi_hba *hisi_hba, struct device *dev = hisi_hba->dev; u64 qw0, device_id = sas_dev->device_id; struct hisi_sas_itct *itct = &hisi_hba->itct[device_id]; - struct domain_device *parent_dev = device->parent; struct asd_sas_port *sas_port = device->port; struct hisi_sas_port *port = to_hisi_sas_port(sas_port); u64 sas_addr; @@ -891,7 +890,7 @@ static void setup_itct_v3_hw(struct hisi_hba *hisi_hba, break; case SAS_SATA_DEV: case SAS_SATA_PENDING: - if (parent_dev && dev_is_expander(parent_dev->dev_type)) + if (dev_parent_is_expander(device)) qw0 = HISI_SAS_DEV_TYPE_STP << ITCT_HDR_DEV_TYPE_OFF; else qw0 = HISI_SAS_DEV_TYPE_SATA << ITCT_HDR_DEV_TYPE_OFF; @@ -1476,7 +1475,6 @@ static void prep_ata_v3_hw(struct hisi_hba *hisi_hba, { struct sas_task *task = slot->task; struct domain_device *device = task->dev; - struct domain_device *parent_dev = device->parent; struct hisi_sas_device *sas_dev = device->lldd_dev; struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr; struct asd_sas_port *sas_port = device->port; @@ -1487,7 +1485,7 @@ static void prep_ata_v3_hw(struct hisi_hba *hisi_hba, u32 dw1 = 0, dw2 = 0; hdr->dw0 = cpu_to_le32(port->id << CMD_HDR_PORT_OFF); - if (parent_dev && dev_is_expander(parent_dev->dev_type)) { + if (dev_parent_is_expander(device)) { hdr->dw0 |= cpu_to_le32(3 << CMD_HDR_CMD_OFF); } else { phy_id = device->phy->identify.phy_identifier; From ad6ae22927a7ed411d892d80934610c49882a378 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Thu, 14 Aug 2025 19:32:20 +0200 Subject: [PATCH 01282/11391] scsi: isci: Use dev_parent_is_expander() helper Make use of the dev_parent_is_expander() helper. Signed-off-by: Niklas Cassel Link: https://lore.kernel.org/r/20250814173215.1765055-17-cassel@kernel.org Reviewed-by: Damien Le Moal Reviewed-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/isci/remote_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c index 82deb6a83a8c..4c7462965ea1 100644 --- a/drivers/scsi/isci/remote_device.c +++ b/drivers/scsi/isci/remote_device.c @@ -1434,7 +1434,7 @@ static enum sci_status isci_remote_device_construct(struct isci_port *iport, struct domain_device *dev = idev->domain_dev; enum sci_status status; - if (dev->parent && dev_is_expander(dev->parent->dev_type)) + if (dev_parent_is_expander(dev)) status = sci_remote_device_ea_construct(iport, idev); else status = sci_remote_device_da_construct(iport, idev); From 3adf779489839516d61c3ead08cc148a7374b581 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Thu, 14 Aug 2025 19:32:21 +0200 Subject: [PATCH 01283/11391] scsi: mvsas: Use dev_parent_is_expander() helper Make use of the dev_parent_is_expander() helper. Signed-off-by: Niklas Cassel Link: https://lore.kernel.org/r/20250814173215.1765055-18-cassel@kernel.org Reviewed-by: Damien Le Moal Reviewed-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/mvsas/mv_sas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index 15b3d9d55a4b..f2e7997d5b9d 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c @@ -1175,7 +1175,7 @@ static int mvs_dev_found_notify(struct domain_device *dev, int lock) mvi_device->dev_type = dev->dev_type; mvi_device->mvi_info = mvi; mvi_device->sas_device = dev; - if (parent_dev && dev_is_expander(parent_dev->dev_type)) { + if (dev_parent_is_expander(dev)) { int phy_id; phy_id = sas_find_attached_phy_id(&parent_dev->ex_dev, dev); From 35e388696c3f3b6bf70e2010873c5e0c1d37d579 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Thu, 14 Aug 2025 19:32:22 +0200 Subject: [PATCH 01284/11391] scsi: pm80xx: Use dev_parent_is_expander() helper Make use of the dev_parent_is_expander() helper. Signed-off-by: Niklas Cassel Link: https://lore.kernel.org/r/20250814173215.1765055-19-cassel@kernel.org Reviewed-by: Damien Le Moal Reviewed-by: John Garry Reviewed-by: Igor Pylypiv Acked-by: Jack Wang Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_hwi.c | 8 +++----- drivers/scsi/pm8001/pm8001_sas.c | 5 ++--- drivers/scsi/pm8001/pm80xx_hwi.c | 8 +++----- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 42a4eeac24c9..fb4913547b00 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -2163,8 +2163,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) /* Print sas address of IO failed device */ if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) && (status != IO_UNDERFLOW)) { - if (!((t->dev->parent) && - (dev_is_expander(t->dev->parent->dev_type)))) { + if (!dev_parent_is_expander(t->dev)) { for (i = 0, j = 4; j <= 7 && i <= 3; i++, j++) sata_addr_low[i] = pm8001_ha->sas_addr[j]; for (i = 0, j = 0; j <= 3 && i <= 3; i++, j++) @@ -4168,7 +4167,6 @@ static int pm8001_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, u16 firstBurstSize = 0; u16 ITNT = 2000; struct domain_device *dev = pm8001_dev->sas_device; - struct domain_device *parent_dev = dev->parent; struct pm8001_port *port = dev->port->lldd_port; memset(&payload, 0, sizeof(payload)); @@ -4186,8 +4184,8 @@ static int pm8001_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, dev_is_expander(pm8001_dev->dev_type)) stp_sspsmp_sata = 0x01; /*ssp or smp*/ } - if (parent_dev && dev_is_expander(parent_dev->dev_type)) - phy_id = parent_dev->ex_dev.ex_phy->phy_id; + if (dev_parent_is_expander(dev)) + phy_id = dev->parent->ex_dev.ex_phy->phy_id; else phy_id = pm8001_dev->attached_phy; opc = OPC_INB_REG_DEV; diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 3e1dac4b820f..2bdeace6c6bf 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -700,7 +700,7 @@ static int pm8001_dev_found_notify(struct domain_device *dev) dev->lldd_dev = pm8001_device; pm8001_device->dev_type = dev->dev_type; pm8001_device->dcompletion = &completion; - if (parent_dev && dev_is_expander(parent_dev->dev_type)) { + if (dev_parent_is_expander(dev)) { int phy_id; phy_id = sas_find_attached_phy_id(&parent_dev->ex_dev, dev); @@ -749,7 +749,6 @@ static void pm8001_dev_gone_notify(struct domain_device *dev) unsigned long flags = 0; struct pm8001_hba_info *pm8001_ha; struct pm8001_device *pm8001_dev = dev->lldd_dev; - struct domain_device *parent_dev = dev->parent; pm8001_ha = pm8001_find_ha_by_dev(dev); spin_lock_irqsave(&pm8001_ha->lock, flags); @@ -771,7 +770,7 @@ static void pm8001_dev_gone_notify(struct domain_device *dev) * The phy array only contains local phys. Thus, we cannot clear * phy_attached for a device behind an expander. */ - if (!(parent_dev && dev_is_expander(parent_dev->dev_type))) + if (!dev_parent_is_expander(dev)) pm8001_ha->phy[pm8001_dev->attached_phy].phy_attached = 0; pm8001_free_dev(pm8001_dev); } else { diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index c1bae995a412..546d0d26f7a1 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -2340,8 +2340,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, /* Print sas address of IO failed device */ if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) && (status != IO_UNDERFLOW)) { - if (!((t->dev->parent) && - (dev_is_expander(t->dev->parent->dev_type)))) { + if (!dev_parent_is_expander(t->dev)) { for (i = 0, j = 4; i <= 3 && j <= 7; i++, j++) sata_addr_low[i] = pm8001_ha->sas_addr[j]; for (i = 0, j = 0; i <= 3 && j <= 3; i++, j++) @@ -4780,7 +4779,6 @@ static int pm80xx_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, u16 firstBurstSize = 0; u16 ITNT = 2000; struct domain_device *dev = pm8001_dev->sas_device; - struct domain_device *parent_dev = dev->parent; struct pm8001_port *port = dev->port->lldd_port; memset(&payload, 0, sizeof(payload)); @@ -4799,8 +4797,8 @@ static int pm80xx_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, dev_is_expander(pm8001_dev->dev_type)) stp_sspsmp_sata = 0x01; /*ssp or smp*/ } - if (parent_dev && dev_is_expander(parent_dev->dev_type)) - phy_id = parent_dev->ex_dev.ex_phy->phy_id; + if (dev_parent_is_expander(dev)) + phy_id = dev->parent->ex_dev.ex_phy->phy_id; else phy_id = pm8001_dev->attached_phy; From b4ec98303f9fc9b1da0053106716db6a7e002d8b Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Thu, 14 Aug 2025 19:32:23 +0200 Subject: [PATCH 01285/11391] scsi: pm80xx: Add helper function to get the local phy id Avoid duplicated code by adding a helper to get the local phy id. No functional changes intended. Signed-off-by: Niklas Cassel Link: https://lore.kernel.org/r/20250814173215.1765055-20-cassel@kernel.org Reviewed-by: Damien Le Moal Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_hwi.c | 7 +++---- drivers/scsi/pm8001/pm8001_sas.c | 10 ++++++++++ drivers/scsi/pm8001/pm8001_sas.h | 1 + drivers/scsi/pm8001/pm80xx_hwi.c | 6 ++---- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index fb4913547b00..8005995a317c 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -4184,10 +4184,9 @@ static int pm8001_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, dev_is_expander(pm8001_dev->dev_type)) stp_sspsmp_sata = 0x01; /*ssp or smp*/ } - if (dev_parent_is_expander(dev)) - phy_id = dev->parent->ex_dev.ex_phy->phy_id; - else - phy_id = pm8001_dev->attached_phy; + + phy_id = pm80xx_get_local_phy_id(dev); + opc = OPC_INB_REG_DEV; linkrate = (pm8001_dev->sas_device->linkrate < dev->port->linkrate) ? pm8001_dev->sas_device->linkrate : dev->port->linkrate; diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 2bdeace6c6bf..5595913eb7fc 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -130,6 +130,16 @@ static void pm80xx_get_tag_opcodes(struct sas_task *task, int *ata_op, } } +u32 pm80xx_get_local_phy_id(struct domain_device *dev) +{ + struct pm8001_device *pm8001_dev = dev->lldd_dev; + + if (dev_parent_is_expander(dev)) + return dev->parent->ex_dev.ex_phy->phy_id; + + return pm8001_dev->attached_phy; +} + void pm80xx_show_pending_commands(struct pm8001_hba_info *pm8001_ha, struct pm8001_device *target_pm8001_dev) { diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index 334485bb2c12..91b2cdf3535c 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -798,6 +798,7 @@ void pm8001_setds_completion(struct domain_device *dev); void pm8001_tmf_aborted(struct sas_task *task); void pm80xx_show_pending_commands(struct pm8001_hba_info *pm8001_ha, struct pm8001_device *dev); +u32 pm80xx_get_local_phy_id(struct domain_device *dev); #endif diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 546d0d26f7a1..31960b72c1e9 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -4797,10 +4797,8 @@ static int pm80xx_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, dev_is_expander(pm8001_dev->dev_type)) stp_sspsmp_sata = 0x01; /*ssp or smp*/ } - if (dev_parent_is_expander(dev)) - phy_id = dev->parent->ex_dev.ex_phy->phy_id; - else - phy_id = pm8001_dev->attached_phy; + + phy_id = pm80xx_get_local_phy_id(dev); opc = OPC_INB_REG_DEV; From ad70c6bc776b53e61c8db6533c833aff0ff5da8b Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Thu, 14 Aug 2025 19:32:24 +0200 Subject: [PATCH 01286/11391] scsi: pm80xx: Fix pm8001_abort_task() for chip_8006 when using an expander For a direct attached device, attached_phy contains the local phy id. For a device behind an expander, attached_phy contains the remote phy id, not the local phy id. The pm8001_ha->phy array only contains the phys of the HBA. It does not contain the phys of the expander. Thus, you cannot use attached_phy to index the pm8001_ha->phy array, without first verifying that the device is directly attached. Use the pm80xx_get_local_phy_id() helper to make sure that we use the local phy id to index the array, regardless if the device is directly attached or not. Fixes: 869ddbdcae3b ("scsi: pm80xx: corrected SATA abort handling sequence.") Reviewed-by: Igor Pylypiv Signed-off-by: Niklas Cassel Link: https://lore.kernel.org/r/20250814173215.1765055-21-cassel@kernel.org Reviewed-by: Damien Le Moal Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_sas.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 5595913eb7fc..c5354263b45e 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -1063,7 +1063,7 @@ int pm8001_abort_task(struct sas_task *task) struct pm8001_hba_info *pm8001_ha; struct pm8001_device *pm8001_dev; int rc = TMF_RESP_FUNC_FAILED, ret; - u32 phy_id, port_id; + u32 port_id; struct sas_task_slow slow_task; if (!task->lldd_task || !task->dev) @@ -1072,7 +1072,6 @@ int pm8001_abort_task(struct sas_task *task) dev = task->dev; pm8001_dev = dev->lldd_dev; pm8001_ha = pm8001_find_ha_by_dev(dev); - phy_id = pm8001_dev->attached_phy; if (PM8001_CHIP_DISP->fatal_errors(pm8001_ha)) { // If the controller is seeing fatal errors @@ -1104,7 +1103,8 @@ int pm8001_abort_task(struct sas_task *task) if (pm8001_ha->chip_id == chip_8006) { DECLARE_COMPLETION_ONSTACK(completion_reset); DECLARE_COMPLETION_ONSTACK(completion); - struct pm8001_phy *phy = pm8001_ha->phy + phy_id; + u32 phy_id = pm80xx_get_local_phy_id(dev); + struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; port_id = phy->port->port_id; /* 1. Set Device state as Recovery */ From 03f69351b63ea9583bd91c60a83d0a8573ea29fb Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Thu, 14 Aug 2025 19:32:25 +0200 Subject: [PATCH 01287/11391] scsi: pm80xx: Use pm80xx_get_local_phy_id() to access phy array While the current code is perfectly fine (because we verify that the device is directly attached before using attached_phy to index the pm8001_ha->phy array), let's use the pm80xx_get_local_phy_id() helper anyway, to reduce the chance that someone will copy paste this pattern to other parts of the driver. Note that in this specific case, we still need to keep the check that the device is not behind an expander, because we do not want to clear attached_phy of the expander if a device behind the expander disappears (as that would disable all the other devices behind the expander). However, if it is the expander itself that disappears, attached_phy will be cleared, just like it would for any other directly attached device. Signed-off-by: Niklas Cassel Link: https://lore.kernel.org/r/20250814173215.1765055-22-cassel@kernel.org Reviewed-by: Damien Le Moal Reviewed-by: Igor Pylypiv Acked-by: Jack Wang Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_sas.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index c5354263b45e..6a8d35aea93a 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -780,8 +780,11 @@ static void pm8001_dev_gone_notify(struct domain_device *dev) * The phy array only contains local phys. Thus, we cannot clear * phy_attached for a device behind an expander. */ - if (!dev_parent_is_expander(dev)) - pm8001_ha->phy[pm8001_dev->attached_phy].phy_attached = 0; + if (!dev_parent_is_expander(dev)) { + u32 phy_id = pm80xx_get_local_phy_id(dev); + + pm8001_ha->phy[phy_id].phy_attached = 0; + } pm8001_free_dev(pm8001_dev); } else { pm8001_dbg(pm8001_ha, DISC, "Found dev has gone.\n"); From 13650cd32cfc640fbd49f0424640f64d57335d4c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 18 Aug 2025 14:38:52 +0200 Subject: [PATCH 01288/11391] soc: qcom: icc-bwmon: Fix handling dev_pm_opp_find_bw_*() errors The ISR calls dev_pm_opp_find_bw_ceil(), which can return EINVAL, ERANGE or ENODEV, and if that one fails with ERANGE, then it tries again with floor dev_pm_opp_find_bw_floor(). In theory, following error paths are possible: 1. First dev_pm_opp_find_bw_ceil() failed with an error different than ERANGE, 2. Any error from second dev_pm_opp_find_bw_floor(). However in practice this would mean that there are no suitable OPPs at all, which is already being checked in the drivers probe() function. This is impossible condition. Relying however in the interrupt handler bwmon_intr_thread() on preconditions checked in probe() is not easy to follow from code readability and is very difficult to handle in static analysis, thus let's make the code just obvious to silence warning reported by Smatch: icc-bwmon.c:693 bwmon_intr_thread() error: 'target_opp' dereferencing possible ERR_PTR() Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/aJTNEQsRFjrFknG9@stanley.mountain/ Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250818123851.111326-2-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/icc-bwmon.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/soc/qcom/icc-bwmon.c b/drivers/soc/qcom/icc-bwmon.c index 3dfa448bf8cf..597f9025e422 100644 --- a/drivers/soc/qcom/icc-bwmon.c +++ b/drivers/soc/qcom/icc-bwmon.c @@ -656,6 +656,9 @@ static irqreturn_t bwmon_intr_thread(int irq, void *dev_id) if (IS_ERR(target_opp) && PTR_ERR(target_opp) == -ERANGE) target_opp = dev_pm_opp_find_bw_floor(bwmon->dev, &bw_kbps, 0); + if (IS_ERR(target_opp)) + return IRQ_HANDLED; + bwmon->target_kbps = bw_kbps; bw_kbps--; From cf0ed173d27a2a832642aa441eb28a4dca53fd19 Mon Sep 17 00:00:00 2001 From: Akhil P Oommen Date: Mon, 23 Jun 2025 19:42:07 +0530 Subject: [PATCH 01289/11391] arm64: defconfig: Enable X1P42100 GPUCC driver In order to enable GPU support in X1P42100-CRD and other similar laptops with Snapdragon X1P42100 SoC, enable X1P42100 GPUCC driver as a module. Signed-off-by: Akhil P Oommen Link: https://lore.kernel.org/r/20250623-x1p-adreno-v4-2-d2575c839cbb@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/configs/defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 68a024fadd78..f8b695488f0b 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -1360,6 +1360,7 @@ CONFIG_CLK_X1E80100_DISPCC=m CONFIG_CLK_X1E80100_GCC=y CONFIG_CLK_X1E80100_GPUCC=m CONFIG_CLK_X1E80100_TCSRCC=y +CONFIG_CLK_X1P42100_GPUCC=m CONFIG_CLK_QCM2290_GPUCC=m CONFIG_QCOM_A53PLL=y CONFIG_QCOM_CLK_APCS_MSM8916=y From cd5d4621ba846dad9b2e6b0c2d1518d083fcfa13 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 18 Aug 2025 08:50:48 -0700 Subject: [PATCH 01290/11391] cpufreq: scmi: Account for malformed DT in scmi_dev_used_by_cpus() Broadcom STB platforms were early adopters (2017) of the SCMI framework and as a result, not all deployed systems have a Device Tree entry where SCMI protocol 0x13 (PERFORMANCE) is declared as a clock provider, nor are the CPU Device Tree node(s) referencing protocol 0x13 as their clock provider. This was clarified in commit e11c480b6df1 ("dt-bindings: firmware: arm,scmi: Extend bindings for protocol@13") in 2023. For those platforms, we allow the checks done by scmi_dev_used_by_cpus() to continue, and in the event of not having done an early return, we key off the documented compatible string and give them a pass to continue to use scmi-cpufreq. Fixes: 6c9bb8692272 ("cpufreq: scmi: Skip SCMI devices that aren't used by the CPUs") Signed-off-by: Florian Fainelli Reviewed-by: Sudeep Holla Signed-off-by: Viresh Kumar --- drivers/cpufreq/scmi-cpufreq.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c index ef078426bfd5..38c165d526d1 100644 --- a/drivers/cpufreq/scmi-cpufreq.c +++ b/drivers/cpufreq/scmi-cpufreq.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -424,6 +425,15 @@ static bool scmi_dev_used_by_cpus(struct device *scmi_dev) return true; } + /* + * Older Broadcom STB chips had a "clocks" property for CPU node(s) + * that did not match the SCMI performance protocol node, if we got + * there, it means we had such an older Device Tree, therefore return + * true to preserve backwards compatibility. + */ + if (of_machine_is_compatible("brcm,brcmstb")) + return true; + return false; } From edafd4f3fd52a614c5cee2684559367eac2286dc Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Sat, 9 Aug 2025 15:29:16 +0530 Subject: [PATCH 01291/11391] 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 01292/11391] 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 bf7a6a67050f5d59a674ecc3ecd06d6b09cfec49 Mon Sep 17 00:00:00 2001 From: Vincent Li Date: Mon, 18 Aug 2025 09:51:13 -0700 Subject: [PATCH 01293/11391] bpftool: Add kernel.kptr_restrict hint for no instructions From bpftool's github repository issue [0]: When a Linux distribution has the kernel.kptr_restrict set to 2, bpftool prog dump jited returns "no instructions returned". This message can be puzzling to bpftool users who are not familiar with kernel BPF internals, so add a small hint for bpftool users to check the kernel.kptr_restrict setting similar to the DUMP_XLATED case. Outside of kernel.kptr_restrict, no instructions could also be returned in case the JIT was disabled. Signed-off-by: Vincent Li Signed-off-by: Daniel Borkmann Acked-by: Daniel Borkmann Link: https://github.com/libbpf/bpftool/issues/184 [0] Link: https://lore.kernel.org/bpf/20250818165113.15982-1-vincent.mc.li@gmail.com --- tools/bpf/bpftool/prog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index 9722d841abc0..cf18c3879680 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c @@ -714,7 +714,7 @@ prog_dump(struct bpf_prog_info *info, enum dump_mode mode, if (mode == DUMP_JITED) { if (info->jited_prog_len == 0 || !info->jited_prog_insns) { - p_info("no instructions returned"); + p_err("error retrieving jit dump: no instructions returned or kernel.kptr_restrict set?"); return -1; } buf = u64_to_ptr(info->jited_prog_insns); From b33b696f86f6d17c9083d69a13d7f32380d818d3 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 25 Jul 2025 23:52:57 +0200 Subject: [PATCH 01294/11391] 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 01295/11391] 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 01296/11391] 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 2b30fc01a6c788ed4a799ed8a6f42ed9ac82417f Mon Sep 17 00:00:00 2001 From: Mohsin Bashir Date: Wed, 13 Aug 2025 15:13:11 -0700 Subject: [PATCH 01297/11391] eth: fbnic: Add support for HDS configuration Add support for configuring the header data split threshold. For fbnic, the tcp data split support is enabled all the time. Fbnic supports a maximum buffer size of 4KB. However, the reservation for the headroom, tailroom, and padding reduce the max header size accordingly. ethtool_hds -g eth0 Ring parameters for eth0: Pre-set maximums: ... HDS thresh: 3584 Current hardware settings: ... HDS thresh: 1536 Verify hds tests in ksft-net-drv are passing ksft-net-drv]# ./drivers/net/hds.py TAP version 13 1..13 ok 1 hds.get_hds ok 2 hds.get_hds_thresh ok 3 hds.set_hds_disable # SKIP disabling of HDS not supported by ... ... ... ok 12 hds.ioctl_set_xdp ok 13 hds.ioctl_enabled_set_xdp \# Totals: pass:12 fail:0 xfail:0 xpass:0 skip:1 error:0 Signed-off-by: Jakub Kicinski Signed-off-by: Mohsin Bashir Link: https://patch.msgid.link/20250813221319.3367670-2-mohsin.bashr@gmail.com Signed-off-by: Paolo Abeni --- .../net/ethernet/meta/fbnic/fbnic_ethtool.c | 21 ++++++++++++++++--- .../net/ethernet/meta/fbnic/fbnic_netdev.c | 4 ++++ .../net/ethernet/meta/fbnic/fbnic_netdev.h | 2 ++ drivers/net/ethernet/meta/fbnic/fbnic_txrx.c | 17 +++++++++++---- drivers/net/ethernet/meta/fbnic/fbnic_txrx.h | 7 ++++++- 5 files changed, 43 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c index 461c8661eb93..569ddd767f9d 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c @@ -2,6 +2,7 @@ /* Copyright (c) Meta Platforms, Inc. and affiliates. */ #include +#include #include #include #include @@ -160,6 +161,7 @@ static void fbnic_clone_swap_cfg(struct fbnic_net *orig, swap(clone->num_rx_queues, orig->num_rx_queues); swap(clone->num_tx_queues, orig->num_tx_queues); swap(clone->num_napi, orig->num_napi); + swap(clone->hds_thresh, orig->hds_thresh); } static void fbnic_aggregate_vector_counters(struct fbnic_net *fbn, @@ -277,15 +279,21 @@ fbnic_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring, ring->rx_mini_pending = fbn->hpq_size; ring->rx_jumbo_pending = fbn->ppq_size; ring->tx_pending = fbn->txq_size; + + kernel_ring->tcp_data_split = ETHTOOL_TCP_DATA_SPLIT_ENABLED; + kernel_ring->hds_thresh_max = FBNIC_HDS_THRESH_MAX; + kernel_ring->hds_thresh = fbn->hds_thresh; } static void fbnic_set_rings(struct fbnic_net *fbn, - struct ethtool_ringparam *ring) + struct ethtool_ringparam *ring, + struct kernel_ethtool_ringparam *kernel_ring) { fbn->rcq_size = ring->rx_pending; fbn->hpq_size = ring->rx_mini_pending; fbn->ppq_size = ring->rx_jumbo_pending; fbn->txq_size = ring->tx_pending; + fbn->hds_thresh = kernel_ring->hds_thresh; } static int @@ -316,8 +324,13 @@ fbnic_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring, return -EINVAL; } + if (kernel_ring->tcp_data_split == ETHTOOL_TCP_DATA_SPLIT_DISABLED) { + NL_SET_ERR_MSG_MOD(extack, "Cannot disable TCP data split"); + return -EINVAL; + } + if (!netif_running(netdev)) { - fbnic_set_rings(fbn, ring); + fbnic_set_rings(fbn, ring, kernel_ring); return 0; } @@ -325,7 +338,7 @@ fbnic_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring, if (!clone) return -ENOMEM; - fbnic_set_rings(clone, ring); + fbnic_set_rings(clone, ring, kernel_ring); err = fbnic_alloc_napi_vectors(clone); if (err) @@ -1678,6 +1691,8 @@ fbnic_get_rmon_stats(struct net_device *netdev, static const struct ethtool_ops fbnic_ethtool_ops = { .supported_coalesce_params = ETHTOOL_COALESCE_USECS | ETHTOOL_COALESCE_RX_MAX_FRAMES, + .supported_ring_params = ETHTOOL_RING_USE_TCP_DATA_SPLIT | + ETHTOOL_RING_USE_HDS_THRS, .rxfh_max_num_contexts = FBNIC_RPC_RSS_TBL_COUNT, .get_drvinfo = fbnic_get_drvinfo, .get_regs_len = fbnic_get_regs_len, diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c index e67e99487a27..a7eb7a367b98 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c @@ -695,6 +695,10 @@ struct net_device *fbnic_netdev_alloc(struct fbnic_dev *fbd) fbn->rx_usecs = FBNIC_RX_USECS_DEFAULT; fbn->rx_max_frames = FBNIC_RX_FRAMES_DEFAULT; + /* Initialize the hds_thresh */ + netdev->cfg->hds_thresh = FBNIC_HDS_THRESH_DEFAULT; + fbn->hds_thresh = FBNIC_HDS_THRESH_DEFAULT; + default_queues = netif_get_num_default_rss_queues(); if (default_queues > fbd->max_num_queues) default_queues = fbd->max_num_queues; diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h index 86576ae04262..04c5c7ed6c3a 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h @@ -31,6 +31,8 @@ struct fbnic_net { u32 ppq_size; u32 rcq_size; + u32 hds_thresh; + u16 rx_usecs; u16 tx_usecs; diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c index f9543d03485f..7c69f6381d9e 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c @@ -2232,13 +2232,22 @@ static void fbnic_enable_rcq(struct fbnic_napi_vector *nv, { struct fbnic_net *fbn = netdev_priv(nv->napi.dev); u32 log_size = fls(rcq->size_mask); - u32 rcq_ctl; + u32 hds_thresh = fbn->hds_thresh; + u32 rcq_ctl = 0; fbnic_config_drop_mode_rcq(nv, rcq); - rcq_ctl = FIELD_PREP(FBNIC_QUEUE_RDE_CTL1_PADLEN_MASK, FBNIC_RX_PAD) | - FIELD_PREP(FBNIC_QUEUE_RDE_CTL1_MAX_HDR_MASK, - FBNIC_RX_MAX_HDR) | + /* Force lower bound on MAX_HEADER_BYTES. Below this, all frames should + * be split at L4. It would also result in the frames being split at + * L2/L3 depending on the frame size. + */ + if (fbn->hds_thresh < FBNIC_HDR_BYTES_MIN) { + rcq_ctl = FBNIC_QUEUE_RDE_CTL0_EN_HDR_SPLIT; + hds_thresh = FBNIC_HDR_BYTES_MIN; + } + + rcq_ctl |= FIELD_PREP(FBNIC_QUEUE_RDE_CTL1_PADLEN_MASK, FBNIC_RX_PAD) | + FIELD_PREP(FBNIC_QUEUE_RDE_CTL1_MAX_HDR_MASK, hds_thresh) | FIELD_PREP(FBNIC_QUEUE_RDE_CTL1_PAYLD_OFF_MASK, FBNIC_RX_PAYLD_OFFSET) | FIELD_PREP(FBNIC_QUEUE_RDE_CTL1_PAYLD_PG_CL_MASK, diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h index 34693596e5eb..7d27712d5462 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h @@ -53,7 +53,6 @@ struct fbnic_net; #define FBNIC_RX_HROOM \ (ALIGN(FBNIC_RX_TROOM + NET_SKB_PAD, 128) - FBNIC_RX_TROOM) #define FBNIC_RX_PAD 0 -#define FBNIC_RX_MAX_HDR (1536 - FBNIC_RX_PAD) #define FBNIC_RX_PAYLD_OFFSET 0 #define FBNIC_RX_PAYLD_PG_CL 0 @@ -61,6 +60,12 @@ struct fbnic_net; #define FBNIC_RING_F_CTX BIT(1) #define FBNIC_RING_F_STATS BIT(2) /* Ring's stats may be used */ +#define FBNIC_HDS_THRESH_MAX \ + (4096 - FBNIC_RX_HROOM - FBNIC_RX_TROOM - FBNIC_RX_PAD) +#define FBNIC_HDS_THRESH_DEFAULT \ + (1536 - FBNIC_RX_PAD) +#define FBNIC_HDR_BYTES_MIN 128 + struct fbnic_pkt_buff { struct xdp_buff buff; ktime_t hwtstamp; From 0cf5a39720d09793f9cc5a8ec6bb026e6b20e883 Mon Sep 17 00:00:00 2001 From: Mohsin Bashir Date: Wed, 13 Aug 2025 15:13:12 -0700 Subject: [PATCH 01298/11391] eth: fbnic: Update Headroom Fbnic currently reserves a minimum of 64B headroom, but this is insufficient for inserting additional headers (e.g., IPV6) via XDP, as only 24 bytes are available for adjustment. To address this limitation, increase the headroom to a larger value while ensuring better page use. Although the resulting headroom (192B) is smaller than the recommended value (256B), forcing the headroom to 256B would require aligning to 256B (as opposed to the current 128B), which can push the max headroom to 511B. Signed-off-by: Jakub Kicinski Signed-off-by: Mohsin Bashir Link: https://patch.msgid.link/20250813221319.3367670-3-mohsin.bashr@gmail.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/meta/fbnic/fbnic_txrx.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h index 7d27712d5462..66c84375e299 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h @@ -50,8 +50,9 @@ struct fbnic_net; #define FBNIC_RX_TROOM \ SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) +#define FBNIC_RX_HROOM_PAD 128 #define FBNIC_RX_HROOM \ - (ALIGN(FBNIC_RX_TROOM + NET_SKB_PAD, 128) - FBNIC_RX_TROOM) + (ALIGN(FBNIC_RX_TROOM + FBNIC_RX_HROOM_PAD, 128) - FBNIC_RX_TROOM) #define FBNIC_RX_PAD 0 #define FBNIC_RX_PAYLD_OFFSET 0 #define FBNIC_RX_PAYLD_PG_CL 0 From 61f9a066c3099264f40737d134c7921567f85072 Mon Sep 17 00:00:00 2001 From: Mohsin Bashir Date: Wed, 13 Aug 2025 15:13:13 -0700 Subject: [PATCH 01299/11391] eth: fbnic: Use shinfo to track frags state on Rx Remove local fields that track frags state and instead store this information directly in the shinfo struct. This change is necessary because the current implementation can lead to inaccuracies in certain scenarios, such as when using XDP multi-buff support. Specifically, the XDP program may update nr_frags without updating the local variables, resulting in an inconsistent state. Signed-off-by: Jakub Kicinski Signed-off-by: Mohsin Bashir Link: https://patch.msgid.link/20250813221319.3367670-4-mohsin.bashr@gmail.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/meta/fbnic/fbnic_txrx.c | 80 ++++++-------------- drivers/net/ethernet/meta/fbnic/fbnic_txrx.h | 4 +- 2 files changed, 26 insertions(+), 58 deletions(-) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c index 7c69f6381d9e..2adbe175ac09 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c @@ -892,9 +892,8 @@ static void fbnic_pkt_prepare(struct fbnic_napi_vector *nv, u64 rcd, xdp_prepare_buff(&pkt->buff, hdr_start, headroom, len - FBNIC_RX_PAD, true); - pkt->data_truesize = 0; - pkt->data_len = 0; - pkt->nr_frags = 0; + pkt->hwtstamp = 0; + pkt->add_frag_failed = false; } static void fbnic_add_rx_frag(struct fbnic_napi_vector *nv, u64 rcd, @@ -905,8 +904,8 @@ static void fbnic_add_rx_frag(struct fbnic_napi_vector *nv, u64 rcd, unsigned int pg_off = FIELD_GET(FBNIC_RCD_AL_BUFF_OFF_MASK, rcd); unsigned int len = FIELD_GET(FBNIC_RCD_AL_BUFF_LEN_MASK, rcd); struct page *page = fbnic_page_pool_get(&qt->sub1, pg_idx); - struct skb_shared_info *shinfo; unsigned int truesize; + bool added; truesize = FIELD_GET(FBNIC_RCD_AL_PAGE_FIN, rcd) ? FBNIC_BD_FRAG_SIZE - pg_off : ALIGN(len, 128); @@ -918,34 +917,34 @@ static void fbnic_add_rx_frag(struct fbnic_napi_vector *nv, u64 rcd, dma_sync_single_range_for_cpu(nv->dev, page_pool_get_dma_addr(page), pg_off, truesize, DMA_BIDIRECTIONAL); - /* Add page to xdp shared info */ - shinfo = xdp_get_shared_info_from_buff(&pkt->buff); - - /* We use gso_segs to store truesize */ - pkt->data_truesize += truesize; - - __skb_fill_page_desc_noacc(shinfo, pkt->nr_frags++, page, pg_off, len); - - /* Store data_len in gso_size */ - pkt->data_len += len; + added = xdp_buff_add_frag(&pkt->buff, page_to_netmem(page), pg_off, len, + truesize); + if (unlikely(!added)) { + pkt->add_frag_failed = true; + netdev_err_once(nv->napi.dev, + "Failed to add fragment to xdp_buff\n"); + } } static void fbnic_put_pkt_buff(struct fbnic_napi_vector *nv, struct fbnic_pkt_buff *pkt, int budget) { - struct skb_shared_info *shinfo; struct page *page; - int nr_frags; if (!pkt->buff.data_hard_start) return; - shinfo = xdp_get_shared_info_from_buff(&pkt->buff); - nr_frags = pkt->nr_frags; + if (xdp_buff_has_frags(&pkt->buff)) { + struct skb_shared_info *shinfo; + int nr_frags; - while (nr_frags--) { - page = skb_frag_page(&shinfo->frags[nr_frags]); - page_pool_put_full_page(nv->page_pool, page, !!budget); + shinfo = xdp_get_shared_info_from_buff(&pkt->buff); + nr_frags = shinfo->nr_frags; + + while (nr_frags--) { + page = skb_frag_page(&shinfo->frags[nr_frags]); + page_pool_put_full_page(nv->page_pool, page, !!budget); + } } page = virt_to_page(pkt->buff.data_hard_start); @@ -955,43 +954,12 @@ static void fbnic_put_pkt_buff(struct fbnic_napi_vector *nv, static struct sk_buff *fbnic_build_skb(struct fbnic_napi_vector *nv, struct fbnic_pkt_buff *pkt) { - unsigned int nr_frags = pkt->nr_frags; - struct skb_shared_info *shinfo; - unsigned int truesize; struct sk_buff *skb; - truesize = xdp_data_hard_end(&pkt->buff) + FBNIC_RX_TROOM - - pkt->buff.data_hard_start; - - /* Build frame around buffer */ - skb = napi_build_skb(pkt->buff.data_hard_start, truesize); - if (unlikely(!skb)) + skb = xdp_build_skb_from_buff(&pkt->buff); + if (!skb) return NULL; - /* Push data pointer to start of data, put tail to end of data */ - skb_reserve(skb, pkt->buff.data - pkt->buff.data_hard_start); - __skb_put(skb, pkt->buff.data_end - pkt->buff.data); - - /* Add tracking for metadata at the start of the frame */ - skb_metadata_set(skb, pkt->buff.data - pkt->buff.data_meta); - - /* Add Rx frags */ - if (nr_frags) { - /* Verify that shared info didn't move */ - shinfo = xdp_get_shared_info_from_buff(&pkt->buff); - WARN_ON(skb_shinfo(skb) != shinfo); - - skb->truesize += pkt->data_truesize; - skb->data_len += pkt->data_len; - shinfo->nr_frags = nr_frags; - skb->len += pkt->data_len; - } - - skb_mark_for_recycle(skb); - - /* Set MAC header specific fields */ - skb->protocol = eth_type_trans(skb, nv->napi.dev); - /* Add timestamp if present */ if (pkt->hwtstamp) skb_hwtstamps(skb)->hwtstamp = pkt->hwtstamp; @@ -1094,7 +1062,9 @@ static int fbnic_clean_rcq(struct fbnic_napi_vector *nv, /* We currently ignore the action table index */ break; case FBNIC_RCD_TYPE_META: - if (likely(!fbnic_rcd_metadata_err(rcd))) + if (unlikely(pkt->add_frag_failed)) + skb = NULL; + else if (likely(!fbnic_rcd_metadata_err(rcd))) skb = fbnic_build_skb(nv, pkt); /* Populate skb and invalidate XDP */ diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h index 66c84375e299..d236152bbaaa 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h @@ -70,9 +70,7 @@ struct fbnic_net; struct fbnic_pkt_buff { struct xdp_buff buff; ktime_t hwtstamp; - u32 data_truesize; - u16 data_len; - u16 nr_frags; + bool add_frag_failed; }; struct fbnic_queue_stats { From 9064ab485f04df40e7f0838245849e2e4c5159d9 Mon Sep 17 00:00:00 2001 From: Mohsin Bashir Date: Wed, 13 Aug 2025 15:13:14 -0700 Subject: [PATCH 01300/11391] eth: fbnic: Prefetch packet headers on Rx Issue a prefetch for the start of the buffer on Rx to try to avoid cache miss on packet headers. Signed-off-by: Jakub Kicinski Signed-off-by: Mohsin Bashir Link: https://patch.msgid.link/20250813221319.3367670-5-mohsin.bashr@gmail.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/meta/fbnic/fbnic_txrx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c index 2adbe175ac09..65d1e40addec 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c @@ -888,7 +888,7 @@ static void fbnic_pkt_prepare(struct fbnic_napi_vector *nv, u64 rcd, /* Build frame around buffer */ hdr_start = page_address(page) + hdr_pg_start; - + net_prefetch(pkt->buff.data); xdp_prepare_buff(&pkt->buff, hdr_start, headroom, len - FBNIC_RX_PAD, true); From 1b0a3950dbd4fa278dc33401a4faba2a23307a16 Mon Sep 17 00:00:00 2001 From: Mohsin Bashir Date: Wed, 13 Aug 2025 15:13:15 -0700 Subject: [PATCH 01301/11391] eth: fbnic: Add XDP pass, drop, abort support Add basic support for attaching an XDP program to the device and support for PASS/DROP/ABORT actions. In fbnic, buffers are always mapped as DMA_BIDIRECTIONAL. The BPF program pointer can be read either on a per-packet basis or on a per-NAPI poll basis. Both approaches are functionally equivalent, in the current code. Stick to per-packet as it limits number of arguments we need to pass around. On the XDP hot path, check that packets with fragments are only allowed when multi-buffer support is enabled for the XDP program. Ideally, this check should not be necessary because ndo_bpf verifies that for XDP programs without multi-buff support, MTU is less than the hds_thresh. However, the MTU currently does not enforce the receive size which would require cleaning up the data path and bouncing the link. For practical reasons, prioritize the ability to enter and exit BPF mode with different MTU sizes without requiring a full reconfig. Testing: Hook a simple XDP program that passes all the packets destined for a specific port iperf3 -c 192.168.1.10 -P 5 -p 12345 Connecting to host 192.168.1.10, port 12345 [ 5] local 192.168.1.9 port 46702 connected to 192.168.1.10 port 12345 [ ID] Interval Transfer Bitrate Retr Cwnd - - - - - - - - - - - - - - - - - - - - - - - - - [SUM] 1.00-2.00 sec 3.86 GBytes 33.2 Gbits/sec 0 XDP_DROP: Hook an XDP program that drops packets destined for a specific port iperf3 -c 192.168.1.10 -P 5 -p 12345 ^C- - - - - - - - - - - - - - - - - - - - - - - - - [ ID] Interval Transfer Bitrate Retr [SUM] 0.00-0.00 sec 0.00 Bytes 0.00 bits/sec 0 sender [SUM] 0.00-0.00 sec 0.00 Bytes 0.00 bits/sec receiver iperf3: interrupt - the client has terminated XDP with HDS: - Validate XDP attachment failure when HDS is low ~] ethtool -G eth0 hds-thresh 512 ~] sudo ip link set eth0 xdpdrv obj xdp_pass_12345.o sec xdp ~] Error: fbnic: MTU too high, or HDS threshold is too low for single buffer XDP. - Validate successful XDP attachment when HDS threshold is appropriate ~] ethtool -G eth0 hds-thresh 1536 ~] sudo ip link set eth0 xdpdrv obj xdp_pass_12345.o sec xdp - Validate when the XDP program is attached, changing HDS thresh to a lower value fails ~] ethtool -G eth0 hds-thresh 512 ~] netlink error: fbnic: Use higher HDS threshold or multi-buf capable program - Validate HDS thresh does not matter when xdp frags support is available ~] ethtool -G eth0 hds-thresh 512 ~] sudo ip link set eth0 xdpdrv obj xdp_pass_mb_12345.o sec xdp.frags Signed-off-by: Jakub Kicinski Signed-off-by: Mohsin Bashir Link: https://patch.msgid.link/20250813221319.3367670-6-mohsin.bashr@gmail.com Signed-off-by: Paolo Abeni --- .../net/ethernet/meta/fbnic/fbnic_ethtool.c | 11 +++ .../net/ethernet/meta/fbnic/fbnic_netdev.c | 35 +++++++ .../net/ethernet/meta/fbnic/fbnic_netdev.h | 5 + drivers/net/ethernet/meta/fbnic/fbnic_txrx.c | 96 +++++++++++++++++-- drivers/net/ethernet/meta/fbnic/fbnic_txrx.h | 1 + 5 files changed, 141 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c index 569ddd767f9d..4c231433a63d 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c @@ -329,6 +329,17 @@ fbnic_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring, return -EINVAL; } + /* If an XDP program is attached, we should check for potential frame + * splitting. If the new HDS threshold can cause splitting, we should + * only allow if the attached XDP program can handle frags. + */ + if (fbnic_check_split_frames(fbn->xdp_prog, netdev->mtu, + kernel_ring->hds_thresh)) { + NL_SET_ERR_MSG_MOD(extack, + "Use higher HDS threshold or multi-buf capable program"); + return -EINVAL; + } + if (!netif_running(netdev)) { fbnic_set_rings(fbn, ring, kernel_ring); return 0; diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c index a7eb7a367b98..fb81d1a7bc51 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c @@ -508,6 +508,40 @@ static void fbnic_get_stats64(struct net_device *dev, } } +bool fbnic_check_split_frames(struct bpf_prog *prog, unsigned int mtu, + u32 hds_thresh) +{ + if (!prog) + return false; + + if (prog->aux->xdp_has_frags) + return false; + + return mtu + ETH_HLEN > hds_thresh; +} + +static int fbnic_bpf(struct net_device *netdev, struct netdev_bpf *bpf) +{ + struct bpf_prog *prog = bpf->prog, *prev_prog; + struct fbnic_net *fbn = netdev_priv(netdev); + + if (bpf->command != XDP_SETUP_PROG) + return -EINVAL; + + if (fbnic_check_split_frames(prog, netdev->mtu, + fbn->hds_thresh)) { + NL_SET_ERR_MSG_MOD(bpf->extack, + "MTU too high, or HDS threshold is too low for single buffer XDP"); + return -EOPNOTSUPP; + } + + prev_prog = xchg(&fbn->xdp_prog, prog); + if (prev_prog) + bpf_prog_put(prev_prog); + + return 0; +} + static const struct net_device_ops fbnic_netdev_ops = { .ndo_open = fbnic_open, .ndo_stop = fbnic_stop, @@ -517,6 +551,7 @@ static const struct net_device_ops fbnic_netdev_ops = { .ndo_set_mac_address = fbnic_set_mac, .ndo_set_rx_mode = fbnic_set_rx_mode, .ndo_get_stats64 = fbnic_get_stats64, + .ndo_bpf = fbnic_bpf, .ndo_hwtstamp_get = fbnic_hwtstamp_get, .ndo_hwtstamp_set = fbnic_hwtstamp_set, }; diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h index 04c5c7ed6c3a..bfa79ea910d8 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h @@ -18,6 +18,8 @@ #define FBNIC_TUN_GSO_FEATURES NETIF_F_GSO_IPXIP6 struct fbnic_net { + struct bpf_prog *xdp_prog; + struct fbnic_ring *tx[FBNIC_MAX_TXQS]; struct fbnic_ring *rx[FBNIC_MAX_RXQS]; @@ -104,4 +106,7 @@ int fbnic_phylink_ethtool_ksettings_get(struct net_device *netdev, int fbnic_phylink_get_fecparam(struct net_device *netdev, struct ethtool_fecparam *fecparam); int fbnic_phylink_init(struct net_device *netdev); + +bool fbnic_check_split_frames(struct bpf_prog *prog, + unsigned int mtu, u32 hds_threshold); #endif /* _FBNIC_NETDEV_H_ */ diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c index 65d1e40addec..a669e169e3ad 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c @@ -2,17 +2,26 @@ /* Copyright (c) Meta Platforms, Inc. and affiliates. */ #include +#include +#include #include #include #include #include #include +#include #include "fbnic.h" #include "fbnic_csr.h" #include "fbnic_netdev.h" #include "fbnic_txrx.h" +enum { + FBNIC_XDP_PASS = 0, + FBNIC_XDP_CONSUME, + FBNIC_XDP_LEN_ERR, +}; + enum { FBNIC_XMIT_CB_TS = 0x01, }; @@ -877,7 +886,7 @@ static void fbnic_pkt_prepare(struct fbnic_napi_vector *nv, u64 rcd, headroom = hdr_pg_off - hdr_pg_start + FBNIC_RX_PAD; frame_sz = hdr_pg_end - hdr_pg_start; - xdp_init_buff(&pkt->buff, frame_sz, NULL); + xdp_init_buff(&pkt->buff, frame_sz, &qt->xdp_rxq); hdr_pg_start += (FBNIC_RCD_AL_BUFF_FRAG_MASK & rcd) * FBNIC_BD_FRAG_SIZE; @@ -967,6 +976,39 @@ static struct sk_buff *fbnic_build_skb(struct fbnic_napi_vector *nv, return skb; } +static struct sk_buff *fbnic_run_xdp(struct fbnic_napi_vector *nv, + struct fbnic_pkt_buff *pkt) +{ + struct fbnic_net *fbn = netdev_priv(nv->napi.dev); + struct bpf_prog *xdp_prog; + int act; + + xdp_prog = READ_ONCE(fbn->xdp_prog); + if (!xdp_prog) + goto xdp_pass; + + /* Should never happen, config paths enforce HDS threshold > MTU */ + if (xdp_buff_has_frags(&pkt->buff) && !xdp_prog->aux->xdp_has_frags) + return ERR_PTR(-FBNIC_XDP_LEN_ERR); + + act = bpf_prog_run_xdp(xdp_prog, &pkt->buff); + switch (act) { + case XDP_PASS: +xdp_pass: + return fbnic_build_skb(nv, pkt); + default: + bpf_warn_invalid_xdp_action(nv->napi.dev, xdp_prog, act); + fallthrough; + case XDP_ABORTED: + trace_xdp_exception(nv->napi.dev, xdp_prog, act); + fallthrough; + case XDP_DROP: + break; + } + + return ERR_PTR(-FBNIC_XDP_CONSUME); +} + static enum pkt_hash_types fbnic_skb_hash_type(u64 rcd) { return (FBNIC_RCD_META_L4_TYPE_MASK & rcd) ? PKT_HASH_TYPE_L4 : @@ -1065,7 +1107,7 @@ static int fbnic_clean_rcq(struct fbnic_napi_vector *nv, if (unlikely(pkt->add_frag_failed)) skb = NULL; else if (likely(!fbnic_rcd_metadata_err(rcd))) - skb = fbnic_build_skb(nv, pkt); + skb = fbnic_run_xdp(nv, pkt); /* Populate skb and invalidate XDP */ if (!IS_ERR_OR_NULL(skb)) { @@ -1251,6 +1293,7 @@ static void fbnic_free_napi_vector(struct fbnic_net *fbn, } for (j = 0; j < nv->rxt_count; j++, i++) { + xdp_rxq_info_unreg(&nv->qt[i].xdp_rxq); fbnic_remove_rx_ring(fbn, &nv->qt[i].sub0); fbnic_remove_rx_ring(fbn, &nv->qt[i].sub1); fbnic_remove_rx_ring(fbn, &nv->qt[i].cmpl); @@ -1423,6 +1466,11 @@ static int fbnic_alloc_napi_vector(struct fbnic_dev *fbd, struct fbnic_net *fbn, fbnic_ring_init(&qt->cmpl, db, rxq_idx, FBNIC_RING_F_STATS); fbn->rx[rxq_idx] = &qt->cmpl; + err = xdp_rxq_info_reg(&qt->xdp_rxq, fbn->netdev, rxq_idx, + nv->napi.napi_id); + if (err) + goto free_ring_cur_qt; + /* Update Rx queue index */ rxt_count--; rxq_idx += v_count; @@ -1433,6 +1481,25 @@ static int fbnic_alloc_napi_vector(struct fbnic_dev *fbd, struct fbnic_net *fbn, return 0; + while (rxt_count < nv->rxt_count) { + qt--; + + xdp_rxq_info_unreg(&qt->xdp_rxq); +free_ring_cur_qt: + fbnic_remove_rx_ring(fbn, &qt->sub0); + fbnic_remove_rx_ring(fbn, &qt->sub1); + fbnic_remove_rx_ring(fbn, &qt->cmpl); + rxt_count++; + } + while (txt_count < nv->txt_count) { + qt--; + + fbnic_remove_tx_ring(fbn, &qt->sub0); + fbnic_remove_tx_ring(fbn, &qt->cmpl); + + txt_count++; + } + fbnic_napi_free_irq(fbd, nv); pp_destroy: page_pool_destroy(nv->page_pool); napi_del: @@ -1709,8 +1776,10 @@ static void fbnic_free_nv_resources(struct fbnic_net *fbn, for (i = 0; i < nv->txt_count; i++) fbnic_free_qt_resources(fbn, &nv->qt[i]); - for (j = 0; j < nv->rxt_count; j++, i++) + for (j = 0; j < nv->rxt_count; j++, i++) { fbnic_free_qt_resources(fbn, &nv->qt[i]); + xdp_rxq_info_unreg_mem_model(&nv->qt[i].xdp_rxq); + } } static int fbnic_alloc_nv_resources(struct fbnic_net *fbn, @@ -1722,19 +1791,32 @@ static int fbnic_alloc_nv_resources(struct fbnic_net *fbn, for (i = 0; i < nv->txt_count; i++) { err = fbnic_alloc_tx_qt_resources(fbn, &nv->qt[i]); if (err) - goto free_resources; + goto free_qt_resources; } /* Allocate Rx Resources */ for (j = 0; j < nv->rxt_count; j++, i++) { + /* Register XDP memory model for completion queue */ + err = xdp_reg_mem_model(&nv->qt[i].xdp_rxq.mem, + MEM_TYPE_PAGE_POOL, + nv->page_pool); + if (err) + goto xdp_unreg_mem_model; + err = fbnic_alloc_rx_qt_resources(fbn, &nv->qt[i]); if (err) - goto free_resources; + goto xdp_unreg_cur_model; } return 0; -free_resources: +xdp_unreg_mem_model: + while (j-- && i--) { + fbnic_free_qt_resources(fbn, &nv->qt[i]); +xdp_unreg_cur_model: + xdp_rxq_info_unreg_mem_model(&nv->qt[i].xdp_rxq); + } +free_qt_resources: while (i--) fbnic_free_qt_resources(fbn, &nv->qt[i]); return err; @@ -2026,7 +2108,7 @@ void fbnic_flush(struct fbnic_net *fbn) memset(qt->cmpl.desc, 0, qt->cmpl.size); fbnic_put_pkt_buff(nv, qt->cmpl.pkt, 0); - qt->cmpl.pkt->buff.data_hard_start = NULL; + memset(qt->cmpl.pkt, 0, sizeof(struct fbnic_pkt_buff)); } } } diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h index d236152bbaaa..5536f72a1c85 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h @@ -128,6 +128,7 @@ struct fbnic_ring { struct fbnic_q_triad { struct fbnic_ring sub0, sub1, cmpl; + struct xdp_rxq_info xdp_rxq; }; struct fbnic_napi_vector { From cf4facfb132af01c3c1bf0fab7685b3db17446ea Mon Sep 17 00:00:00 2001 From: Mohsin Bashir Date: Wed, 13 Aug 2025 15:13:16 -0700 Subject: [PATCH 01302/11391] eth: fbnic: Add support for XDP queues Add support for allocating XDP_TX queues and configuring ring support. FBNIC has been designed with XDP support in mind. Each Tx queue has 2 submission queues and one completion queue, with the expectation that one of the submission queues will be used by the stack, and the other by XDP. XDP queues are populated by XDP_TX and start from index 128 in the TX queue array. The support for XDP_TX is added in the next patch. Signed-off-by: Jakub Kicinski Signed-off-by: Mohsin Bashir Link: https://patch.msgid.link/20250813221319.3367670-7-mohsin.bashr@gmail.com Signed-off-by: Paolo Abeni --- .../net/ethernet/meta/fbnic/fbnic_netdev.h | 2 +- drivers/net/ethernet/meta/fbnic/fbnic_txrx.c | 139 +++++++++++++++++- drivers/net/ethernet/meta/fbnic/fbnic_txrx.h | 7 + 3 files changed, 142 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h index bfa79ea910d8..0a6347f28210 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h @@ -20,7 +20,7 @@ struct fbnic_net { struct bpf_prog *xdp_prog; - struct fbnic_ring *tx[FBNIC_MAX_TXQS]; + struct fbnic_ring *tx[FBNIC_MAX_TXQS + FBNIC_MAX_XDPQS]; struct fbnic_ring *rx[FBNIC_MAX_RXQS]; struct fbnic_napi_vector *napi[FBNIC_MAX_NAPI_VECTORS]; diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c index a669e169e3ad..8c7709f707e6 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c @@ -615,6 +615,37 @@ static void fbnic_clean_twq0(struct fbnic_napi_vector *nv, int napi_budget, } } +static void fbnic_clean_twq1(struct fbnic_napi_vector *nv, bool pp_allow_direct, + struct fbnic_ring *ring, bool discard, + unsigned int hw_head) +{ + unsigned int head = ring->head; + u64 total_bytes = 0; + + while (hw_head != head) { + struct page *page; + u64 twd; + + if (unlikely(!(ring->desc[head] & FBNIC_TWD_TYPE(AL)))) + goto next_desc; + + twd = le64_to_cpu(ring->desc[head]); + page = ring->tx_buf[head]; + + total_bytes += FIELD_GET(FBNIC_TWD_LEN_MASK, twd); + + page_pool_put_page(nv->page_pool, page, -1, pp_allow_direct); +next_desc: + head++; + head &= ring->size_mask; + } + + if (!total_bytes) + return; + + ring->head = head; +} + static void fbnic_clean_tsq(struct fbnic_napi_vector *nv, struct fbnic_ring *ring, u64 tcd, int *ts_head, int *head0) @@ -698,12 +729,21 @@ static void fbnic_page_pool_drain(struct fbnic_ring *ring, unsigned int idx, } static void fbnic_clean_twq(struct fbnic_napi_vector *nv, int napi_budget, - struct fbnic_q_triad *qt, s32 ts_head, s32 head0) + struct fbnic_q_triad *qt, s32 ts_head, s32 head0, + s32 head1) { if (head0 >= 0) fbnic_clean_twq0(nv, napi_budget, &qt->sub0, false, head0); else if (ts_head >= 0) fbnic_clean_twq0(nv, napi_budget, &qt->sub0, false, ts_head); + + if (head1 >= 0) { + qt->cmpl.deferred_head = -1; + if (napi_budget) + fbnic_clean_twq1(nv, true, &qt->sub1, false, head1); + else + qt->cmpl.deferred_head = head1; + } } static void @@ -711,6 +751,7 @@ fbnic_clean_tcq(struct fbnic_napi_vector *nv, struct fbnic_q_triad *qt, int napi_budget) { struct fbnic_ring *cmpl = &qt->cmpl; + s32 head1 = cmpl->deferred_head; s32 head0 = -1, ts_head = -1; __le64 *raw_tcd, done; u32 head = cmpl->head; @@ -728,7 +769,10 @@ fbnic_clean_tcq(struct fbnic_napi_vector *nv, struct fbnic_q_triad *qt, switch (FIELD_GET(FBNIC_TCD_TYPE_MASK, tcd)) { case FBNIC_TCD_TYPE_0: - if (!(tcd & FBNIC_TCD_TWQ1)) + if (tcd & FBNIC_TCD_TWQ1) + head1 = FIELD_GET(FBNIC_TCD_TYPE0_HEAD1_MASK, + tcd); + else head0 = FIELD_GET(FBNIC_TCD_TYPE0_HEAD0_MASK, tcd); /* Currently all err status bits are related to @@ -761,7 +805,7 @@ fbnic_clean_tcq(struct fbnic_napi_vector *nv, struct fbnic_q_triad *qt, } /* Unmap and free processed buffers */ - fbnic_clean_twq(nv, napi_budget, qt, ts_head, head0); + fbnic_clean_twq(nv, napi_budget, qt, ts_head, head0, head1); } static void fbnic_clean_bdq(struct fbnic_napi_vector *nv, int napi_budget, @@ -1268,6 +1312,17 @@ static void fbnic_remove_tx_ring(struct fbnic_net *fbn, fbn->tx[txr->q_idx] = NULL; } +static void fbnic_remove_xdp_ring(struct fbnic_net *fbn, + struct fbnic_ring *xdpr) +{ + if (!(xdpr->flags & FBNIC_RING_F_STATS)) + return; + + /* Remove pointer to the Tx ring */ + WARN_ON(fbn->tx[xdpr->q_idx] && fbn->tx[xdpr->q_idx] != xdpr); + fbn->tx[xdpr->q_idx] = NULL; +} + static void fbnic_remove_rx_ring(struct fbnic_net *fbn, struct fbnic_ring *rxr) { @@ -1289,6 +1344,7 @@ static void fbnic_free_napi_vector(struct fbnic_net *fbn, for (i = 0; i < nv->txt_count; i++) { fbnic_remove_tx_ring(fbn, &nv->qt[i].sub0); + fbnic_remove_xdp_ring(fbn, &nv->qt[i].sub1); fbnic_remove_tx_ring(fbn, &nv->qt[i].cmpl); } @@ -1363,6 +1419,7 @@ static void fbnic_ring_init(struct fbnic_ring *ring, u32 __iomem *doorbell, ring->doorbell = doorbell; ring->q_idx = q_idx; ring->flags = flags; + ring->deferred_head = -1; } static int fbnic_alloc_napi_vector(struct fbnic_dev *fbd, struct fbnic_net *fbn, @@ -1372,11 +1429,18 @@ static int fbnic_alloc_napi_vector(struct fbnic_dev *fbd, struct fbnic_net *fbn, { int txt_count = txq_count, rxt_count = rxq_count; u32 __iomem *uc_addr = fbd->uc_addr0; + int xdp_count = 0, qt_count, err; struct fbnic_napi_vector *nv; struct fbnic_q_triad *qt; - int qt_count, err; u32 __iomem *db; + /* We need to reserve at least one Tx Queue Triad for an XDP ring */ + if (rxq_count) { + xdp_count = 1; + if (!txt_count) + txt_count = 1; + } + qt_count = txt_count + rxq_count; if (!qt_count) return -EINVAL; @@ -1425,12 +1489,13 @@ static int fbnic_alloc_napi_vector(struct fbnic_dev *fbd, struct fbnic_net *fbn, qt = nv->qt; while (txt_count) { + u8 flags = FBNIC_RING_F_CTX | FBNIC_RING_F_STATS; + /* Configure Tx queue */ db = &uc_addr[FBNIC_QUEUE(txq_idx) + FBNIC_QUEUE_TWQ0_TAIL]; /* Assign Tx queue to netdev if applicable */ if (txq_count > 0) { - u8 flags = FBNIC_RING_F_CTX | FBNIC_RING_F_STATS; fbnic_ring_init(&qt->sub0, db, txq_idx, flags); fbn->tx[txq_idx] = &qt->sub0; @@ -1440,6 +1505,28 @@ static int fbnic_alloc_napi_vector(struct fbnic_dev *fbd, struct fbnic_net *fbn, FBNIC_RING_F_DISABLED); } + /* Configure XDP queue */ + db = &uc_addr[FBNIC_QUEUE(txq_idx) + FBNIC_QUEUE_TWQ1_TAIL]; + + /* Assign XDP queue to netdev if applicable + * + * The setup for this is in itself a bit different. + * 1. We only need one XDP Tx queue per NAPI vector. + * 2. We associate it to the first Rx queue index. + * 3. The hardware side is associated based on the Tx Queue. + * 4. The netdev queue is offset by FBNIC_MAX_TXQs. + */ + if (xdp_count > 0) { + unsigned int xdp_idx = FBNIC_MAX_TXQS + rxq_idx; + + fbnic_ring_init(&qt->sub1, db, xdp_idx, flags); + fbn->tx[xdp_idx] = &qt->sub1; + xdp_count--; + } else { + fbnic_ring_init(&qt->sub1, db, 0, + FBNIC_RING_F_DISABLED); + } + /* Configure Tx completion queue */ db = &uc_addr[FBNIC_QUEUE(txq_idx) + FBNIC_QUEUE_TCQ_HEAD]; fbnic_ring_init(&qt->cmpl, db, 0, 0); @@ -1495,6 +1582,7 @@ static int fbnic_alloc_napi_vector(struct fbnic_dev *fbd, struct fbnic_net *fbn, qt--; fbnic_remove_tx_ring(fbn, &qt->sub0); + fbnic_remove_xdp_ring(fbn, &qt->sub1); fbnic_remove_tx_ring(fbn, &qt->cmpl); txt_count++; @@ -1729,6 +1817,10 @@ static int fbnic_alloc_tx_qt_resources(struct fbnic_net *fbn, if (err) return err; + err = fbnic_alloc_tx_ring_resources(fbn, &qt->sub1); + if (err) + goto free_sub0; + err = fbnic_alloc_tx_ring_resources(fbn, &qt->cmpl); if (err) goto free_sub1; @@ -1736,6 +1828,8 @@ static int fbnic_alloc_tx_qt_resources(struct fbnic_net *fbn, return 0; free_sub1: + fbnic_free_ring_resources(dev, &qt->sub1); +free_sub0: fbnic_free_ring_resources(dev, &qt->sub0); return err; } @@ -1923,6 +2017,15 @@ static void fbnic_disable_twq0(struct fbnic_ring *txr) fbnic_ring_wr32(txr, FBNIC_QUEUE_TWQ0_CTL, twq_ctl); } +static void fbnic_disable_twq1(struct fbnic_ring *txr) +{ + u32 twq_ctl = fbnic_ring_rd32(txr, FBNIC_QUEUE_TWQ1_CTL); + + twq_ctl &= ~FBNIC_QUEUE_TWQ_CTL_ENABLE; + + fbnic_ring_wr32(txr, FBNIC_QUEUE_TWQ1_CTL, twq_ctl); +} + static void fbnic_disable_tcq(struct fbnic_ring *txr) { fbnic_ring_wr32(txr, FBNIC_QUEUE_TCQ_CTL, 0); @@ -1968,6 +2071,7 @@ void fbnic_disable(struct fbnic_net *fbn) struct fbnic_q_triad *qt = &nv->qt[t]; fbnic_disable_twq0(&qt->sub0); + fbnic_disable_twq1(&qt->sub1); fbnic_disable_tcq(&qt->cmpl); } @@ -2082,6 +2186,8 @@ void fbnic_flush(struct fbnic_net *fbn) /* Clean the work queues of unprocessed work */ fbnic_clean_twq0(nv, 0, &qt->sub0, true, qt->sub0.tail); + fbnic_clean_twq1(nv, false, &qt->sub1, true, + qt->sub1.tail); /* Reset completion queue descriptor ring */ memset(qt->cmpl.desc, 0, qt->cmpl.size); @@ -2156,6 +2262,28 @@ static void fbnic_enable_twq0(struct fbnic_ring *twq) fbnic_ring_wr32(twq, FBNIC_QUEUE_TWQ0_CTL, FBNIC_QUEUE_TWQ_CTL_ENABLE); } +static void fbnic_enable_twq1(struct fbnic_ring *twq) +{ + u32 log_size = fls(twq->size_mask); + + if (!twq->size_mask) + return; + + /* Reset head/tail */ + fbnic_ring_wr32(twq, FBNIC_QUEUE_TWQ1_CTL, FBNIC_QUEUE_TWQ_CTL_RESET); + twq->tail = 0; + twq->head = 0; + + /* Store descriptor ring address and size */ + fbnic_ring_wr32(twq, FBNIC_QUEUE_TWQ1_BAL, lower_32_bits(twq->dma)); + fbnic_ring_wr32(twq, FBNIC_QUEUE_TWQ1_BAH, upper_32_bits(twq->dma)); + + /* Write lower 4 bits of log size as 64K ring size is 0 */ + fbnic_ring_wr32(twq, FBNIC_QUEUE_TWQ1_SIZE, log_size & 0xf); + + fbnic_ring_wr32(twq, FBNIC_QUEUE_TWQ1_CTL, FBNIC_QUEUE_TWQ_CTL_ENABLE); +} + static void fbnic_enable_tcq(struct fbnic_napi_vector *nv, struct fbnic_ring *tcq) { @@ -2341,6 +2469,7 @@ void fbnic_enable(struct fbnic_net *fbn) struct fbnic_q_triad *qt = &nv->qt[t]; fbnic_enable_twq0(&qt->sub0); + fbnic_enable_twq1(&qt->sub1); fbnic_enable_tcq(nv, &qt->cmpl); } diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h index 5536f72a1c85..0e92d11115a6 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h @@ -35,6 +35,7 @@ struct fbnic_net; #define FBNIC_MAX_TXQS 128u #define FBNIC_MAX_RXQS 128u +#define FBNIC_MAX_XDPQS 128u /* These apply to TWQs, TCQ, RCQ */ #define FBNIC_QUEUE_SIZE_MIN 16u @@ -119,6 +120,12 @@ struct fbnic_ring { u32 head, tail; /* Head/Tail of ring */ + /* Deferred_head is used to cache the head for TWQ1 if an attempt + * is made to clean TWQ1 with zero napi_budget. We do not use it for + * any other ring. + */ + s32 deferred_head; + struct fbnic_queue_stats stats; /* Slow path fields follow */ From 168deb7b31b2e2f578726093c8a133f8e36c0b86 Mon Sep 17 00:00:00 2001 From: Mohsin Bashir Date: Wed, 13 Aug 2025 15:13:17 -0700 Subject: [PATCH 01303/11391] eth: fbnic: Add support for XDP_TX action Add support for XDP_TX action and cleaning the associated work. Signed-off-by: Jakub Kicinski Signed-off-by: Mohsin Bashir Link: https://patch.msgid.link/20250813221319.3367670-8-mohsin.bashr@gmail.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/meta/fbnic/fbnic_txrx.c | 85 +++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c index 8c7709f707e6..de3610a7491a 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c @@ -19,6 +19,7 @@ enum { FBNIC_XDP_PASS = 0, FBNIC_XDP_CONSUME, + FBNIC_XDP_TX, FBNIC_XDP_LEN_ERR, }; @@ -1020,6 +1021,80 @@ static struct sk_buff *fbnic_build_skb(struct fbnic_napi_vector *nv, return skb; } +static long fbnic_pkt_tx(struct fbnic_napi_vector *nv, + struct fbnic_pkt_buff *pkt) +{ + struct fbnic_ring *ring = &nv->qt[0].sub1; + int size, offset, nsegs = 1, data_len = 0; + unsigned int tail = ring->tail; + struct skb_shared_info *shinfo; + skb_frag_t *frag = NULL; + struct page *page; + dma_addr_t dma; + __le64 *twd; + + if (unlikely(xdp_buff_has_frags(&pkt->buff))) { + shinfo = xdp_get_shared_info_from_buff(&pkt->buff); + nsegs += shinfo->nr_frags; + data_len = shinfo->xdp_frags_size; + frag = &shinfo->frags[0]; + } + + if (fbnic_desc_unused(ring) < nsegs) + return -FBNIC_XDP_CONSUME; + + page = virt_to_page(pkt->buff.data_hard_start); + offset = offset_in_page(pkt->buff.data); + dma = page_pool_get_dma_addr(page); + + size = pkt->buff.data_end - pkt->buff.data; + + while (nsegs--) { + dma_sync_single_range_for_device(nv->dev, dma, offset, size, + DMA_BIDIRECTIONAL); + dma += offset; + + ring->tx_buf[tail] = page; + + twd = &ring->desc[tail]; + *twd = cpu_to_le64(FIELD_PREP(FBNIC_TWD_ADDR_MASK, dma) | + FIELD_PREP(FBNIC_TWD_LEN_MASK, size) | + FIELD_PREP(FBNIC_TWD_TYPE_MASK, + FBNIC_TWD_TYPE_AL)); + + tail++; + tail &= ring->size_mask; + + if (!data_len) + break; + + offset = skb_frag_off(frag); + page = skb_frag_page(frag); + dma = page_pool_get_dma_addr(page); + + size = skb_frag_size(frag); + data_len -= size; + frag++; + } + + *twd |= FBNIC_TWD_TYPE(LAST_AL); + + ring->tail = tail; + + return -FBNIC_XDP_TX; +} + +static void fbnic_pkt_commit_tail(struct fbnic_napi_vector *nv, + unsigned int pkt_tail) +{ + struct fbnic_ring *ring = &nv->qt[0].sub1; + + /* Force DMA writes to flush before writing to tail */ + dma_wmb(); + + writel(pkt_tail, ring->doorbell); +} + static struct sk_buff *fbnic_run_xdp(struct fbnic_napi_vector *nv, struct fbnic_pkt_buff *pkt) { @@ -1040,6 +1115,8 @@ static struct sk_buff *fbnic_run_xdp(struct fbnic_napi_vector *nv, case XDP_PASS: xdp_pass: return fbnic_build_skb(nv, pkt); + case XDP_TX: + return ERR_PTR(fbnic_pkt_tx(nv, pkt)); default: bpf_warn_invalid_xdp_action(nv->napi.dev, xdp_prog, act); fallthrough; @@ -1104,10 +1181,10 @@ static int fbnic_clean_rcq(struct fbnic_napi_vector *nv, struct fbnic_q_triad *qt, int budget) { unsigned int packets = 0, bytes = 0, dropped = 0, alloc_failed = 0; + s32 head0 = -1, head1 = -1, pkt_tail = -1; u64 csum_complete = 0, csum_none = 0; struct fbnic_ring *rcq = &qt->cmpl; struct fbnic_pkt_buff *pkt; - s32 head0 = -1, head1 = -1; __le64 *raw_rcd, done; u32 head = rcq->head; @@ -1163,6 +1240,9 @@ static int fbnic_clean_rcq(struct fbnic_napi_vector *nv, bytes += skb->len; napi_gro_receive(&nv->napi, skb); + } else if (skb == ERR_PTR(-FBNIC_XDP_TX)) { + pkt_tail = nv->qt[0].sub1.tail; + bytes += xdp_get_buff_len(&pkt->buff); } else { if (!skb) { alloc_failed++; @@ -1198,6 +1278,9 @@ static int fbnic_clean_rcq(struct fbnic_napi_vector *nv, rcq->stats.rx.csum_none += csum_none; u64_stats_update_end(&rcq->stats.syncp); + if (pkt_tail >= 0) + fbnic_pkt_commit_tail(nv, pkt_tail); + /* Unmap and free processed buffers */ if (head0 >= 0) fbnic_clean_bdq(nv, budget, &qt->sub0, head0); From 5213ff086344394ddb586298ad1d408c93406621 Mon Sep 17 00:00:00 2001 From: Mohsin Bashir Date: Wed, 13 Aug 2025 15:13:18 -0700 Subject: [PATCH 01304/11391] eth: fbnic: Collect packet statistics for XDP Add support for XDP statistics collection and reporting via rtnl_link and netdev_queue API. For XDP programs without frags support, fbnic requires MTU to be less than the HDS threshold. If an over-sized frame is received, the frame is dropped and recorded as rx_length_errors reported via ip stats to highlight that this is an error. Signed-off-by: Jakub Kicinski Signed-off-by: Mohsin Bashir Link: https://patch.msgid.link/20250813221319.3367670-9-mohsin.bashr@gmail.com Signed-off-by: Paolo Abeni --- .../device_drivers/ethernet/meta/fbnic.rst | 11 ++++ .../net/ethernet/meta/fbnic/fbnic_netdev.c | 36 ++++++++++++- drivers/net/ethernet/meta/fbnic/fbnic_txrx.c | 51 +++++++++++++++++-- drivers/net/ethernet/meta/fbnic/fbnic_txrx.h | 1 + 4 files changed, 94 insertions(+), 5 deletions(-) diff --git a/Documentation/networking/device_drivers/ethernet/meta/fbnic.rst b/Documentation/networking/device_drivers/ethernet/meta/fbnic.rst index afb8353daefd..fb6559fa4be4 100644 --- a/Documentation/networking/device_drivers/ethernet/meta/fbnic.rst +++ b/Documentation/networking/device_drivers/ethernet/meta/fbnic.rst @@ -160,3 +160,14 @@ behavior and potential performance bottlenecks. credit exhaustion - ``pcie_ob_rd_no_np_cred``: Read requests dropped due to non-posted credit exhaustion + +XDP Length Error: +~~~~~~~~~~~~~~~~~ + +For XDP programs without frags support, fbnic tries to make sure that MTU fits +into a single buffer. If an oversized frame is received and gets fragmented, +it is dropped and the following netlink counters are updated + + - ``rx-length``: number of frames dropped due to lack of fragmentation + support in the attached XDP program + - ``rx-errors``: total number of packets with errors received on the interface diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c index fb81d1a7bc51..b8b684ad376b 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c @@ -407,11 +407,12 @@ static void fbnic_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats64) { u64 rx_bytes, rx_packets, rx_dropped = 0, rx_errors = 0; + u64 rx_over = 0, rx_missed = 0, rx_length = 0; u64 tx_bytes, tx_packets, tx_dropped = 0; struct fbnic_net *fbn = netdev_priv(dev); struct fbnic_dev *fbd = fbn->fbd; struct fbnic_queue_stats *stats; - u64 rx_over = 0, rx_missed = 0; + unsigned int start, i; fbnic_get_hw_stats(fbd); @@ -489,6 +490,7 @@ static void fbnic_get_stats64(struct net_device *dev, stats64->rx_missed_errors = rx_missed; for (i = 0; i < fbn->num_rx_queues; i++) { + struct fbnic_ring *xdpr = fbn->tx[FBNIC_MAX_TXQS + i]; struct fbnic_ring *rxr = fbn->rx[i]; if (!rxr) @@ -500,11 +502,29 @@ static void fbnic_get_stats64(struct net_device *dev, rx_bytes = stats->bytes; rx_packets = stats->packets; rx_dropped = stats->dropped; + rx_length = stats->rx.length_errors; } while (u64_stats_fetch_retry(&stats->syncp, start)); stats64->rx_bytes += rx_bytes; stats64->rx_packets += rx_packets; stats64->rx_dropped += rx_dropped; + stats64->rx_errors += rx_length; + stats64->rx_length_errors += rx_length; + + if (!xdpr) + continue; + + stats = &xdpr->stats; + do { + start = u64_stats_fetch_begin(&stats->syncp); + tx_bytes = stats->bytes; + tx_packets = stats->packets; + tx_dropped = stats->dropped; + } while (u64_stats_fetch_retry(&stats->syncp, start)); + + stats64->tx_bytes += tx_bytes; + stats64->tx_packets += tx_packets; + stats64->tx_dropped += tx_dropped; } } @@ -603,6 +623,7 @@ static void fbnic_get_queue_stats_tx(struct net_device *dev, int idx, struct fbnic_ring *txr = fbn->tx[idx]; struct fbnic_queue_stats *stats; u64 stop, wake, csum, lso; + struct fbnic_ring *xdpr; unsigned int start; u64 bytes, packets; @@ -626,6 +647,19 @@ static void fbnic_get_queue_stats_tx(struct net_device *dev, int idx, tx->hw_gso_wire_packets = lso; tx->stop = stop; tx->wake = wake; + + xdpr = fbn->tx[FBNIC_MAX_TXQS + idx]; + if (xdpr) { + stats = &xdpr->stats; + do { + start = u64_stats_fetch_begin(&stats->syncp); + bytes = stats->bytes; + packets = stats->packets; + } while (u64_stats_fetch_retry(&stats->syncp, start)); + + tx->bytes += bytes; + tx->packets += packets; + } } static void fbnic_get_base_stats(struct net_device *dev, diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c index de3610a7491a..fea4577e38d4 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c @@ -620,8 +620,8 @@ static void fbnic_clean_twq1(struct fbnic_napi_vector *nv, bool pp_allow_direct, struct fbnic_ring *ring, bool discard, unsigned int hw_head) { + u64 total_bytes = 0, total_packets = 0; unsigned int head = ring->head; - u64 total_bytes = 0; while (hw_head != head) { struct page *page; @@ -633,6 +633,11 @@ static void fbnic_clean_twq1(struct fbnic_napi_vector *nv, bool pp_allow_direct, twd = le64_to_cpu(ring->desc[head]); page = ring->tx_buf[head]; + /* TYPE_AL is 2, TYPE_LAST_AL is 3. So this trick gives + * us one increment per packet, with no branches. + */ + total_packets += FIELD_GET(FBNIC_TWD_TYPE_MASK, twd) - + FBNIC_TWD_TYPE_AL; total_bytes += FIELD_GET(FBNIC_TWD_LEN_MASK, twd); page_pool_put_page(nv->page_pool, page, -1, pp_allow_direct); @@ -645,6 +650,18 @@ static void fbnic_clean_twq1(struct fbnic_napi_vector *nv, bool pp_allow_direct, return; ring->head = head; + + if (discard) { + u64_stats_update_begin(&ring->stats.syncp); + ring->stats.dropped += total_packets; + u64_stats_update_end(&ring->stats.syncp); + return; + } + + u64_stats_update_begin(&ring->stats.syncp); + ring->stats.bytes += total_bytes; + ring->stats.packets += total_packets; + u64_stats_update_end(&ring->stats.syncp); } static void fbnic_clean_tsq(struct fbnic_napi_vector *nv, @@ -1040,8 +1057,12 @@ static long fbnic_pkt_tx(struct fbnic_napi_vector *nv, frag = &shinfo->frags[0]; } - if (fbnic_desc_unused(ring) < nsegs) + if (fbnic_desc_unused(ring) < nsegs) { + u64_stats_update_begin(&ring->stats.syncp); + ring->stats.dropped++; + u64_stats_update_end(&ring->stats.syncp); return -FBNIC_XDP_CONSUME; + } page = virt_to_page(pkt->buff.data_hard_start); offset = offset_in_page(pkt->buff.data); @@ -1181,8 +1202,8 @@ static int fbnic_clean_rcq(struct fbnic_napi_vector *nv, struct fbnic_q_triad *qt, int budget) { unsigned int packets = 0, bytes = 0, dropped = 0, alloc_failed = 0; + u64 csum_complete = 0, csum_none = 0, length_errors = 0; s32 head0 = -1, head1 = -1, pkt_tail = -1; - u64 csum_complete = 0, csum_none = 0; struct fbnic_ring *rcq = &qt->cmpl; struct fbnic_pkt_buff *pkt; __le64 *raw_rcd, done; @@ -1247,6 +1268,8 @@ static int fbnic_clean_rcq(struct fbnic_napi_vector *nv, if (!skb) { alloc_failed++; dropped++; + } else if (skb == ERR_PTR(-FBNIC_XDP_LEN_ERR)) { + length_errors++; } else { dropped++; } @@ -1276,6 +1299,7 @@ static int fbnic_clean_rcq(struct fbnic_napi_vector *nv, rcq->stats.rx.alloc_failed += alloc_failed; rcq->stats.rx.csum_complete += csum_complete; rcq->stats.rx.csum_none += csum_none; + rcq->stats.rx.length_errors += length_errors; u64_stats_update_end(&rcq->stats.syncp); if (pkt_tail >= 0) @@ -1359,8 +1383,9 @@ void fbnic_aggregate_ring_rx_counters(struct fbnic_net *fbn, fbn->rx_stats.rx.alloc_failed += stats->rx.alloc_failed; fbn->rx_stats.rx.csum_complete += stats->rx.csum_complete; fbn->rx_stats.rx.csum_none += stats->rx.csum_none; + fbn->rx_stats.rx.length_errors += stats->rx.length_errors; /* Remember to add new stats here */ - BUILD_BUG_ON(sizeof(fbn->rx_stats.rx) / 8 != 3); + BUILD_BUG_ON(sizeof(fbn->rx_stats.rx) / 8 != 4); } void fbnic_aggregate_ring_tx_counters(struct fbnic_net *fbn, @@ -1382,6 +1407,22 @@ void fbnic_aggregate_ring_tx_counters(struct fbnic_net *fbn, BUILD_BUG_ON(sizeof(fbn->tx_stats.twq) / 8 != 6); } +static void fbnic_aggregate_ring_xdp_counters(struct fbnic_net *fbn, + struct fbnic_ring *xdpr) +{ + struct fbnic_queue_stats *stats = &xdpr->stats; + + if (!(xdpr->flags & FBNIC_RING_F_STATS)) + return; + + /* Capture stats from queues before dissasociating them */ + fbn->rx_stats.bytes += stats->bytes; + fbn->rx_stats.packets += stats->packets; + fbn->rx_stats.dropped += stats->dropped; + fbn->tx_stats.bytes += stats->bytes; + fbn->tx_stats.packets += stats->packets; +} + static void fbnic_remove_tx_ring(struct fbnic_net *fbn, struct fbnic_ring *txr) { @@ -1401,6 +1442,8 @@ static void fbnic_remove_xdp_ring(struct fbnic_net *fbn, if (!(xdpr->flags & FBNIC_RING_F_STATS)) return; + fbnic_aggregate_ring_xdp_counters(fbn, xdpr); + /* Remove pointer to the Tx ring */ WARN_ON(fbn->tx[xdpr->q_idx] && fbn->tx[xdpr->q_idx] != xdpr); fbn->tx[xdpr->q_idx] = NULL; diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h index 0e92d11115a6..873440ca6a31 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h @@ -90,6 +90,7 @@ struct fbnic_queue_stats { u64 alloc_failed; u64 csum_complete; u64 csum_none; + u64 length_errors; } rx; }; u64 dropped; From 7fedb8f2677e89d6a39f238fe7428eaf7646ba58 Mon Sep 17 00:00:00 2001 From: Mohsin Bashir Date: Wed, 13 Aug 2025 15:13:19 -0700 Subject: [PATCH 01305/11391] eth: fbnic: Report XDP stats via ethtool Add support to collect XDP stats via ethtool API. We record packets and bytes sent, and packets dropped on the XDP_TX path. ethtool -S eth0 | grep xdp | grep -v "0" xdp_tx_queue_13_packets: 2 xdp_tx_queue_13_bytes: 16126 Signed-off-by: Jakub Kicinski Signed-off-by: Mohsin Bashir Link: https://patch.msgid.link/20250813221319.3367670-10-mohsin.bashr@gmail.com Signed-off-by: Paolo Abeni --- .../net/ethernet/meta/fbnic/fbnic_ethtool.c | 50 ++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c index 4c231433a63d..a758f510f886 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c @@ -112,6 +112,20 @@ static const struct fbnic_stat fbnic_gstrings_hw_q_stats[] = { FBNIC_HW_RXB_DEQUEUE_STATS_LEN * FBNIC_RXB_DEQUEUE_INDICES + \ FBNIC_HW_Q_STATS_LEN * FBNIC_MAX_QUEUES) +#define FBNIC_QUEUE_STAT(name, stat) \ + FBNIC_STAT_FIELDS(fbnic_ring, name, stat) + +static const struct fbnic_stat fbnic_gstrings_xdp_stats[] = { + FBNIC_QUEUE_STAT("xdp_tx_queue_%u_packets", stats.packets), + FBNIC_QUEUE_STAT("xdp_tx_queue_%u_bytes", stats.bytes), + FBNIC_QUEUE_STAT("xdp_tx_queue_%u_dropped", stats.dropped), +}; + +#define FBNIC_XDP_STATS_LEN ARRAY_SIZE(fbnic_gstrings_xdp_stats) + +#define FBNIC_STATS_LEN \ + (FBNIC_HW_STATS_LEN + FBNIC_XDP_STATS_LEN * FBNIC_MAX_XDPQS) + static void fbnic_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) { @@ -422,6 +436,16 @@ static void fbnic_get_rxb_dequeue_strings(u8 **data, unsigned int idx) ethtool_sprintf(data, stat->string, idx); } +static void fbnic_get_xdp_queue_strings(u8 **data, unsigned int idx) +{ + const struct fbnic_stat *stat; + int i; + + stat = fbnic_gstrings_xdp_stats; + for (i = 0; i < FBNIC_XDP_STATS_LEN; i++, stat++) + ethtool_sprintf(data, stat->string, idx); +} + static void fbnic_get_strings(struct net_device *dev, u32 sset, u8 *data) { const struct fbnic_stat *stat; @@ -447,6 +471,9 @@ static void fbnic_get_strings(struct net_device *dev, u32 sset, u8 *data) for (i = 0; i < FBNIC_HW_Q_STATS_LEN; i++, stat++) ethtool_sprintf(&data, stat->string, idx); } + + for (i = 0; i < FBNIC_MAX_XDPQS; i++) + fbnic_get_xdp_queue_strings(&data, i); break; } } @@ -464,6 +491,24 @@ static void fbnic_report_hw_stats(const struct fbnic_stat *stat, } } +static void fbnic_get_xdp_queue_stats(struct fbnic_ring *ring, u64 **data) +{ + const struct fbnic_stat *stat; + int i; + + if (!ring) { + *data += FBNIC_XDP_STATS_LEN; + return; + } + + stat = fbnic_gstrings_xdp_stats; + for (i = 0; i < FBNIC_XDP_STATS_LEN; i++, stat++, (*data)++) { + u8 *p = (u8 *)ring + stat->offset; + + **data = *(u64 *)p; + } +} + static void fbnic_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data) { @@ -511,13 +556,16 @@ static void fbnic_get_ethtool_stats(struct net_device *dev, FBNIC_HW_Q_STATS_LEN, &data); } spin_unlock(&fbd->hw_stats_lock); + + for (i = 0; i < FBNIC_MAX_XDPQS; i++) + fbnic_get_xdp_queue_stats(fbn->tx[i + FBNIC_MAX_TXQS], &data); } static int fbnic_get_sset_count(struct net_device *dev, int sset) { switch (sset) { case ETH_SS_STATS: - return FBNIC_HW_STATS_LEN; + return FBNIC_STATS_LEN; default: return -EOPNOTSUPP; } From 5d1c82943f3beaa8b97eb11d865239cbab88e527 Mon Sep 17 00:00:00 2001 From: Shubham Sharma Date: Sun, 10 Aug 2025 17:00:08 +0530 Subject: [PATCH 01306/11391] docs: device-mapper: fix typos in delay.rst and vdo-design.rst Fixed the following typos in device-mapper documentation: - explicitely -> explicitly - approriate -> appropriate Signed-off-by: Shubham Sharma Signed-off-by: Mikulas Patocka --- Documentation/admin-guide/device-mapper/delay.rst | 2 +- Documentation/admin-guide/device-mapper/vdo-design.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/admin-guide/device-mapper/delay.rst b/Documentation/admin-guide/device-mapper/delay.rst index 4d667228e744..982136160d6f 100644 --- a/Documentation/admin-guide/device-mapper/delay.rst +++ b/Documentation/admin-guide/device-mapper/delay.rst @@ -18,7 +18,7 @@ Table line has to either have 3, 6 or 9 arguments: to write and flush operations on optionally different write_device with optionally different sector offset -9: same as 6 arguments plus define flush_offset and flush_delay explicitely +9: same as 6 arguments plus define flush_offset and flush_delay explicitly on/with optionally different flush_device/flush_offset. Offsets are specified in sectors. diff --git a/Documentation/admin-guide/device-mapper/vdo-design.rst b/Documentation/admin-guide/device-mapper/vdo-design.rst index 3cd59decbec0..faa0ecd4a5ae 100644 --- a/Documentation/admin-guide/device-mapper/vdo-design.rst +++ b/Documentation/admin-guide/device-mapper/vdo-design.rst @@ -600,7 +600,7 @@ lock and return itself to the pool. All storage within vdo is managed as 4KB blocks, but it can accept writes as small as 512 bytes. Processing a write that is smaller than 4K requires a read-modify-write operation that reads the relevant 4K block, copies the -new data over the approriate sectors of the block, and then launches a +new data over the appropriate sectors of the block, and then launches a write operation for the modified data block. The read and write stages of this operation are nearly identical to the normal read and write operations, and a single data_vio is used throughout this operation. From a3191475d17c19826fff712cbd057032cb079399 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Tue, 5 Aug 2025 13:35:41 +0300 Subject: [PATCH 01307/11391] dm-ima: more strlen() drops Following commit ebbd17695e9e ("dm: ima: avoid extra calls to strlen()"), convert 'dm_ima_alloc_and_copy_capacity_str()' to return the number of characters emitted by 'scnprintf()' and simplify the users accordingly. Compile tested only. Signed-off-by: Dmitry Antipov Reviewed-by: Hou Tao Signed-off-by: Mikulas Patocka --- drivers/md/dm-ima.c | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/drivers/md/dm-ima.c b/drivers/md/dm-ima.c index 8b50c908c6f4..f5c0ecc7cb0b 100644 --- a/drivers/md/dm-ima.c +++ b/drivers/md/dm-ima.c @@ -157,10 +157,8 @@ static int dm_ima_alloc_and_copy_capacity_str(struct mapped_device *md, char **c if (!(*capacity_str)) return -ENOMEM; - scnprintf(*capacity_str, DM_IMA_DEVICE_BUF_LEN, "current_device_capacity=%llu;", - capacity); - - return 0; + return scnprintf(*capacity_str, DM_IMA_DEVICE_BUF_LEN, "current_device_capacity=%llu;", + capacity); } /* @@ -371,18 +369,18 @@ void dm_ima_measure_on_device_resume(struct mapped_device *md, bool swap) { char *device_table_data, *dev_name = NULL, *dev_uuid = NULL, *capacity_str = NULL; char active[] = "active_table_hash="; - unsigned int active_len = strlen(active), capacity_len = 0; + unsigned int active_len = strlen(active); unsigned int l = 0; bool noio = true; bool nodata = true; - int r; + int capacity_len; device_table_data = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN, GFP_KERNEL, noio); if (!device_table_data) return; - r = dm_ima_alloc_and_copy_capacity_str(md, &capacity_str, noio); - if (r) + capacity_len = dm_ima_alloc_and_copy_capacity_str(md, &capacity_str, noio); + if (capacity_len < 0) goto error; memcpy(device_table_data + l, DM_IMA_VERSION_STR, md->ima.dm_version_str_len); @@ -445,8 +443,7 @@ void dm_ima_measure_on_device_resume(struct mapped_device *md, bool swap) } if (nodata) { - r = dm_ima_alloc_and_copy_name_uuid(md, &dev_name, &dev_uuid, noio); - if (r) + if (dm_ima_alloc_and_copy_name_uuid(md, &dev_name, &dev_uuid, noio)) goto error; l = scnprintf(device_table_data, DM_IMA_DEVICE_BUF_LEN, @@ -454,7 +451,6 @@ void dm_ima_measure_on_device_resume(struct mapped_device *md, bool swap) DM_IMA_VERSION_STR, dev_name, dev_uuid); } - capacity_len = strlen(capacity_str); memcpy(device_table_data + l, capacity_str, capacity_len); l += capacity_len; @@ -483,18 +479,17 @@ void dm_ima_measure_on_device_remove(struct mapped_device *md, bool remove_all) unsigned int device_active_len = strlen(device_active_str); unsigned int device_inactive_len = strlen(device_inactive_str); unsigned int remove_all_len = strlen(remove_all_str); - unsigned int capacity_len = 0; unsigned int l = 0; bool noio = true; bool nodata = true; - int r; + int capacity_len; device_table_data = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN*2, GFP_KERNEL, noio); if (!device_table_data) goto exit; - r = dm_ima_alloc_and_copy_capacity_str(md, &capacity_str, noio); - if (r) { + capacity_len = dm_ima_alloc_and_copy_capacity_str(md, &capacity_str, noio); + if (capacity_len < 0) { kfree(device_table_data); goto exit; } @@ -570,7 +565,6 @@ void dm_ima_measure_on_device_remove(struct mapped_device *md, bool remove_all) memcpy(device_table_data + l, remove_all ? "y;" : "n;", 2); l += 2; - capacity_len = strlen(capacity_str); memcpy(device_table_data + l, capacity_str, capacity_len); l += capacity_len; @@ -602,20 +596,20 @@ void dm_ima_measure_on_device_remove(struct mapped_device *md, bool remove_all) */ void dm_ima_measure_on_table_clear(struct mapped_device *md, bool new_map) { - unsigned int l = 0, capacity_len = 0; + unsigned int l = 0; char *device_table_data = NULL, *dev_name = NULL, *dev_uuid = NULL, *capacity_str = NULL; char inactive_str[] = "inactive_table_hash="; unsigned int inactive_len = strlen(inactive_str); bool noio = true; bool nodata = true; - int r; + int capacity_len; device_table_data = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN, GFP_KERNEL, noio); if (!device_table_data) return; - r = dm_ima_alloc_and_copy_capacity_str(md, &capacity_str, noio); - if (r) + capacity_len = dm_ima_alloc_and_copy_capacity_str(md, &capacity_str, noio); + if (capacity_len < 0) goto error1; memcpy(device_table_data + l, DM_IMA_VERSION_STR, md->ima.dm_version_str_len); @@ -650,7 +644,6 @@ void dm_ima_measure_on_table_clear(struct mapped_device *md, bool new_map) DM_IMA_VERSION_STR, dev_name, dev_uuid); } - capacity_len = strlen(capacity_str); memcpy(device_table_data + l, capacity_str, capacity_len); l += capacity_len; @@ -703,7 +696,7 @@ void dm_ima_measure_on_device_rename(struct mapped_device *md) char *old_device_data = NULL, *new_device_data = NULL, *combined_device_data = NULL; char *new_dev_name = NULL, *new_dev_uuid = NULL, *capacity_str = NULL; bool noio = true; - int r, len; + int len; if (dm_ima_alloc_and_copy_device_data(md, &new_device_data, md->ima.active_table.num_targets, noio)) @@ -716,8 +709,7 @@ void dm_ima_measure_on_device_rename(struct mapped_device *md) if (!combined_device_data) goto error; - r = dm_ima_alloc_and_copy_capacity_str(md, &capacity_str, noio); - if (r) + if (dm_ima_alloc_and_copy_capacity_str(md, &capacity_str, noio) < 0) goto error; old_device_data = md->ima.active_table.device_metadata; From c3797175b3673b3a38d59991f7bf4762bce016dd Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Wed, 6 Aug 2025 20:27:04 +0800 Subject: [PATCH 01308/11391] dm: use vmalloc_array() to simplify code Remove array_size() calls and replace vmalloc() with vmalloc_array() to simplify the code. Signed-off-by: Qianfeng Rong Signed-off-by: Mikulas Patocka --- drivers/md/dm-cache-policy-smq.c | 2 +- drivers/md/dm-region-hash.c | 2 +- drivers/md/dm-switch.c | 4 ++-- drivers/md/dm-thin.c | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/md/dm-cache-policy-smq.c b/drivers/md/dm-cache-policy-smq.c index 2ed894155cab..7e1e8cc0e33a 100644 --- a/drivers/md/dm-cache-policy-smq.c +++ b/drivers/md/dm-cache-policy-smq.c @@ -590,7 +590,7 @@ static int h_init(struct smq_hash_table *ht, struct entry_space *es, unsigned in nr_buckets = roundup_pow_of_two(max(nr_entries / 4u, 16u)); ht->hash_bits = __ffs(nr_buckets); - ht->buckets = vmalloc(array_size(nr_buckets, sizeof(*ht->buckets))); + ht->buckets = vmalloc_array(nr_buckets, sizeof(*ht->buckets)); if (!ht->buckets) return -ENOMEM; diff --git a/drivers/md/dm-region-hash.c b/drivers/md/dm-region-hash.c index a4550975c27d..e9b47b659976 100644 --- a/drivers/md/dm-region-hash.c +++ b/drivers/md/dm-region-hash.c @@ -206,7 +206,7 @@ struct dm_region_hash *dm_region_hash_create( rh->shift = RH_HASH_SHIFT; rh->prime = RH_HASH_MULT; - rh->buckets = vmalloc(array_size(nr_buckets, sizeof(*rh->buckets))); + rh->buckets = vmalloc_array(nr_buckets, sizeof(*rh->buckets)); if (!rh->buckets) { DMERR("unable to allocate region hash bucket memory"); kfree(rh); diff --git a/drivers/md/dm-switch.c b/drivers/md/dm-switch.c index bb1a70b5a215..50a52ca50b34 100644 --- a/drivers/md/dm-switch.c +++ b/drivers/md/dm-switch.c @@ -114,8 +114,8 @@ static int alloc_region_table(struct dm_target *ti, unsigned int nr_paths) return -EINVAL; } - sctx->region_table = vmalloc(array_size(nr_slots, - sizeof(region_table_slot_t))); + sctx->region_table = vmalloc_array(nr_slots, + sizeof(region_table_slot_t)); if (!sctx->region_table) { ti->error = "Cannot allocate region table"; return -ENOMEM; diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 007bb93e5fca..c84149ba4e38 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -3031,8 +3031,8 @@ static struct pool *pool_create(struct mapped_device *pool_md, } pool->cell_sort_array = - vmalloc(array_size(CELL_SORT_ARRAY_SIZE, - sizeof(*pool->cell_sort_array))); + vmalloc_array(CELL_SORT_ARRAY_SIZE, + sizeof(*pool->cell_sort_array)); if (!pool->cell_sort_array) { *error = "Error allocating cell sort array"; err_p = ERR_PTR(-ENOMEM); From d4f00a584b1536f6655ae31641a3dd4c7a80b63c Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Mon, 11 Aug 2025 13:13:28 +0200 Subject: [PATCH 01309/11391] dm-ima: drop a useless argument The "gfp_t flags" is always GFP_KERNEL, so it can be removed. Signed-off-by: Mikulas Patocka --- drivers/md/dm-ima.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/md/dm-ima.c b/drivers/md/dm-ima.c index f5c0ecc7cb0b..efb3cd4f9cd4 100644 --- a/drivers/md/dm-ima.c +++ b/drivers/md/dm-ima.c @@ -45,7 +45,7 @@ static void fix_separator_chars(char **buf) /* * Internal function to allocate memory for IMA measurements. */ -static void *dm_ima_alloc(size_t len, gfp_t flags, bool noio) +static void *dm_ima_alloc(size_t len, bool noio) { unsigned int noio_flag; void *ptr; @@ -53,7 +53,7 @@ static void *dm_ima_alloc(size_t len, gfp_t flags, bool noio) if (noio) noio_flag = memalloc_noio_save(); - ptr = kzalloc(len, flags); + ptr = kzalloc(len, GFP_KERNEL); if (noio) memalloc_noio_restore(noio_flag); @@ -68,13 +68,13 @@ static int dm_ima_alloc_and_copy_name_uuid(struct mapped_device *md, char **dev_ char **dev_uuid, bool noio) { int r; - *dev_name = dm_ima_alloc(DM_NAME_LEN*2, GFP_KERNEL, noio); + *dev_name = dm_ima_alloc(DM_NAME_LEN*2, noio); if (!(*dev_name)) { r = -ENOMEM; goto error; } - *dev_uuid = dm_ima_alloc(DM_UUID_LEN*2, GFP_KERNEL, noio); + *dev_uuid = dm_ima_alloc(DM_UUID_LEN*2, noio); if (!(*dev_uuid)) { r = -ENOMEM; goto error; @@ -109,7 +109,7 @@ static int dm_ima_alloc_and_copy_device_data(struct mapped_device *md, char **de if (r) return r; - *device_data = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN, GFP_KERNEL, noio); + *device_data = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN, noio); if (!(*device_data)) { r = -ENOMEM; goto error; @@ -153,7 +153,7 @@ static int dm_ima_alloc_and_copy_capacity_str(struct mapped_device *md, char **c capacity = get_capacity(md->disk); - *capacity_str = dm_ima_alloc(DM_IMA_DEVICE_CAPACITY_BUF_LEN, GFP_KERNEL, noio); + *capacity_str = dm_ima_alloc(DM_IMA_DEVICE_CAPACITY_BUF_LEN, noio); if (!(*capacity_str)) return -ENOMEM; @@ -193,15 +193,15 @@ void dm_ima_measure_on_table_load(struct dm_table *table, unsigned int status_fl const size_t hash_alg_prefix_len = strlen(DM_IMA_TABLE_HASH_ALG) + 1; char table_load_event_name[] = "dm_table_load"; - ima_buf = dm_ima_alloc(DM_IMA_MEASUREMENT_BUF_LEN, GFP_KERNEL, noio); + ima_buf = dm_ima_alloc(DM_IMA_MEASUREMENT_BUF_LEN, noio); if (!ima_buf) return; - target_metadata_buf = dm_ima_alloc(DM_IMA_TARGET_METADATA_BUF_LEN, GFP_KERNEL, noio); + target_metadata_buf = dm_ima_alloc(DM_IMA_TARGET_METADATA_BUF_LEN, noio); if (!target_metadata_buf) goto error; - target_data_buf = dm_ima_alloc(DM_IMA_TARGET_DATA_BUF_LEN, GFP_KERNEL, noio); + target_data_buf = dm_ima_alloc(DM_IMA_TARGET_DATA_BUF_LEN, noio); if (!target_data_buf) goto error; @@ -216,7 +216,7 @@ void dm_ima_measure_on_table_load(struct dm_table *table, unsigned int status_fl shash->tfm = tfm; digest_size = crypto_shash_digestsize(tfm); - digest = dm_ima_alloc(digest_size, GFP_KERNEL, noio); + digest = dm_ima_alloc(digest_size, noio); if (!digest) goto error; @@ -325,7 +325,7 @@ void dm_ima_measure_on_table_load(struct dm_table *table, unsigned int status_fl if (r < 0) goto error; - digest_buf = dm_ima_alloc((digest_size*2) + hash_alg_prefix_len + 1, GFP_KERNEL, noio); + digest_buf = dm_ima_alloc((digest_size*2) + hash_alg_prefix_len + 1, noio); if (!digest_buf) goto error; @@ -375,7 +375,7 @@ void dm_ima_measure_on_device_resume(struct mapped_device *md, bool swap) bool nodata = true; int capacity_len; - device_table_data = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN, GFP_KERNEL, noio); + device_table_data = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN, noio); if (!device_table_data) return; @@ -484,7 +484,7 @@ void dm_ima_measure_on_device_remove(struct mapped_device *md, bool remove_all) bool nodata = true; int capacity_len; - device_table_data = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN*2, GFP_KERNEL, noio); + device_table_data = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN*2, noio); if (!device_table_data) goto exit; @@ -604,7 +604,7 @@ void dm_ima_measure_on_table_clear(struct mapped_device *md, bool new_map) bool nodata = true; int capacity_len; - device_table_data = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN, GFP_KERNEL, noio); + device_table_data = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN, noio); if (!device_table_data) return; @@ -705,7 +705,7 @@ void dm_ima_measure_on_device_rename(struct mapped_device *md) if (dm_ima_alloc_and_copy_name_uuid(md, &new_dev_name, &new_dev_uuid, noio)) goto error; - combined_device_data = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN * 2, GFP_KERNEL, noio); + combined_device_data = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN * 2, noio); if (!combined_device_data) goto error; From 31a9403b0d5450aa2595e2fbb8f6091f097906ab Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Mon, 11 Aug 2025 20:36:36 +0800 Subject: [PATCH 01310/11391] dm bufio: remove redundant __GFP_NOWARN GFP_NOWAIT already includes __GFP_NOWARN, so let's remove the redundant __GFP_NOWARN. Also update comments to clarify the flag semantics. Signed-off-by: Qianfeng Rong Signed-off-by: Mikulas Patocka --- drivers/md/dm-bufio.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index ff7595caf440..ad0507726abd 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -1337,7 +1337,7 @@ static void use_bio(struct dm_buffer *b, enum req_op op, sector_t sector, char *ptr; unsigned int len; - bio = bio_kmalloc(1, GFP_NOWAIT | __GFP_NORETRY | __GFP_NOWARN); + bio = bio_kmalloc(1, GFP_NOWAIT); if (!bio) { use_dmio(b, op, sector, n_sectors, offset, ioprio); return; @@ -1601,18 +1601,18 @@ static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client * dm-bufio is resistant to allocation failures (it just keeps * one buffer reserved in cases all the allocations fail). * So set flags to not try too hard: - * GFP_NOWAIT: don't wait; if we need to sleep we'll release our - * mutex and wait ourselves. + * GFP_NOWAIT: don't wait and don't print a warning in case of + * failure; if we need to sleep we'll release our mutex + * and wait ourselves. * __GFP_NORETRY: don't retry and rather return failure * __GFP_NOMEMALLOC: don't use emergency reserves - * __GFP_NOWARN: don't print a warning in case of failure * * For debugging, if we set the cache size to 1, no new buffers will * be allocated. */ while (1) { if (dm_bufio_cache_size_latch != 1) { - b = alloc_buffer(c, GFP_NOWAIT | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN); + b = alloc_buffer(c, GFP_NOWAIT | __GFP_NORETRY | __GFP_NOMEMALLOC); if (b) return b; } From a86f1b4047a9ccaa5a0e691e7cf52928b68f4595 Mon Sep 17 00:00:00 2001 From: Soham Metha Date: Wed, 13 Aug 2025 02:19:47 +0530 Subject: [PATCH 01311/11391] docs: device-mapper: fixed spelling mistakes in documentation found/fixed the following typos - flushs -> flushes in `Documentation/admin-guide/device-mapper/delay.rst` Signed-off-by: Soham Metha Signed-off-by: Mikulas Patocka --- Documentation/admin-guide/device-mapper/delay.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/admin-guide/device-mapper/delay.rst b/Documentation/admin-guide/device-mapper/delay.rst index 982136160d6f..a1e673c0e782 100644 --- a/Documentation/admin-guide/device-mapper/delay.rst +++ b/Documentation/admin-guide/device-mapper/delay.rst @@ -3,7 +3,7 @@ dm-delay ======== Device-Mapper's "delay" target delays reads and/or writes -and/or flushs and optionally maps them to different devices. +and/or flushes and optionally maps them to different devices. Arguments:: @@ -40,7 +40,7 @@ Example scripts #!/bin/sh # # Create mapped device delaying write and flush operations for 400ms and - # splitting reads to device $1 but writes and flushs to different device $2 + # splitting reads to device $1 but writes and flushes to different device $2 # to different offsets of 2048 and 4096 sectors respectively. # dmsetup create delayed --table "0 `blockdev --getsz $1` delay $1 2048 0 $2 4096 400" @@ -48,7 +48,7 @@ Example scripts :: #!/bin/sh # - # Create mapped device delaying reads for 50ms, writes for 100ms and flushs for 333ms + # Create mapped device delaying reads for 50ms, writes for 100ms and flushes for 333ms # onto the same backing device at offset 0 sectors. # dmsetup create delayed --table "0 `blockdev --getsz $1` delay $1 0 50 $2 0 100 $1 0 333" From c7c61bc417b0334c4feb2bac455c17bf36c5891b Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Fri, 15 Aug 2025 15:03:13 +0700 Subject: [PATCH 01312/11391] dm-vdo: Promote dm-vdo title to title heading dm-vdo docs currently has no explicit title heading but instead there are multiple section headings as top-level heading. As such, these sections are rendered as titles and inflates number of entries in the toctree index. Promote the first section heading ("dm-vdo") to title heading. Fixes: 04bf7ac646ab ("dm: add documentation for dm-vdo target") Signed-off-by: Bagas Sanjaya Signed-off-by: Mikulas Patocka --- Documentation/admin-guide/device-mapper/vdo.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/admin-guide/device-mapper/vdo.rst b/Documentation/admin-guide/device-mapper/vdo.rst index a14e6d3e787c..8a67b320a97b 100644 --- a/Documentation/admin-guide/device-mapper/vdo.rst +++ b/Documentation/admin-guide/device-mapper/vdo.rst @@ -1,5 +1,6 @@ .. SPDX-License-Identifier: GPL-2.0-only +====== dm-vdo ====== From 499cbe0f2fb0641cf07a1a8ac9f7317674295fea Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 18 Aug 2025 06:58:21 +0200 Subject: [PATCH 01313/11391] dm error: mark as DM_TARGET_PASSES_INTEGRITY Mark dm error as DM_TARGET_PASSES_INTEGRITY so that it can be stacked on top of PI capable devices. The claim is strictly speaking as lie as dm error fails all I/O and doesn't pass anything on, but doing the same for integrity I/O work just fine :) This helps to make about two dozen xfstests test cases pass on PI capable devices. Signed-off-by: Christoph Hellwig Signed-off-by: Mikulas Patocka --- drivers/md/dm-target.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/md/dm-target.c b/drivers/md/dm-target.c index 2af5a9514c05..8fede41adec0 100644 --- a/drivers/md/dm-target.c +++ b/drivers/md/dm-target.c @@ -263,7 +263,8 @@ static long io_err_dax_direct_access(struct dm_target *ti, pgoff_t pgoff, static struct target_type error_target = { .name = "error", .version = {1, 7, 0}, - .features = DM_TARGET_WILDCARD | DM_TARGET_ZONED_HM, + .features = DM_TARGET_WILDCARD | DM_TARGET_ZONED_HM | + DM_TARGET_PASSES_INTEGRITY, .ctr = io_err_ctr, .dtr = io_err_dtr, .map = io_err_map, From dcb8d01b65fb5a891ddbbedcbe6eff0b8ec37867 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 18 Jul 2025 19:13:39 +0300 Subject: [PATCH 01314/11391] dt-bindings: power: qcom-rpmpd: split RPMh domains definitions Historically both RPM and RPMh domain definitions were a part of the same, qcom-rpmpd.h header. Now as we have a separate header for RPMh definitions, qcom,rpmhpd.h, move all RPMh power domain definitions to that header. Signed-off-by: Dmitry Baryshkov Acked-by: Rob Herring (Arm) Reviewed-by: Konrad Dybcio Reviewed-by: Bjorn Andersson Link: https://lore.kernel.org/r/20250718-rework-rpmhpd-rpmpd-v1-1-eedca108e540@oss.qualcomm.com Signed-off-by: Ulf Hansson --- include/dt-bindings/power/qcom,rpmhpd.h | 233 ++++++++++++++++++++++++ include/dt-bindings/power/qcom-rpmpd.h | 228 +---------------------- 2 files changed, 234 insertions(+), 227 deletions(-) diff --git a/include/dt-bindings/power/qcom,rpmhpd.h b/include/dt-bindings/power/qcom,rpmhpd.h index e54ffa361451..73cceb88953f 100644 --- a/include/dt-bindings/power/qcom,rpmhpd.h +++ b/include/dt-bindings/power/qcom,rpmhpd.h @@ -29,4 +29,237 @@ #define RPMHPD_NSP2 19 #define RPMHPD_GMXC 20 +/* RPMh Power Domain performance levels */ +#define RPMH_REGULATOR_LEVEL_RETENTION 16 +#define RPMH_REGULATOR_LEVEL_MIN_SVS 48 +#define RPMH_REGULATOR_LEVEL_LOW_SVS_D3 50 +#define RPMH_REGULATOR_LEVEL_LOW_SVS_D2 52 +#define RPMH_REGULATOR_LEVEL_LOW_SVS_D1 56 +#define RPMH_REGULATOR_LEVEL_LOW_SVS_D0 60 +#define RPMH_REGULATOR_LEVEL_LOW_SVS 64 +#define RPMH_REGULATOR_LEVEL_LOW_SVS_P1 72 +#define RPMH_REGULATOR_LEVEL_LOW_SVS_L1 80 +#define RPMH_REGULATOR_LEVEL_LOW_SVS_L2 96 +#define RPMH_REGULATOR_LEVEL_SVS 128 +#define RPMH_REGULATOR_LEVEL_SVS_L0 144 +#define RPMH_REGULATOR_LEVEL_SVS_L1 192 +#define RPMH_REGULATOR_LEVEL_SVS_L2 224 +#define RPMH_REGULATOR_LEVEL_NOM 256 +#define RPMH_REGULATOR_LEVEL_NOM_L0 288 +#define RPMH_REGULATOR_LEVEL_NOM_L1 320 +#define RPMH_REGULATOR_LEVEL_NOM_L2 336 +#define RPMH_REGULATOR_LEVEL_TURBO 384 +#define RPMH_REGULATOR_LEVEL_TURBO_L0 400 +#define RPMH_REGULATOR_LEVEL_TURBO_L1 416 +#define RPMH_REGULATOR_LEVEL_TURBO_L2 432 +#define RPMH_REGULATOR_LEVEL_TURBO_L3 448 +#define RPMH_REGULATOR_LEVEL_TURBO_L4 452 +#define RPMH_REGULATOR_LEVEL_TURBO_L5 456 +#define RPMH_REGULATOR_LEVEL_SUPER_TURBO 464 +#define RPMH_REGULATOR_LEVEL_SUPER_TURBO_NO_CPR 480 + +/* + * Platform-specific power domain bindings. Don't add new entries here, use + * RPMHPD_* above. + */ + +/* SA8775P Power Domain Indexes */ +#define SA8775P_CX 0 +#define SA8775P_CX_AO 1 +#define SA8775P_DDR 2 +#define SA8775P_EBI 3 +#define SA8775P_GFX 4 +#define SA8775P_LCX 5 +#define SA8775P_LMX 6 +#define SA8775P_MMCX 7 +#define SA8775P_MMCX_AO 8 +#define SA8775P_MSS 9 +#define SA8775P_MX 10 +#define SA8775P_MX_AO 11 +#define SA8775P_MXC 12 +#define SA8775P_MXC_AO 13 +#define SA8775P_NSP0 14 +#define SA8775P_NSP1 15 +#define SA8775P_XO 16 + +/* SDM670 Power Domain Indexes */ +#define SDM670_MX 0 +#define SDM670_MX_AO 1 +#define SDM670_CX 2 +#define SDM670_CX_AO 3 +#define SDM670_LMX 4 +#define SDM670_LCX 5 +#define SDM670_GFX 6 +#define SDM670_MSS 7 + +/* SDM845 Power Domain Indexes */ +#define SDM845_EBI 0 +#define SDM845_MX 1 +#define SDM845_MX_AO 2 +#define SDM845_CX 3 +#define SDM845_CX_AO 4 +#define SDM845_LMX 5 +#define SDM845_LCX 6 +#define SDM845_GFX 7 +#define SDM845_MSS 8 + +/* SDX55 Power Domain Indexes */ +#define SDX55_MSS 0 +#define SDX55_MX 1 +#define SDX55_CX 2 + +/* SDX65 Power Domain Indexes */ +#define SDX65_MSS 0 +#define SDX65_MX 1 +#define SDX65_MX_AO 2 +#define SDX65_CX 3 +#define SDX65_CX_AO 4 +#define SDX65_MXC 5 + +/* SM6350 Power Domain Indexes */ +#define SM6350_CX 0 +#define SM6350_GFX 1 +#define SM6350_LCX 2 +#define SM6350_LMX 3 +#define SM6350_MSS 4 +#define SM6350_MX 5 + +/* SM8150 Power Domain Indexes */ +#define SM8150_MSS 0 +#define SM8150_EBI 1 +#define SM8150_LMX 2 +#define SM8150_LCX 3 +#define SM8150_GFX 4 +#define SM8150_MX 5 +#define SM8150_MX_AO 6 +#define SM8150_CX 7 +#define SM8150_CX_AO 8 +#define SM8150_MMCX 9 +#define SM8150_MMCX_AO 10 + +/* SA8155P is a special case, kept for backwards compatibility */ +#define SA8155P_CX SM8150_CX +#define SA8155P_CX_AO SM8150_CX_AO +#define SA8155P_EBI SM8150_EBI +#define SA8155P_GFX SM8150_GFX +#define SA8155P_MSS SM8150_MSS +#define SA8155P_MX SM8150_MX +#define SA8155P_MX_AO SM8150_MX_AO + +/* SM8250 Power Domain Indexes */ +#define SM8250_CX 0 +#define SM8250_CX_AO 1 +#define SM8250_EBI 2 +#define SM8250_GFX 3 +#define SM8250_LCX 4 +#define SM8250_LMX 5 +#define SM8250_MMCX 6 +#define SM8250_MMCX_AO 7 +#define SM8250_MX 8 +#define SM8250_MX_AO 9 + +/* SM8350 Power Domain Indexes */ +#define SM8350_CX 0 +#define SM8350_CX_AO 1 +#define SM8350_EBI 2 +#define SM8350_GFX 3 +#define SM8350_LCX 4 +#define SM8350_LMX 5 +#define SM8350_MMCX 6 +#define SM8350_MMCX_AO 7 +#define SM8350_MX 8 +#define SM8350_MX_AO 9 +#define SM8350_MXC 10 +#define SM8350_MXC_AO 11 +#define SM8350_MSS 12 + +/* SM8450 Power Domain Indexes */ +#define SM8450_CX 0 +#define SM8450_CX_AO 1 +#define SM8450_EBI 2 +#define SM8450_GFX 3 +#define SM8450_LCX 4 +#define SM8450_LMX 5 +#define SM8450_MMCX 6 +#define SM8450_MMCX_AO 7 +#define SM8450_MX 8 +#define SM8450_MX_AO 9 +#define SM8450_MXC 10 +#define SM8450_MXC_AO 11 +#define SM8450_MSS 12 + +/* SM8550 Power Domain Indexes */ +#define SM8550_CX 0 +#define SM8550_CX_AO 1 +#define SM8550_EBI 2 +#define SM8550_GFX 3 +#define SM8550_LCX 4 +#define SM8550_LMX 5 +#define SM8550_MMCX 6 +#define SM8550_MMCX_AO 7 +#define SM8550_MX 8 +#define SM8550_MX_AO 9 +#define SM8550_MXC 10 +#define SM8550_MXC_AO 11 +#define SM8550_MSS 12 +#define SM8550_NSP 13 + +/* QDU1000/QRU1000 Power Domain Indexes */ +#define QDU1000_EBI 0 +#define QDU1000_MSS 1 +#define QDU1000_CX 2 +#define QDU1000_MX 3 + +/* SC7180 Power Domain Indexes */ +#define SC7180_CX 0 +#define SC7180_CX_AO 1 +#define SC7180_GFX 2 +#define SC7180_MX 3 +#define SC7180_MX_AO 4 +#define SC7180_LMX 5 +#define SC7180_LCX 6 +#define SC7180_MSS 7 + +/* SC7280 Power Domain Indexes */ +#define SC7280_CX 0 +#define SC7280_CX_AO 1 +#define SC7280_EBI 2 +#define SC7280_GFX 3 +#define SC7280_MX 4 +#define SC7280_MX_AO 5 +#define SC7280_LMX 6 +#define SC7280_LCX 7 +#define SC7280_MSS 8 + +/* SC8180X Power Domain Indexes */ +#define SC8180X_CX 0 +#define SC8180X_CX_AO 1 +#define SC8180X_EBI 2 +#define SC8180X_GFX 3 +#define SC8180X_LCX 4 +#define SC8180X_LMX 5 +#define SC8180X_MMCX 6 +#define SC8180X_MMCX_AO 7 +#define SC8180X_MSS 8 +#define SC8180X_MX 9 +#define SC8180X_MX_AO 10 + +/* SC8280XP Power Domain Indexes */ +#define SC8280XP_CX 0 +#define SC8280XP_CX_AO 1 +#define SC8280XP_DDR 2 +#define SC8280XP_EBI 3 +#define SC8280XP_GFX 4 +#define SC8280XP_LCX 5 +#define SC8280XP_LMX 6 +#define SC8280XP_MMCX 7 +#define SC8280XP_MMCX_AO 8 +#define SC8280XP_MSS 9 +#define SC8280XP_MX 10 +#define SC8280XP_MXC 12 +#define SC8280XP_MX_AO 11 +#define SC8280XP_NSP 13 +#define SC8280XP_QPHY 14 +#define SC8280XP_XO 15 + #endif diff --git a/include/dt-bindings/power/qcom-rpmpd.h b/include/dt-bindings/power/qcom-rpmpd.h index f15bcee7c928..d303b3b37f18 100644 --- a/include/dt-bindings/power/qcom-rpmpd.h +++ b/include/dt-bindings/power/qcom-rpmpd.h @@ -4,66 +4,7 @@ #ifndef _DT_BINDINGS_POWER_QCOM_RPMPD_H #define _DT_BINDINGS_POWER_QCOM_RPMPD_H -/* SA8775P Power Domain Indexes */ -#define SA8775P_CX 0 -#define SA8775P_CX_AO 1 -#define SA8775P_DDR 2 -#define SA8775P_EBI 3 -#define SA8775P_GFX 4 -#define SA8775P_LCX 5 -#define SA8775P_LMX 6 -#define SA8775P_MMCX 7 -#define SA8775P_MMCX_AO 8 -#define SA8775P_MSS 9 -#define SA8775P_MX 10 -#define SA8775P_MX_AO 11 -#define SA8775P_MXC 12 -#define SA8775P_MXC_AO 13 -#define SA8775P_NSP0 14 -#define SA8775P_NSP1 15 -#define SA8775P_XO 16 - -/* SDM670 Power Domain Indexes */ -#define SDM670_MX 0 -#define SDM670_MX_AO 1 -#define SDM670_CX 2 -#define SDM670_CX_AO 3 -#define SDM670_LMX 4 -#define SDM670_LCX 5 -#define SDM670_GFX 6 -#define SDM670_MSS 7 - -/* SDM845 Power Domain Indexes */ -#define SDM845_EBI 0 -#define SDM845_MX 1 -#define SDM845_MX_AO 2 -#define SDM845_CX 3 -#define SDM845_CX_AO 4 -#define SDM845_LMX 5 -#define SDM845_LCX 6 -#define SDM845_GFX 7 -#define SDM845_MSS 8 - -/* SDX55 Power Domain Indexes */ -#define SDX55_MSS 0 -#define SDX55_MX 1 -#define SDX55_CX 2 - -/* SDX65 Power Domain Indexes */ -#define SDX65_MSS 0 -#define SDX65_MX 1 -#define SDX65_MX_AO 2 -#define SDX65_CX 3 -#define SDX65_CX_AO 4 -#define SDX65_MXC 5 - -/* SM6350 Power Domain Indexes */ -#define SM6350_CX 0 -#define SM6350_GFX 1 -#define SM6350_LCX 2 -#define SM6350_LMX 3 -#define SM6350_MSS 4 -#define SM6350_MX 5 +#include /* SM6375 Power Domain Indexes */ #define SM6375_VDDCX 0 @@ -77,173 +18,6 @@ #define SM6375_VDD_LPI_CX 8 #define SM6375_VDD_LPI_MX 9 -/* SM8150 Power Domain Indexes */ -#define SM8150_MSS 0 -#define SM8150_EBI 1 -#define SM8150_LMX 2 -#define SM8150_LCX 3 -#define SM8150_GFX 4 -#define SM8150_MX 5 -#define SM8150_MX_AO 6 -#define SM8150_CX 7 -#define SM8150_CX_AO 8 -#define SM8150_MMCX 9 -#define SM8150_MMCX_AO 10 - -/* SA8155P is a special case, kept for backwards compatibility */ -#define SA8155P_CX SM8150_CX -#define SA8155P_CX_AO SM8150_CX_AO -#define SA8155P_EBI SM8150_EBI -#define SA8155P_GFX SM8150_GFX -#define SA8155P_MSS SM8150_MSS -#define SA8155P_MX SM8150_MX -#define SA8155P_MX_AO SM8150_MX_AO - -/* SM8250 Power Domain Indexes */ -#define SM8250_CX 0 -#define SM8250_CX_AO 1 -#define SM8250_EBI 2 -#define SM8250_GFX 3 -#define SM8250_LCX 4 -#define SM8250_LMX 5 -#define SM8250_MMCX 6 -#define SM8250_MMCX_AO 7 -#define SM8250_MX 8 -#define SM8250_MX_AO 9 - -/* SM8350 Power Domain Indexes */ -#define SM8350_CX 0 -#define SM8350_CX_AO 1 -#define SM8350_EBI 2 -#define SM8350_GFX 3 -#define SM8350_LCX 4 -#define SM8350_LMX 5 -#define SM8350_MMCX 6 -#define SM8350_MMCX_AO 7 -#define SM8350_MX 8 -#define SM8350_MX_AO 9 -#define SM8350_MXC 10 -#define SM8350_MXC_AO 11 -#define SM8350_MSS 12 - -/* SM8450 Power Domain Indexes */ -#define SM8450_CX 0 -#define SM8450_CX_AO 1 -#define SM8450_EBI 2 -#define SM8450_GFX 3 -#define SM8450_LCX 4 -#define SM8450_LMX 5 -#define SM8450_MMCX 6 -#define SM8450_MMCX_AO 7 -#define SM8450_MX 8 -#define SM8450_MX_AO 9 -#define SM8450_MXC 10 -#define SM8450_MXC_AO 11 -#define SM8450_MSS 12 - -/* SM8550 Power Domain Indexes */ -#define SM8550_CX 0 -#define SM8550_CX_AO 1 -#define SM8550_EBI 2 -#define SM8550_GFX 3 -#define SM8550_LCX 4 -#define SM8550_LMX 5 -#define SM8550_MMCX 6 -#define SM8550_MMCX_AO 7 -#define SM8550_MX 8 -#define SM8550_MX_AO 9 -#define SM8550_MXC 10 -#define SM8550_MXC_AO 11 -#define SM8550_MSS 12 -#define SM8550_NSP 13 - -/* QDU1000/QRU1000 Power Domain Indexes */ -#define QDU1000_EBI 0 -#define QDU1000_MSS 1 -#define QDU1000_CX 2 -#define QDU1000_MX 3 - -/* SC7180 Power Domain Indexes */ -#define SC7180_CX 0 -#define SC7180_CX_AO 1 -#define SC7180_GFX 2 -#define SC7180_MX 3 -#define SC7180_MX_AO 4 -#define SC7180_LMX 5 -#define SC7180_LCX 6 -#define SC7180_MSS 7 - -/* SC7280 Power Domain Indexes */ -#define SC7280_CX 0 -#define SC7280_CX_AO 1 -#define SC7280_EBI 2 -#define SC7280_GFX 3 -#define SC7280_MX 4 -#define SC7280_MX_AO 5 -#define SC7280_LMX 6 -#define SC7280_LCX 7 -#define SC7280_MSS 8 - -/* SC8180X Power Domain Indexes */ -#define SC8180X_CX 0 -#define SC8180X_CX_AO 1 -#define SC8180X_EBI 2 -#define SC8180X_GFX 3 -#define SC8180X_LCX 4 -#define SC8180X_LMX 5 -#define SC8180X_MMCX 6 -#define SC8180X_MMCX_AO 7 -#define SC8180X_MSS 8 -#define SC8180X_MX 9 -#define SC8180X_MX_AO 10 - -/* SC8280XP Power Domain Indexes */ -#define SC8280XP_CX 0 -#define SC8280XP_CX_AO 1 -#define SC8280XP_DDR 2 -#define SC8280XP_EBI 3 -#define SC8280XP_GFX 4 -#define SC8280XP_LCX 5 -#define SC8280XP_LMX 6 -#define SC8280XP_MMCX 7 -#define SC8280XP_MMCX_AO 8 -#define SC8280XP_MSS 9 -#define SC8280XP_MX 10 -#define SC8280XP_MXC 12 -#define SC8280XP_MX_AO 11 -#define SC8280XP_NSP 13 -#define SC8280XP_QPHY 14 -#define SC8280XP_XO 15 - -/* SDM845 Power Domain performance levels */ -#define RPMH_REGULATOR_LEVEL_RETENTION 16 -#define RPMH_REGULATOR_LEVEL_MIN_SVS 48 -#define RPMH_REGULATOR_LEVEL_LOW_SVS_D3 50 -#define RPMH_REGULATOR_LEVEL_LOW_SVS_D2 52 -#define RPMH_REGULATOR_LEVEL_LOW_SVS_D1 56 -#define RPMH_REGULATOR_LEVEL_LOW_SVS_D0 60 -#define RPMH_REGULATOR_LEVEL_LOW_SVS 64 -#define RPMH_REGULATOR_LEVEL_LOW_SVS_P1 72 -#define RPMH_REGULATOR_LEVEL_LOW_SVS_L1 80 -#define RPMH_REGULATOR_LEVEL_LOW_SVS_L2 96 -#define RPMH_REGULATOR_LEVEL_SVS 128 -#define RPMH_REGULATOR_LEVEL_SVS_L0 144 -#define RPMH_REGULATOR_LEVEL_SVS_L1 192 -#define RPMH_REGULATOR_LEVEL_SVS_L2 224 -#define RPMH_REGULATOR_LEVEL_NOM 256 -#define RPMH_REGULATOR_LEVEL_NOM_L0 288 -#define RPMH_REGULATOR_LEVEL_NOM_L1 320 -#define RPMH_REGULATOR_LEVEL_NOM_L2 336 -#define RPMH_REGULATOR_LEVEL_TURBO 384 -#define RPMH_REGULATOR_LEVEL_TURBO_L0 400 -#define RPMH_REGULATOR_LEVEL_TURBO_L1 416 -#define RPMH_REGULATOR_LEVEL_TURBO_L2 432 -#define RPMH_REGULATOR_LEVEL_TURBO_L3 448 -#define RPMH_REGULATOR_LEVEL_TURBO_L4 452 -#define RPMH_REGULATOR_LEVEL_TURBO_L5 456 -#define RPMH_REGULATOR_LEVEL_SUPER_TURBO 464 -#define RPMH_REGULATOR_LEVEL_SUPER_TURBO_NO_CPR 480 - /* MDM9607 Power Domains */ #define MDM9607_VDDCX 0 #define MDM9607_VDDCX_AO 1 From e6e1e3b6b8f9b9b78aa0dccdde431145cefb05f5 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 18 Jul 2025 19:13:40 +0300 Subject: [PATCH 01315/11391] dt-bindings: power: qcom-rpmpd: sort out entries After removing RPMh PD indices, it becomes obvious that several entries don't follow the alphabetic sorting order. Move them in order to keep the file sorted. Signed-off-by: Dmitry Baryshkov Acked-by: Rob Herring (Arm) Reviewed-by: Bjorn Andersson Link: https://lore.kernel.org/r/20250718-rework-rpmhpd-rpmpd-v1-2-eedca108e540@oss.qualcomm.com Signed-off-by: Ulf Hansson --- include/dt-bindings/power/qcom-rpmpd.h | 42 +++++++++++++------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/include/dt-bindings/power/qcom-rpmpd.h b/include/dt-bindings/power/qcom-rpmpd.h index d303b3b37f18..65f7d5ecc352 100644 --- a/include/dt-bindings/power/qcom-rpmpd.h +++ b/include/dt-bindings/power/qcom-rpmpd.h @@ -6,18 +6,6 @@ #include -/* SM6375 Power Domain Indexes */ -#define SM6375_VDDCX 0 -#define SM6375_VDDCX_AO 1 -#define SM6375_VDDCX_VFL 2 -#define SM6375_VDDMX 3 -#define SM6375_VDDMX_AO 4 -#define SM6375_VDDMX_VFL 5 -#define SM6375_VDDGX 6 -#define SM6375_VDDGX_AO 7 -#define SM6375_VDD_LPI_CX 8 -#define SM6375_VDD_LPI_MX 9 - /* MDM9607 Power Domains */ #define MDM9607_VDDCX 0 #define MDM9607_VDDCX_AO 1 @@ -130,6 +118,16 @@ #define MSM8998_SSCMX 8 #define MSM8998_SSCMX_VFL 9 +/* QCM2290 Power Domains */ +#define QCM2290_VDDCX 0 +#define QCM2290_VDDCX_AO 1 +#define QCM2290_VDDCX_VFL 2 +#define QCM2290_VDDMX 3 +#define QCM2290_VDDMX_AO 4 +#define QCM2290_VDDMX_VFL 5 +#define QCM2290_VDD_LPI_CX 6 +#define QCM2290_VDD_LPI_MX 7 + /* QCS404 Power Domains */ #define QCS404_VDDMX 0 #define QCS404_VDDMX_AO 1 @@ -169,15 +167,17 @@ #define SM6125_VDDMX_AO 4 #define SM6125_VDDMX_VFL 5 -/* QCM2290 Power Domains */ -#define QCM2290_VDDCX 0 -#define QCM2290_VDDCX_AO 1 -#define QCM2290_VDDCX_VFL 2 -#define QCM2290_VDDMX 3 -#define QCM2290_VDDMX_AO 4 -#define QCM2290_VDDMX_VFL 5 -#define QCM2290_VDD_LPI_CX 6 -#define QCM2290_VDD_LPI_MX 7 +/* SM6375 Power Domain Indexes */ +#define SM6375_VDDCX 0 +#define SM6375_VDDCX_AO 1 +#define SM6375_VDDCX_VFL 2 +#define SM6375_VDDMX 3 +#define SM6375_VDDMX_AO 4 +#define SM6375_VDDMX_VFL 5 +#define SM6375_VDDGX 6 +#define SM6375_VDDGX_AO 7 +#define SM6375_VDD_LPI_CX 8 +#define SM6375_VDD_LPI_MX 9 /* RPM SMD Power Domain performance levels */ #define RPM_SMD_LEVEL_RETENTION 16 From 94838f383a050e124c044e74a954777b8f2e6c17 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 18 Jul 2025 19:13:41 +0300 Subject: [PATCH 01316/11391] dt-bindings: power: qcom-rpmpd: add generic bindings for RPM power domains Some of the Qualcomm RPM PD controllers use a common set of indices for power domains. Add generic indices for Qualcomm RPM power domain controllers. Signed-off-by: Dmitry Baryshkov Acked-by: Rob Herring (Arm) Reviewed-by: Bjorn Andersson Link: https://lore.kernel.org/r/20250718-rework-rpmhpd-rpmpd-v1-3-eedca108e540@oss.qualcomm.com Signed-off-by: Ulf Hansson --- include/dt-bindings/power/qcom-rpmpd.h | 121 ++++++++++++++----------- 1 file changed, 70 insertions(+), 51 deletions(-) diff --git a/include/dt-bindings/power/qcom-rpmpd.h b/include/dt-bindings/power/qcom-rpmpd.h index 65f7d5ecc352..4371ac941f29 100644 --- a/include/dt-bindings/power/qcom-rpmpd.h +++ b/include/dt-bindings/power/qcom-rpmpd.h @@ -6,18 +6,37 @@ #include +/* Generic RPM Power Domain Indexes */ +#define RPMPD_VDDCX 0 +#define RPMPD_VDDCX_AO 1 +/* VFC and VFL are mutually exclusive and can not be present on the same platform */ +#define RPMPD_VDDCX_VFC 2 +#define RPMPD_VDDCX_VFL 2 +#define RPMPD_VDDMX 3 +#define RPMPD_VDDMX_AO 4 +#define RPMPD_VDDMX_VFL 5 +#define RPMPD_SSCCX 6 +#define RPMPD_SSCCX_VFL 7 +#define RPMPD_SSCMX 8 +#define RPMPD_SSCMX_VFL 9 + +/* + * Platform-specific power domain bindings. Don't add new entries here, use + * RPMPD_* above. + */ + /* MDM9607 Power Domains */ -#define MDM9607_VDDCX 0 -#define MDM9607_VDDCX_AO 1 -#define MDM9607_VDDCX_VFL 2 -#define MDM9607_VDDMX 3 -#define MDM9607_VDDMX_AO 4 -#define MDM9607_VDDMX_VFL 5 +#define MDM9607_VDDCX RPMPD_VDDCX +#define MDM9607_VDDCX_AO RPMPD_VDDCX_AO +#define MDM9607_VDDCX_VFL RPMPD_VDDCX_VFL +#define MDM9607_VDDMX RPMPD_VDDMX +#define MDM9607_VDDMX_AO RPMPD_VDDMX_AO +#define MDM9607_VDDMX_VFL RPMPD_VDDMX_VFL /* MSM8226 Power Domain Indexes */ -#define MSM8226_VDDCX 0 -#define MSM8226_VDDCX_AO 1 -#define MSM8226_VDDCX_VFC 2 +#define MSM8226_VDDCX RPMPD_VDDCX +#define MSM8226_VDDCX_AO RPMPD_VDDCX_AO +#define MSM8226_VDDCX_VFC RPMPD_VDDCX_VFC /* MSM8939 Power Domains */ #define MSM8939_VDDMDCX 0 @@ -30,11 +49,11 @@ #define MSM8939_VDDMX_AO 7 /* MSM8916 Power Domain Indexes */ -#define MSM8916_VDDCX 0 -#define MSM8916_VDDCX_AO 1 -#define MSM8916_VDDCX_VFC 2 -#define MSM8916_VDDMX 3 -#define MSM8916_VDDMX_AO 4 +#define MSM8916_VDDCX RPMPD_VDDCX +#define MSM8916_VDDCX_AO RPMPD_VDDCX_AO +#define MSM8916_VDDCX_VFC RPMPD_VDDCX_VFC +#define MSM8916_VDDMX RPMPD_VDDMX +#define MSM8916_VDDMX_AO RPMPD_VDDMX_AO /* MSM8909 Power Domain Indexes */ #define MSM8909_VDDCX MSM8916_VDDCX @@ -44,11 +63,11 @@ #define MSM8909_VDDMX_AO MSM8916_VDDMX_AO /* MSM8917 Power Domain Indexes */ -#define MSM8917_VDDCX 0 -#define MSM8917_VDDCX_AO 1 -#define MSM8917_VDDCX_VFL 2 -#define MSM8917_VDDMX 3 -#define MSM8917_VDDMX_AO 4 +#define MSM8917_VDDCX RPMPD_VDDCX +#define MSM8917_VDDCX_AO RPMPD_VDDCX_AO +#define MSM8917_VDDCX_VFL RPMPD_VDDCX_VFL +#define MSM8917_VDDMX RPMPD_VDDMX +#define MSM8917_VDDMX_AO RPMPD_VDDMX_AO /* MSM8937 Power Domain Indexes */ #define MSM8937_VDDCX MSM8917_VDDCX @@ -81,12 +100,12 @@ #define MSM8974_VDDGFX_VFC 4 /* MSM8976 Power Domain Indexes */ -#define MSM8976_VDDCX 0 -#define MSM8976_VDDCX_AO 1 -#define MSM8976_VDDCX_VFL 2 -#define MSM8976_VDDMX 3 -#define MSM8976_VDDMX_AO 4 -#define MSM8976_VDDMX_VFL 5 +#define MSM8976_VDDCX RPMPD_VDDCX +#define MSM8976_VDDCX_AO RPMPD_VDDCX_AO +#define MSM8976_VDDCX_VFL RPMPD_VDDCX_VFL +#define MSM8976_VDDMX RPMPD_VDDMX +#define MSM8976_VDDMX_AO RPMPD_VDDMX_AO +#define MSM8976_VDDMX_VFL RPMPD_VDDMX_VFL /* MSM8994 Power Domain Indexes */ #define MSM8994_VDDCX 0 @@ -107,16 +126,16 @@ #define MSM8996_VDDSSCX_VFC 6 /* MSM8998 Power Domain Indexes */ -#define MSM8998_VDDCX 0 -#define MSM8998_VDDCX_AO 1 -#define MSM8998_VDDCX_VFL 2 -#define MSM8998_VDDMX 3 -#define MSM8998_VDDMX_AO 4 -#define MSM8998_VDDMX_VFL 5 -#define MSM8998_SSCCX 6 -#define MSM8998_SSCCX_VFL 7 -#define MSM8998_SSCMX 8 -#define MSM8998_SSCMX_VFL 9 +#define MSM8998_VDDCX RPMPD_VDDCX +#define MSM8998_VDDCX_AO RPMPD_VDDCX_AO +#define MSM8998_VDDCX_VFL RPMPD_VDDCX_VFL +#define MSM8998_VDDMX RPMPD_VDDMX +#define MSM8998_VDDMX_AO RPMPD_VDDMX_AO +#define MSM8998_VDDMX_VFL RPMPD_VDDMX_VFL +#define MSM8998_SSCCX RPMPD_SSCCX +#define MSM8998_SSCCX_VFL RPMPD_SSCCX_VFL +#define MSM8998_SSCMX RPMPD_SSCMX +#define MSM8998_SSCMX_VFL RPMPD_SSCMX_VFL /* QCM2290 Power Domains */ #define QCM2290_VDDCX 0 @@ -138,16 +157,16 @@ #define QCS404_LPIMX_VFL 6 /* SDM660 Power Domains */ -#define SDM660_VDDCX 0 -#define SDM660_VDDCX_AO 1 -#define SDM660_VDDCX_VFL 2 -#define SDM660_VDDMX 3 -#define SDM660_VDDMX_AO 4 -#define SDM660_VDDMX_VFL 5 -#define SDM660_SSCCX 6 -#define SDM660_SSCCX_VFL 7 -#define SDM660_SSCMX 8 -#define SDM660_SSCMX_VFL 9 +#define SDM660_VDDCX RPMPD_VDDCX +#define SDM660_VDDCX_AO RPMPD_VDDCX_AO +#define SDM660_VDDCX_VFL RPMPD_VDDCX_VFL +#define SDM660_VDDMX RPMPD_VDDMX +#define SDM660_VDDMX_AO RPMPD_VDDMX_AO +#define SDM660_VDDMX_VFL RPMPD_VDDMX_VFL +#define SDM660_SSCCX RPMPD_SSCCX +#define SDM660_SSCCX_VFL RPMPD_SSCCX_VFL +#define SDM660_SSCMX RPMPD_SSCMX +#define SDM660_SSCMX_VFL RPMPD_SSCMX_VFL /* SM6115 Power Domains */ #define SM6115_VDDCX 0 @@ -160,12 +179,12 @@ #define SM6115_VDD_LPI_MX 7 /* SM6125 Power Domains */ -#define SM6125_VDDCX 0 -#define SM6125_VDDCX_AO 1 -#define SM6125_VDDCX_VFL 2 -#define SM6125_VDDMX 3 -#define SM6125_VDDMX_AO 4 -#define SM6125_VDDMX_VFL 5 +#define SM6125_VDDCX RPMPD_VDDCX +#define SM6125_VDDCX_AO RPMPD_VDDCX_AO +#define SM6125_VDDCX_VFL RPMPD_VDDCX_VFL +#define SM6125_VDDMX RPMPD_VDDMX +#define SM6125_VDDMX_AO RPMPD_VDDMX_AO +#define SM6125_VDDMX_VFL RPMPD_VDDMX_VFL /* SM6375 Power Domain Indexes */ #define SM6375_VDDCX 0 From d9f0633867711cff87c5604a4f90daa8ab986e4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0erif=20Rami?= Date: Tue, 19 Aug 2025 09:51:17 +0200 Subject: [PATCH 01317/11391] ALSA: usb-audio: us144mkii: Use le16_to_cpu() for product ID comparison MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `us144mkii.c` driver was generating sparse warnings due to direct comparisons of `dev->descriptor.idProduct` (a `__le16` type) with integer constants. This commit resolves these warnings by explicitly converting `idProduct` to a CPU-endian integer using `le16_to_cpu()` before comparison. This ensures correct handling of endianness and eliminates the sparse warnings: - `restricted __le16 degrades to integer` Fixes: dee1bcf28a3d ("ALSA: usb-audio: Add initial driver for TASCAM US-144MKII") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202508190811.tjQJZI1X-lkp@intel.com/ Signed-off-by: Šerif Rami Link: https://patch.msgid.link/20250819075118.9221-1-ramiserifpersia@gmail.com Signed-off-by: Takashi Iwai --- sound/usb/usx2y/us144mkii.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/usb/usx2y/us144mkii.c b/sound/usb/usx2y/us144mkii.c index da53c1908c4a..3127a3206370 100644 --- a/sound/usb/usx2y/us144mkii.c +++ b/sound/usb/usx2y/us144mkii.c @@ -514,10 +514,10 @@ static int tascam_probe(struct usb_interface *intf, } strscpy(card->driver, DRIVER_NAME, sizeof(card->driver)); - if (dev->descriptor.idProduct == USB_PID_TASCAM_US144) { + if (le16_to_cpu(dev->descriptor.idProduct) == USB_PID_TASCAM_US144) { strscpy(card->shortname, "TASCAM US-144", sizeof(card->shortname)); - } else if (dev->descriptor.idProduct == USB_PID_TASCAM_US144MKII) { + } else if (le16_to_cpu(dev->descriptor.idProduct) == USB_PID_TASCAM_US144MKII) { strscpy(card->shortname, "TASCAM US-144MKII", sizeof(card->shortname)); } else { From 31f799ae091bb5254085520a41ecc060dc667e01 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 18 Jul 2025 19:13:42 +0300 Subject: [PATCH 01318/11391] pmdomain: qcom: rpmpd: switch to RPMPD_* indices Use generic RPMPD_* defines for power domain instead of using platform-specific defines for the platforms that use shared indices. Signed-off-by: Dmitry Baryshkov Reviewed-by: Bjorn Andersson Link: https://lore.kernel.org/r/20250718-rework-rpmhpd-rpmpd-v1-4-eedca108e540@oss.qualcomm.com Signed-off-by: Ulf Hansson --- drivers/pmdomain/qcom/rpmpd.c | 112 +++++++++++++++++----------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/drivers/pmdomain/qcom/rpmpd.c b/drivers/pmdomain/qcom/rpmpd.c index 833c46944600..f8580ec0f737 100644 --- a/drivers/pmdomain/qcom/rpmpd.c +++ b/drivers/pmdomain/qcom/rpmpd.c @@ -631,12 +631,12 @@ static struct rpmpd ssc_mx_rwsm0_vfl = { }; static struct rpmpd *mdm9607_rpmpds[] = { - [MDM9607_VDDCX] = &cx_s3a_lvl, - [MDM9607_VDDCX_AO] = &cx_s3a_lvl_ao, - [MDM9607_VDDCX_VFL] = &cx_s3a_vfl, - [MDM9607_VDDMX] = &mx_l12a_lvl, - [MDM9607_VDDMX_AO] = &mx_l12a_lvl_ao, - [MDM9607_VDDMX_VFL] = &mx_l12a_vfl, + [RPMPD_VDDCX] = &cx_s3a_lvl, + [RPMPD_VDDCX_AO] = &cx_s3a_lvl_ao, + [RPMPD_VDDCX_VFL] = &cx_s3a_vfl, + [RPMPD_VDDMX] = &mx_l12a_lvl, + [RPMPD_VDDMX_AO] = &mx_l12a_lvl_ao, + [RPMPD_VDDMX_VFL] = &mx_l12a_vfl, }; static const struct rpmpd_desc mdm9607_desc = { @@ -646,9 +646,9 @@ static const struct rpmpd_desc mdm9607_desc = { }; static struct rpmpd *msm8226_rpmpds[] = { - [MSM8226_VDDCX] = &cx_s1a_corner, - [MSM8226_VDDCX_AO] = &cx_s1a_corner_ao, - [MSM8226_VDDCX_VFC] = &cx_s1a_vfc, + [RPMPD_VDDCX] = &cx_s1a_corner, + [RPMPD_VDDCX_AO] = &cx_s1a_corner_ao, + [RPMPD_VDDCX_VFC] = &cx_s1a_vfc, }; static const struct rpmpd_desc msm8226_desc = { @@ -675,11 +675,11 @@ static const struct rpmpd_desc msm8939_desc = { }; static struct rpmpd *msm8916_rpmpds[] = { - [MSM8916_VDDCX] = &cx_s1a_corner, - [MSM8916_VDDCX_AO] = &cx_s1a_corner_ao, - [MSM8916_VDDCX_VFC] = &cx_s1a_vfc, - [MSM8916_VDDMX] = &mx_l3a_corner, - [MSM8916_VDDMX_AO] = &mx_l3a_corner_ao, + [RPMPD_VDDCX] = &cx_s1a_corner, + [RPMPD_VDDCX_AO] = &cx_s1a_corner_ao, + [RPMPD_VDDCX_VFC] = &cx_s1a_vfc, + [RPMPD_VDDMX] = &mx_l3a_corner, + [RPMPD_VDDMX_AO] = &mx_l3a_corner_ao, }; static const struct rpmpd_desc msm8916_desc = { @@ -689,11 +689,11 @@ static const struct rpmpd_desc msm8916_desc = { }; static struct rpmpd *msm8917_rpmpds[] = { - [MSM8917_VDDCX] = &cx_s2a_lvl, - [MSM8917_VDDCX_AO] = &cx_s2a_lvl_ao, - [MSM8917_VDDCX_VFL] = &cx_s2a_vfl, - [MSM8917_VDDMX] = &mx_l3a_lvl, - [MSM8917_VDDMX_AO] = &mx_l3a_lvl_ao, + [RPMPD_VDDCX] = &cx_s2a_lvl, + [RPMPD_VDDCX_AO] = &cx_s2a_lvl_ao, + [RPMPD_VDDCX_VFL] = &cx_s2a_vfl, + [RPMPD_VDDMX] = &mx_l3a_lvl, + [RPMPD_VDDMX_AO] = &mx_l3a_lvl_ao, }; static const struct rpmpd_desc msm8917_desc = { @@ -747,12 +747,12 @@ static const struct rpmpd_desc msm8974pro_pma8084_desc = { }; static struct rpmpd *msm8976_rpmpds[] = { - [MSM8976_VDDCX] = &cx_s2a_lvl, - [MSM8976_VDDCX_AO] = &cx_s2a_lvl_ao, - [MSM8976_VDDCX_VFL] = &cx_rwsc2_vfl, - [MSM8976_VDDMX] = &mx_s6a_lvl, - [MSM8976_VDDMX_AO] = &mx_s6a_lvl_ao, - [MSM8976_VDDMX_VFL] = &mx_rwsm6_vfl, + [RPMPD_VDDCX] = &cx_s2a_lvl, + [RPMPD_VDDCX_AO] = &cx_s2a_lvl_ao, + [RPMPD_VDDCX_VFL] = &cx_rwsc2_vfl, + [RPMPD_VDDMX] = &mx_s6a_lvl, + [RPMPD_VDDMX_AO] = &mx_s6a_lvl_ao, + [RPMPD_VDDMX_VFL] = &mx_rwsm6_vfl, }; static const struct rpmpd_desc msm8976_desc = { @@ -796,16 +796,16 @@ static const struct rpmpd_desc msm8996_desc = { }; static struct rpmpd *msm8998_rpmpds[] = { - [MSM8998_VDDCX] = &cx_rwcx0_lvl, - [MSM8998_VDDCX_AO] = &cx_rwcx0_lvl_ao, - [MSM8998_VDDCX_VFL] = &cx_rwcx0_vfl, - [MSM8998_VDDMX] = &mx_rwmx0_lvl, - [MSM8998_VDDMX_AO] = &mx_rwmx0_lvl_ao, - [MSM8998_VDDMX_VFL] = &mx_rwmx0_vfl, - [MSM8998_SSCCX] = &ssc_cx_rwsc0_lvl, - [MSM8998_SSCCX_VFL] = &ssc_cx_rwsc0_vfl, - [MSM8998_SSCMX] = &ssc_mx_rwsm0_lvl, - [MSM8998_SSCMX_VFL] = &ssc_mx_rwsm0_vfl, + [RPMPD_VDDCX] = &cx_rwcx0_lvl, + [RPMPD_VDDCX_AO] = &cx_rwcx0_lvl_ao, + [RPMPD_VDDCX_VFL] = &cx_rwcx0_vfl, + [RPMPD_VDDMX] = &mx_rwmx0_lvl, + [RPMPD_VDDMX_AO] = &mx_rwmx0_lvl_ao, + [RPMPD_VDDMX_VFL] = &mx_rwmx0_vfl, + [RPMPD_SSCCX] = &ssc_cx_rwsc0_lvl, + [RPMPD_SSCCX_VFL] = &ssc_cx_rwsc0_vfl, + [RPMPD_SSCMX] = &ssc_mx_rwsm0_lvl, + [RPMPD_SSCMX_VFL] = &ssc_mx_rwsm0_vfl, }; static const struct rpmpd_desc msm8998_desc = { @@ -831,11 +831,11 @@ static const struct rpmpd_desc qcs404_desc = { }; static struct rpmpd *qm215_rpmpds[] = { - [QM215_VDDCX] = &cx_s1a_lvl, - [QM215_VDDCX_AO] = &cx_s1a_lvl_ao, - [QM215_VDDCX_VFL] = &cx_s1a_vfl, - [QM215_VDDMX] = &mx_l2a_lvl, - [QM215_VDDMX_AO] = &mx_l2a_lvl_ao, + [RPMPD_VDDCX] = &cx_s1a_lvl, + [RPMPD_VDDCX_AO] = &cx_s1a_lvl_ao, + [RPMPD_VDDCX_VFL] = &cx_s1a_vfl, + [RPMPD_VDDMX] = &mx_l2a_lvl, + [RPMPD_VDDMX_AO] = &mx_l2a_lvl_ao, }; static const struct rpmpd_desc qm215_desc = { @@ -845,16 +845,16 @@ static const struct rpmpd_desc qm215_desc = { }; static struct rpmpd *sdm660_rpmpds[] = { - [SDM660_VDDCX] = &cx_rwcx0_lvl, - [SDM660_VDDCX_AO] = &cx_rwcx0_lvl_ao, - [SDM660_VDDCX_VFL] = &cx_rwcx0_vfl, - [SDM660_VDDMX] = &mx_rwmx0_lvl, - [SDM660_VDDMX_AO] = &mx_rwmx0_lvl_ao, - [SDM660_VDDMX_VFL] = &mx_rwmx0_vfl, - [SDM660_SSCCX] = &ssc_cx_rwlc0_lvl, - [SDM660_SSCCX_VFL] = &ssc_cx_rwlc0_vfl, - [SDM660_SSCMX] = &ssc_mx_rwlm0_lvl, - [SDM660_SSCMX_VFL] = &ssc_mx_rwlm0_vfl, + [RPMPD_VDDCX] = &cx_rwcx0_lvl, + [RPMPD_VDDCX_AO] = &cx_rwcx0_lvl_ao, + [RPMPD_VDDCX_VFL] = &cx_rwcx0_vfl, + [RPMPD_VDDMX] = &mx_rwmx0_lvl, + [RPMPD_VDDMX_AO] = &mx_rwmx0_lvl_ao, + [RPMPD_VDDMX_VFL] = &mx_rwmx0_vfl, + [RPMPD_SSCCX] = &ssc_cx_rwlc0_lvl, + [RPMPD_SSCCX_VFL] = &ssc_cx_rwlc0_vfl, + [RPMPD_SSCMX] = &ssc_mx_rwlm0_lvl, + [RPMPD_SSCMX_VFL] = &ssc_mx_rwlm0_vfl, }; static const struct rpmpd_desc sdm660_desc = { @@ -881,12 +881,12 @@ static const struct rpmpd_desc sm6115_desc = { }; static struct rpmpd *sm6125_rpmpds[] = { - [SM6125_VDDCX] = &cx_rwcx0_lvl, - [SM6125_VDDCX_AO] = &cx_rwcx0_lvl_ao, - [SM6125_VDDCX_VFL] = &cx_rwcx0_vfl, - [SM6125_VDDMX] = &mx_rwmx0_lvl, - [SM6125_VDDMX_AO] = &mx_rwmx0_lvl_ao, - [SM6125_VDDMX_VFL] = &mx_rwmx0_vfl, + [RPMPD_VDDCX] = &cx_rwcx0_lvl, + [RPMPD_VDDCX_AO] = &cx_rwcx0_lvl_ao, + [RPMPD_VDDCX_VFL] = &cx_rwcx0_vfl, + [RPMPD_VDDMX] = &mx_rwmx0_lvl, + [RPMPD_VDDMX_AO] = &mx_rwmx0_lvl_ao, + [RPMPD_VDDMX_VFL] = &mx_rwmx0_vfl, }; static const struct rpmpd_desc sm6125_desc = { From cd09e96fbac54fa962750c8cecea4d3d5e7e72ae Mon Sep 17 00:00:00 2001 From: Quynh Nguyen Date: Thu, 7 Aug 2025 17:14:35 +0200 Subject: [PATCH 01319/11391] arm64: dts: renesas: r9a08g045: Add I3C node Add the I3C node to RZ/G3S SoC DTSI. Signed-off-by: Quynh Nguyen [wsa: adapted to upstream driver, moved bus frequencies to board file] Signed-off-by: Wolfram Sang Reviewed-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250807151434.5241-7-wsa+renesas@sang-engineering.com Signed-off-by: Geert Uytterhoeven --- arch/arm64/boot/dts/renesas/r9a08g045.dtsi | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/arch/arm64/boot/dts/renesas/r9a08g045.dtsi b/arch/arm64/boot/dts/renesas/r9a08g045.dtsi index 0364f89776e6..16e6ac614417 100644 --- a/arch/arm64/boot/dts/renesas/r9a08g045.dtsi +++ b/arch/arm64/boot/dts/renesas/r9a08g045.dtsi @@ -272,6 +272,42 @@ channel@8 { }; }; + i3c: i3c@1005b000 { + compatible = "renesas,r9a08g045-i3c"; + reg = <0 0x1005b000 0 0x1000>; + clocks = <&cpg CPG_MOD R9A08G045_I3C_PCLK>, + <&cpg CPG_MOD R9A08G045_I3C_TCLK>; + clock-names = "pclk", "tclk"; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + interrupt-names = "ierr", "terr", "abort", "resp", + "cmd", "ibi", "rx", "tx", "rcv", + "st", "sp", "tend", "nack", "al", + "tmo", "wu", "exit"; + resets = <&cpg R9A08G045_I3C_PRESETN>, + <&cpg R9A08G045_I3C_TRESETN>; + reset-names = "presetn", "tresetn"; + power-domains = <&cpg>; + #address-cells = <3>; + #size-cells = <0>; + status = "disabled"; + }; + vbattb: clock-controller@1005c000 { compatible = "renesas,r9a08g045-vbattb"; reg = <0 0x1005c000 0 0x1000>; From 6fb1e70e7a918969573bc5258975456bb7165cc0 Mon Sep 17 00:00:00 2001 From: Tommaso Merciai Date: Thu, 7 Aug 2025 17:14:36 +0200 Subject: [PATCH 01320/11391] arm64: dts: renesas: r9a09g047: Add I3C node Add the I3C node to RZ/G3E SoC DTSI. Signed-off-by: Tommaso Merciai Signed-off-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250807151434.5241-8-wsa+renesas@sang-engineering.com Signed-off-by: Geert Uytterhoeven --- arch/arm64/boot/dts/renesas/r9a09g047.dtsi | 35 ++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/arch/arm64/boot/dts/renesas/r9a09g047.dtsi b/arch/arm64/boot/dts/renesas/r9a09g047.dtsi index eeccd1345f71..e5b24e46d645 100644 --- a/arch/arm64/boot/dts/renesas/r9a09g047.dtsi +++ b/arch/arm64/boot/dts/renesas/r9a09g047.dtsi @@ -492,6 +492,41 @@ scif0: serial@11c01400 { status = "disabled"; }; + i3c: i3c@12400000 { + compatible = "renesas,r9a09g047-i3c"; + reg = <0 0x12400000 0 0x10000>; + clocks = <&cpg CPG_MOD 0x91>, + <&cpg CPG_MOD 0x92>, + <&cpg CPG_MOD 0x90>; + clock-names = "pclk", "tclk", "pclkrw"; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + interrupt-names = "ierr", "terr", "abort", "resp", + "cmd", "ibi", "rx", "tx", "rcv", + "st", "sp", "tend", "nack", "al", + "tmo", "wu"; + resets = <&cpg 0x96>, <&cpg 0x97>; + reset-names = "presetn", "tresetn"; + power-domains = <&cpg>; + #address-cells = <3>; + #size-cells = <0>; + status = "disabled"; + }; + canfd: can@12440000 { compatible = "renesas,r9a09g047-canfd"; reg = <0 0x12440000 0 0x40000>; From be5d60d94b982d46a734750d93624bd85a1c7089 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Tue, 12 Aug 2025 21:03:32 +0100 Subject: [PATCH 01321/11391] arm64: dts: renesas: r9a09g077: Add DT nodes for SCI channels 1-5 The RZ/T2H SoC exposes six SCI controllers; sci0 was already present in the SoC DTSI. Add the remaining SCI nodes (sci1-sci5). Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250812200344.3253781-2-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- arch/arm64/boot/dts/renesas/r9a09g077.dtsi | 70 ++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/arch/arm64/boot/dts/renesas/r9a09g077.dtsi b/arch/arm64/boot/dts/renesas/r9a09g077.dtsi index b16fd9259d8d..8ee88b8e8f33 100644 --- a/arch/arm64/boot/dts/renesas/r9a09g077.dtsi +++ b/arch/arm64/boot/dts/renesas/r9a09g077.dtsi @@ -90,6 +90,76 @@ sci0: serial@80005000 { status = "disabled"; }; + sci1: serial@80005400 { + compatible = "renesas,r9a09g077-rsci"; + reg = <0 0x80005400 0 0x400>; + interrupts = , + , + , + ; + interrupt-names = "eri", "rxi", "txi", "tei"; + clocks = <&cpg CPG_MOD 9>, <&cpg CPG_CORE R9A09G077_CLK_PCLKM>; + clock-names = "operation", "bus"; + power-domains = <&cpg>; + status = "disabled"; + }; + + sci2: serial@80005800 { + compatible = "renesas,r9a09g077-rsci"; + reg = <0 0x80005800 0 0x400>; + interrupts = , + , + , + ; + interrupt-names = "eri", "rxi", "txi", "tei"; + clocks = <&cpg CPG_MOD 10>, <&cpg CPG_CORE R9A09G077_CLK_PCLKM>; + clock-names = "operation", "bus"; + power-domains = <&cpg>; + status = "disabled"; + }; + + sci3: serial@80005c00 { + compatible = "renesas,r9a09g077-rsci"; + reg = <0 0x80005c00 0 0x400>; + interrupts = , + , + , + ; + interrupt-names = "eri", "rxi", "txi", "tei"; + clocks = <&cpg CPG_MOD 11>, <&cpg CPG_CORE R9A09G077_CLK_PCLKM>; + clock-names = "operation", "bus"; + power-domains = <&cpg>; + status = "disabled"; + }; + + sci4: serial@80006000 { + compatible = "renesas,r9a09g077-rsci"; + reg = <0 0x80006000 0 0x400>; + interrupts = , + , + , + ; + interrupt-names = "eri", "rxi", "txi", "tei"; + clocks = <&cpg CPG_MOD 12>, <&cpg CPG_CORE R9A09G077_CLK_PCLKM>; + clock-names = "operation", "bus"; + power-domains = <&cpg>; + status = "disabled"; + }; + + sci5: serial@81005000 { + compatible = "renesas,r9a09g077-rsci"; + reg = <0 0x81005000 0 0x400>; + interrupts = , + , + , + ; + interrupt-names = "eri", "rxi", "txi", "tei"; + clocks = <&cpg CPG_MOD 600>, <&cpg CPG_CORE R9A09G077_CLK_PCLKM>; + clock-names = "operation", "bus"; + power-domains = <&cpg>; + status = "disabled"; + }; + i2c0: i2c@80088000 { compatible = "renesas,riic-r9a09g077"; reg = <0 0x80088000 0 0x400>; From 41e194978510a9910be2ed7b4d8b4edb61671a90 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Tue, 12 Aug 2025 21:03:33 +0100 Subject: [PATCH 01322/11391] arm64: dts: renesas: r9a09g087: Add DT nodes for SCI channels 1-5 The RZ/N2H SoC exposes six SCI controllers; sci0 was already present in the SoC DTSI. Add the remaining SCI nodes (sci1-sci5). Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250812200344.3253781-3-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- arch/arm64/boot/dts/renesas/r9a09g087.dtsi | 70 ++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/arch/arm64/boot/dts/renesas/r9a09g087.dtsi b/arch/arm64/boot/dts/renesas/r9a09g087.dtsi index 4da21199d22e..7dcaee711486 100644 --- a/arch/arm64/boot/dts/renesas/r9a09g087.dtsi +++ b/arch/arm64/boot/dts/renesas/r9a09g087.dtsi @@ -90,6 +90,76 @@ sci0: serial@80005000 { status = "disabled"; }; + sci1: serial@80005400 { + compatible = "renesas,r9a09g087-rsci", "renesas,r9a09g077-rsci"; + reg = <0 0x80005400 0 0x400>; + interrupts = , + , + , + ; + interrupt-names = "eri", "rxi", "txi", "tei"; + clocks = <&cpg CPG_MOD 9>, <&cpg CPG_CORE R9A09G087_CLK_PCLKM>; + clock-names = "operation", "bus"; + power-domains = <&cpg>; + status = "disabled"; + }; + + sci2: serial@80005800 { + compatible = "renesas,r9a09g087-rsci", "renesas,r9a09g077-rsci"; + reg = <0 0x80005800 0 0x400>; + interrupts = , + , + , + ; + interrupt-names = "eri", "rxi", "txi", "tei"; + clocks = <&cpg CPG_MOD 10>, <&cpg CPG_CORE R9A09G087_CLK_PCLKM>; + clock-names = "operation", "bus"; + power-domains = <&cpg>; + status = "disabled"; + }; + + sci3: serial@80005c00 { + compatible = "renesas,r9a09g087-rsci", "renesas,r9a09g077-rsci"; + reg = <0 0x80005c00 0 0x400>; + interrupts = , + , + , + ; + interrupt-names = "eri", "rxi", "txi", "tei"; + clocks = <&cpg CPG_MOD 11>, <&cpg CPG_CORE R9A09G087_CLK_PCLKM>; + clock-names = "operation", "bus"; + power-domains = <&cpg>; + status = "disabled"; + }; + + sci4: serial@80006000 { + compatible = "renesas,r9a09g087-rsci", "renesas,r9a09g077-rsci"; + reg = <0 0x80006000 0 0x400>; + interrupts = , + , + , + ; + interrupt-names = "eri", "rxi", "txi", "tei"; + clocks = <&cpg CPG_MOD 12>, <&cpg CPG_CORE R9A09G087_CLK_PCLKM>; + clock-names = "operation", "bus"; + power-domains = <&cpg>; + status = "disabled"; + }; + + sci5: serial@81005000 { + compatible = "renesas,r9a09g087-rsci", "renesas,r9a09g077-rsci"; + reg = <0 0x81005000 0 0x400>; + interrupts = , + , + , + ; + interrupt-names = "eri", "rxi", "txi", "tei"; + clocks = <&cpg CPG_MOD 600>, <&cpg CPG_CORE R9A09G087_CLK_PCLKM>; + clock-names = "operation", "bus"; + power-domains = <&cpg>; + status = "disabled"; + }; + i2c0: i2c@80088000 { compatible = "renesas,riic-r9a09g087", "renesas,riic-r9a09g077"; reg = <0 0x80088000 0 0x400>; From 98340bf91dd9e8f08f25364edd8819ee903c1b84 Mon Sep 17 00:00:00 2001 From: Thierry Bultel Date: Tue, 12 Aug 2025 21:03:34 +0100 Subject: [PATCH 01323/11391] arm64: dts: renesas: r9a09g077: Add pinctrl node Add pinctrl node to RZ/T2H ("R9A09G077") SoC DTSI. Signed-off-by: Thierry Bultel Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250812200344.3253781-4-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- arch/arm64/boot/dts/renesas/r9a09g077.dtsi | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/arm64/boot/dts/renesas/r9a09g077.dtsi b/arch/arm64/boot/dts/renesas/r9a09g077.dtsi index 8ee88b8e8f33..0929ce2db05c 100644 --- a/arch/arm64/boot/dts/renesas/r9a09g077.dtsi +++ b/arch/arm64/boot/dts/renesas/r9a09g077.dtsi @@ -216,6 +216,19 @@ cpg: clock-controller@80280000 { #power-domain-cells = <0>; }; + pinctrl: pinctrl@802c0000 { + compatible = "renesas,r9a09g077-pinctrl"; + reg = <0 0x802c0000 0 0x10000>, + <0 0x812c0000 0 0x10000>, + <0 0x802b0000 0 0x10000>; + reg-names = "nsr", "srs", "srn"; + clocks = <&cpg CPG_CORE R9A09G077_CLK_PCLKM>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl 0 0 288>; + power-domains = <&cpg>; + }; + gic: interrupt-controller@83000000 { compatible = "arm,gic-v3"; reg = <0x0 0x83000000 0 0x40000>, From 4bcff9c05b9db73aa2cfe911e948b24151858ce7 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 11 Aug 2025 17:02:00 +0200 Subject: [PATCH 01324/11391] pinctrl: stm32: use new generic GPIO chip API Convert the driver to using the new generic GPIO chip interfaces from linux/gpio/generic.h. Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/20250811-gpio-mmio-pinctrl-conv-v1-1-a84c5da2be20@linaro.org Signed-off-by: Linus Walleij --- drivers/pinctrl/stm32/pinctrl-stm32-hdp.c | 32 ++++++++++++++--------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/drivers/pinctrl/stm32/pinctrl-stm32-hdp.c b/drivers/pinctrl/stm32/pinctrl-stm32-hdp.c index e91442eb566b..dea49b9aabf2 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32-hdp.c +++ b/drivers/pinctrl/stm32/pinctrl-stm32-hdp.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -45,7 +46,7 @@ struct stm32_hdp { void __iomem *base; struct clk *clk; struct pinctrl_dev *pctl_dev; - struct gpio_chip gpio_chip; + struct gpio_generic_chip gpio_chip; u32 mux_conf; u32 gposet_conf; const char * const *func_name; @@ -603,6 +604,7 @@ MODULE_DEVICE_TABLE(of, stm32_hdp_of_match); static int stm32_hdp_probe(struct platform_device *pdev) { + struct gpio_generic_chip_config config; struct device *dev = &pdev->dev; struct stm32_hdp *hdp; u8 version; @@ -635,21 +637,25 @@ static int stm32_hdp_probe(struct platform_device *pdev) if (err) return dev_err_probe(dev, err, "Failed to enable pinctrl\n"); - hdp->gpio_chip.get_direction = stm32_hdp_gpio_get_direction; - hdp->gpio_chip.ngpio = ARRAY_SIZE(stm32_hdp_pins); - hdp->gpio_chip.can_sleep = true; - hdp->gpio_chip.names = stm32_hdp_pins_group; + hdp->gpio_chip.gc.get_direction = stm32_hdp_gpio_get_direction; + hdp->gpio_chip.gc.ngpio = ARRAY_SIZE(stm32_hdp_pins); + hdp->gpio_chip.gc.can_sleep = true; + hdp->gpio_chip.gc.names = stm32_hdp_pins_group; - err = bgpio_init(&hdp->gpio_chip, dev, 4, - hdp->base + HDP_GPOVAL, - hdp->base + HDP_GPOSET, - hdp->base + HDP_GPOCLR, - NULL, NULL, BGPIOF_NO_INPUT); + config = (typeof(config)){ + .dev = dev, + .sz = 4, + .dat = hdp->base + HDP_GPOVAL, + .set = hdp->base + HDP_GPOSET, + .clr = hdp->base + HDP_GPOCLR, + .flags = BGPIOF_NO_INPUT, + }; + + err = gpio_generic_chip_init(&hdp->gpio_chip, &config); if (err) - return dev_err_probe(dev, err, "Failed to init bgpio\n"); + return dev_err_probe(dev, err, "Failed to init the generic GPIO chip\n"); - - err = devm_gpiochip_add_data(dev, &hdp->gpio_chip, hdp); + err = devm_gpiochip_add_data(dev, &hdp->gpio_chip.gc, hdp); if (err) return dev_err_probe(dev, err, "Failed to add gpiochip\n"); From 658cd189d793d56c1f80841da6a8b5d2d7c72aa3 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 11 Aug 2025 17:02:01 +0200 Subject: [PATCH 01325/11391] pinctrl: equilibrium: use new generic GPIO chip API Convert the driver to using the new generic GPIO chip interfaces from linux/gpio/generic.h. Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/20250811-gpio-mmio-pinctrl-conv-v1-2-a84c5da2be20@linaro.org Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-equilibrium.c | 26 ++++++++++++++++---------- drivers/pinctrl/pinctrl-equilibrium.h | 2 +- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/drivers/pinctrl/pinctrl-equilibrium.c b/drivers/pinctrl/pinctrl-equilibrium.c index fce804d42e7d..210044185679 100644 --- a/drivers/pinctrl/pinctrl-equilibrium.c +++ b/drivers/pinctrl/pinctrl-equilibrium.c @@ -2,6 +2,7 @@ /* Copyright (C) 2019 Intel Corporation */ #include +#include #include #include #include @@ -179,7 +180,7 @@ static int gpiochip_setup(struct device *dev, struct eqbr_gpio_ctrl *gctrl) struct gpio_irq_chip *girq; struct gpio_chip *gc; - gc = &gctrl->chip; + gc = &gctrl->chip.gc; gc->label = gctrl->name; gc->fwnode = gctrl->fwnode; gc->request = gpiochip_generic_request; @@ -191,7 +192,7 @@ static int gpiochip_setup(struct device *dev, struct eqbr_gpio_ctrl *gctrl) return 0; } - girq = &gctrl->chip.irq; + girq = &gctrl->chip.gc.irq; gpio_irq_chip_set_chip(girq, &eqbr_irq_chip); girq->parent_handler = eqbr_irq_handler; girq->num_parents = 1; @@ -208,6 +209,7 @@ static int gpiochip_setup(struct device *dev, struct eqbr_gpio_ctrl *gctrl) static int gpiolib_reg(struct eqbr_pinctrl_drv_data *drvdata) { + struct gpio_generic_chip_config config; struct device *dev = drvdata->dev; struct eqbr_gpio_ctrl *gctrl; struct device_node *np; @@ -239,12 +241,16 @@ static int gpiolib_reg(struct eqbr_pinctrl_drv_data *drvdata) } raw_spin_lock_init(&gctrl->lock); - ret = bgpio_init(&gctrl->chip, dev, gctrl->bank->nr_pins / 8, - gctrl->membase + GPIO_IN, - gctrl->membase + GPIO_OUTSET, - gctrl->membase + GPIO_OUTCLR, - gctrl->membase + GPIO_DIR, - NULL, 0); + config = (typeof(config)){ + .dev = dev, + .sz = gctrl->bank->nr_pins / 8, + .dat = gctrl->membase + GPIO_IN, + .set = gctrl->membase + GPIO_OUTSET, + .clr = gctrl->membase + GPIO_OUTCLR, + .dirout = gctrl->membase + GPIO_DIR, + }; + + ret = gpio_generic_chip_init(&gctrl->chip, &config); if (ret) { dev_err(dev, "unable to init generic GPIO\n"); return ret; @@ -254,7 +260,7 @@ static int gpiolib_reg(struct eqbr_pinctrl_drv_data *drvdata) if (ret) return ret; - ret = devm_gpiochip_add_data(dev, &gctrl->chip, gctrl); + ret = devm_gpiochip_add_data(dev, &gctrl->chip.gc, gctrl); if (ret) return ret; } @@ -499,7 +505,7 @@ static int eqbr_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, bank->pin_base, pin); return -ENODEV; } - gc = &gctrl->chip; + gc = &gctrl->chip.gc; gc->direction_output(gc, offset, 0); continue; default: diff --git a/drivers/pinctrl/pinctrl-equilibrium.h b/drivers/pinctrl/pinctrl-equilibrium.h index b4d149bde39d..b56124d7fe91 100644 --- a/drivers/pinctrl/pinctrl-equilibrium.h +++ b/drivers/pinctrl/pinctrl-equilibrium.h @@ -96,7 +96,7 @@ struct fwnode_handle; * @lock: spin lock to protect gpio register write. */ struct eqbr_gpio_ctrl { - struct gpio_chip chip; + struct gpio_generic_chip chip; struct fwnode_handle *fwnode; struct eqbr_pin_bank *bank; void __iomem *membase; From d2e9afca3a40eb4fe39ef0654e89cc19b2e0a939 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 11 Aug 2025 17:02:02 +0200 Subject: [PATCH 01326/11391] pinctrl: npcm8xx: use new generic GPIO chip API Convert the driver to using the new generic GPIO chip interfaces from linux/gpio/generic.h. Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/20250811-gpio-mmio-pinctrl-conv-v1-3-a84c5da2be20@linaro.org Signed-off-by: Linus Walleij --- drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c | 154 +++++++++++----------- 1 file changed, 78 insertions(+), 76 deletions(-) diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c index 3c3b9d8d3681..0f155a685bba 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c +++ b/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -90,7 +91,7 @@ struct debounce_time { }; struct npcm8xx_gpio { - struct gpio_chip gc; + struct gpio_generic_chip chip; void __iomem *base; struct debounce_time debounce; int irqbase; @@ -115,24 +116,20 @@ struct npcm8xx_pinctrl { }; /* GPIO handling in the pinctrl driver */ -static void npcm_gpio_set(struct gpio_chip *gc, void __iomem *reg, +static void npcm_gpio_set(struct gpio_generic_chip *chip, void __iomem *reg, unsigned int pinmask) { - unsigned long flags; + guard(gpio_generic_lock_irqsave)(chip); - raw_spin_lock_irqsave(&gc->bgpio_lock, flags); iowrite32(ioread32(reg) | pinmask, reg); - raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); } -static void npcm_gpio_clr(struct gpio_chip *gc, void __iomem *reg, +static void npcm_gpio_clr(struct gpio_generic_chip *chip, void __iomem *reg, unsigned int pinmask) { - unsigned long flags; + guard(gpio_generic_lock_irqsave)(chip); - raw_spin_lock_irqsave(&gc->bgpio_lock, flags); iowrite32(ioread32(reg) & ~pinmask, reg); - raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); } static void npcmgpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) @@ -233,32 +230,32 @@ static int npcmgpio_set_irq_type(struct irq_data *d, unsigned int type) switch (type) { case IRQ_TYPE_EDGE_RISING: - npcm_gpio_clr(&bank->gc, bank->base + NPCM8XX_GP_N_EVBE, gpio); - npcm_gpio_clr(&bank->gc, bank->base + NPCM8XX_GP_N_POL, gpio); + npcm_gpio_clr(&bank->chip, bank->base + NPCM8XX_GP_N_EVBE, gpio); + npcm_gpio_clr(&bank->chip, bank->base + NPCM8XX_GP_N_POL, gpio); break; case IRQ_TYPE_EDGE_FALLING: - npcm_gpio_clr(&bank->gc, bank->base + NPCM8XX_GP_N_EVBE, gpio); - npcm_gpio_set(&bank->gc, bank->base + NPCM8XX_GP_N_POL, gpio); + npcm_gpio_clr(&bank->chip, bank->base + NPCM8XX_GP_N_EVBE, gpio); + npcm_gpio_set(&bank->chip, bank->base + NPCM8XX_GP_N_POL, gpio); break; case IRQ_TYPE_EDGE_BOTH: - npcm_gpio_clr(&bank->gc, bank->base + NPCM8XX_GP_N_POL, gpio); - npcm_gpio_set(&bank->gc, bank->base + NPCM8XX_GP_N_EVBE, gpio); + npcm_gpio_clr(&bank->chip, bank->base + NPCM8XX_GP_N_POL, gpio); + npcm_gpio_set(&bank->chip, bank->base + NPCM8XX_GP_N_EVBE, gpio); break; case IRQ_TYPE_LEVEL_LOW: - npcm_gpio_set(&bank->gc, bank->base + NPCM8XX_GP_N_POL, gpio); + npcm_gpio_set(&bank->chip, bank->base + NPCM8XX_GP_N_POL, gpio); break; case IRQ_TYPE_LEVEL_HIGH: - npcm_gpio_clr(&bank->gc, bank->base + NPCM8XX_GP_N_POL, gpio); + npcm_gpio_clr(&bank->chip, bank->base + NPCM8XX_GP_N_POL, gpio); break; default: return -EINVAL; } if (type & IRQ_TYPE_LEVEL_MASK) { - npcm_gpio_clr(&bank->gc, bank->base + NPCM8XX_GP_N_EVTYP, gpio); + npcm_gpio_clr(&bank->chip, bank->base + NPCM8XX_GP_N_EVTYP, gpio); irq_set_handler_locked(d, handle_level_irq); } else if (type & IRQ_TYPE_EDGE_BOTH) { - npcm_gpio_set(&bank->gc, bank->base + NPCM8XX_GP_N_EVTYP, gpio); + npcm_gpio_set(&bank->chip, bank->base + NPCM8XX_GP_N_EVTYP, gpio); irq_set_handler_locked(d, handle_edge_irq); } @@ -1842,7 +1839,7 @@ static void npcm8xx_setfunc(struct regmap *gcr_regmap, const unsigned int *pin, static int npcm8xx_get_slew_rate(struct npcm8xx_gpio *bank, struct regmap *gcr_regmap, unsigned int pin) { - int gpio = pin % bank->gc.ngpio; + int gpio = pin % bank->chip.gc.ngpio; unsigned long pinmask = BIT(gpio); u32 val; @@ -1862,15 +1859,15 @@ static int npcm8xx_set_slew_rate(struct npcm8xx_gpio *bank, int arg) { void __iomem *OSRC_Offset = bank->base + NPCM8XX_GP_N_OSRC; - int gpio = BIT(pin % bank->gc.ngpio); + int gpio = BIT(pin % bank->chip.gc.ngpio); if (pincfg[pin].flag & SLEW) { switch (arg) { case 0: - npcm_gpio_clr(&bank->gc, OSRC_Offset, gpio); + npcm_gpio_clr(&bank->chip, OSRC_Offset, gpio); return 0; case 1: - npcm_gpio_set(&bank->gc, OSRC_Offset, gpio); + npcm_gpio_set(&bank->chip, OSRC_Offset, gpio); return 0; default: return -EINVAL; @@ -1902,7 +1899,7 @@ static int npcm8xx_get_drive_strength(struct pinctrl_dev *pctldev, struct npcm8xx_pinctrl *npcm = pinctrl_dev_get_drvdata(pctldev); struct npcm8xx_gpio *bank = &npcm->gpio_bank[pin / NPCM8XX_GPIO_PER_BANK]; - int gpio = pin % bank->gc.ngpio; + int gpio = pin % bank->chip.gc.ngpio; unsigned long pinmask = BIT(gpio); int flg, val; u32 ds = 0; @@ -1913,7 +1910,7 @@ static int npcm8xx_get_drive_strength(struct pinctrl_dev *pctldev, val = ioread32(bank->base + NPCM8XX_GP_N_ODSC) & pinmask; ds = val ? DSHI(flg) : DSLO(flg); - dev_dbg(bank->gc.parent, "pin %d strength %d = %d\n", pin, val, ds); + dev_dbg(bank->chip.gc.parent, "pin %d strength %d = %d\n", pin, val, ds); return ds; } @@ -1923,15 +1920,15 @@ static int npcm8xx_set_drive_strength(struct npcm8xx_pinctrl *npcm, { struct npcm8xx_gpio *bank = &npcm->gpio_bank[pin / NPCM8XX_GPIO_PER_BANK]; - int gpio = BIT(pin % bank->gc.ngpio); + int gpio = BIT(pin % bank->chip.gc.ngpio); int v; v = pincfg[pin].flag & DRIVE_STRENGTH_MASK; if (DSLO(v) == nval) - npcm_gpio_clr(&bank->gc, bank->base + NPCM8XX_GP_N_ODSC, gpio); + npcm_gpio_clr(&bank->chip, bank->base + NPCM8XX_GP_N_ODSC, gpio); else if (DSHI(v) == nval) - npcm_gpio_set(&bank->gc, bank->base + NPCM8XX_GP_N_ODSC, gpio); + npcm_gpio_set(&bank->chip, bank->base + NPCM8XX_GP_N_ODSC, gpio); else return -ENOTSUPP; @@ -2054,7 +2051,7 @@ static int npcm_gpio_set_direction(struct pinctrl_dev *pctldev, struct npcm8xx_pinctrl *npcm = pinctrl_dev_get_drvdata(pctldev); struct npcm8xx_gpio *bank = &npcm->gpio_bank[offset / NPCM8XX_GPIO_PER_BANK]; - int gpio = BIT(offset % bank->gc.ngpio); + int gpio = BIT(offset % bank->chip.gc.ngpio); if (input) iowrite32(gpio, bank->base + NPCM8XX_GP_N_OEC); @@ -2085,7 +2082,7 @@ static int debounce_timing_setting(struct npcm8xx_gpio *bank, u32 gpio, if (bank->debounce.set_val[i]) { if (bank->debounce.nanosec_val[i] == nanosecs) { debounce_select = i << gpio_debounce; - npcm_gpio_set(&bank->gc, DBNCS_offset, + npcm_gpio_set(&bank->chip, DBNCS_offset, debounce_select); break; } @@ -2093,7 +2090,7 @@ static int debounce_timing_setting(struct npcm8xx_gpio *bank, u32 gpio, bank->debounce.set_val[i] = true; bank->debounce.nanosec_val[i] = nanosecs; debounce_select = i << gpio_debounce; - npcm_gpio_set(&bank->gc, DBNCS_offset, debounce_select); + npcm_gpio_set(&bank->chip, DBNCS_offset, debounce_select); switch (nanosecs) { case 1 ... 1040: iowrite32(0, bank->base + NPCM8XX_GP_N_DBNCP0 + (i * 4)); @@ -2145,21 +2142,21 @@ static int npcm_set_debounce(struct npcm8xx_pinctrl *npcm, unsigned int pin, { struct npcm8xx_gpio *bank = &npcm->gpio_bank[pin / NPCM8XX_GPIO_PER_BANK]; - int gpio = BIT(pin % bank->gc.ngpio); + int gpio = BIT(pin % bank->chip.gc.ngpio); int ret; if (nanosecs) { - ret = debounce_timing_setting(bank, pin % bank->gc.ngpio, + ret = debounce_timing_setting(bank, pin % bank->chip.gc.ngpio, nanosecs); if (ret) dev_err(npcm->dev, "Pin %d, All four debounce timing values are used, please use one of exist debounce values\n", pin); else - npcm_gpio_set(&bank->gc, bank->base + NPCM8XX_GP_N_DBNC, + npcm_gpio_set(&bank->chip, bank->base + NPCM8XX_GP_N_DBNC, gpio); return ret; } - npcm_gpio_clr(&bank->gc, bank->base + NPCM8XX_GP_N_DBNC, gpio); + npcm_gpio_clr(&bank->chip, bank->base + NPCM8XX_GP_N_DBNC, gpio); return 0; } @@ -2172,7 +2169,7 @@ static int npcm8xx_config_get(struct pinctrl_dev *pctldev, unsigned int pin, struct npcm8xx_pinctrl *npcm = pinctrl_dev_get_drvdata(pctldev); struct npcm8xx_gpio *bank = &npcm->gpio_bank[pin / NPCM8XX_GPIO_PER_BANK]; - int gpio = pin % bank->gc.ngpio; + int gpio = pin % bank->chip.gc.ngpio; unsigned long pinmask = BIT(gpio); u32 ie, oe, pu, pd; int rc = 0; @@ -2235,34 +2232,34 @@ static int npcm8xx_config_set_one(struct npcm8xx_pinctrl *npcm, struct npcm8xx_gpio *bank = &npcm->gpio_bank[pin / NPCM8XX_GPIO_PER_BANK]; u32 arg = pinconf_to_config_argument(config); - int gpio = BIT(pin % bank->gc.ngpio); + int gpio = BIT(pin % bank->chip.gc.ngpio); switch (param) { case PIN_CONFIG_BIAS_DISABLE: - npcm_gpio_clr(&bank->gc, bank->base + NPCM8XX_GP_N_PU, gpio); - npcm_gpio_clr(&bank->gc, bank->base + NPCM8XX_GP_N_PD, gpio); + npcm_gpio_clr(&bank->chip, bank->base + NPCM8XX_GP_N_PU, gpio); + npcm_gpio_clr(&bank->chip, bank->base + NPCM8XX_GP_N_PD, gpio); break; case PIN_CONFIG_BIAS_PULL_DOWN: - npcm_gpio_clr(&bank->gc, bank->base + NPCM8XX_GP_N_PU, gpio); - npcm_gpio_set(&bank->gc, bank->base + NPCM8XX_GP_N_PD, gpio); + npcm_gpio_clr(&bank->chip, bank->base + NPCM8XX_GP_N_PU, gpio); + npcm_gpio_set(&bank->chip, bank->base + NPCM8XX_GP_N_PD, gpio); break; case PIN_CONFIG_BIAS_PULL_UP: - npcm_gpio_clr(&bank->gc, bank->base + NPCM8XX_GP_N_PD, gpio); - npcm_gpio_set(&bank->gc, bank->base + NPCM8XX_GP_N_PU, gpio); + npcm_gpio_clr(&bank->chip, bank->base + NPCM8XX_GP_N_PD, gpio); + npcm_gpio_set(&bank->chip, bank->base + NPCM8XX_GP_N_PU, gpio); break; case PIN_CONFIG_INPUT_ENABLE: iowrite32(gpio, bank->base + NPCM8XX_GP_N_OEC); - bank->direction_input(&bank->gc, pin % bank->gc.ngpio); + bank->direction_input(&bank->chip.gc, pin % bank->chip.gc.ngpio); break; case PIN_CONFIG_OUTPUT: - bank->direction_output(&bank->gc, pin % bank->gc.ngpio, arg); + bank->direction_output(&bank->chip.gc, pin % bank->chip.gc.ngpio, arg); iowrite32(gpio, bank->base + NPCM8XX_GP_N_OES); break; case PIN_CONFIG_DRIVE_PUSH_PULL: - npcm_gpio_clr(&bank->gc, bank->base + NPCM8XX_GP_N_OTYP, gpio); + npcm_gpio_clr(&bank->chip, bank->base + NPCM8XX_GP_N_OTYP, gpio); break; case PIN_CONFIG_DRIVE_OPEN_DRAIN: - npcm_gpio_set(&bank->gc, bank->base + NPCM8XX_GP_N_OTYP, gpio); + npcm_gpio_set(&bank->chip, bank->base + NPCM8XX_GP_N_OTYP, gpio); break; case PIN_CONFIG_INPUT_DEBOUNCE: return npcm_set_debounce(npcm, pin, arg * 1000); @@ -2313,13 +2310,14 @@ static int npcmgpio_add_pin_ranges(struct gpio_chip *chip) { struct npcm8xx_gpio *bank = gpiochip_get_data(chip); - return gpiochip_add_pin_range(&bank->gc, dev_name(chip->parent), - bank->pinctrl_id, bank->gc.base, - bank->gc.ngpio); + return gpiochip_add_pin_range(&bank->chip.gc, dev_name(chip->parent), + bank->pinctrl_id, bank->chip.gc.base, + bank->chip.gc.ngpio); } static int npcm8xx_gpio_fw(struct npcm8xx_pinctrl *pctrl) { + struct gpio_generic_chip_config config; struct fwnode_reference_args args; struct device *dev = pctrl->dev; struct fwnode_handle *child; @@ -2331,15 +2329,19 @@ static int npcm8xx_gpio_fw(struct npcm8xx_pinctrl *pctrl) if (!pctrl->gpio_bank[id].base) return dev_err_probe(dev, -ENXIO, "fwnode_iomap id %d failed\n", id); - ret = bgpio_init(&pctrl->gpio_bank[id].gc, dev, 4, - pctrl->gpio_bank[id].base + NPCM8XX_GP_N_DIN, - pctrl->gpio_bank[id].base + NPCM8XX_GP_N_DOUT, - NULL, - NULL, - pctrl->gpio_bank[id].base + NPCM8XX_GP_N_IEM, - BGPIOF_READ_OUTPUT_REG_SET); + config = (typeof(config)){ + .dev = dev, + .sz = 4, + .dat = pctrl->gpio_bank[id].base + NPCM8XX_GP_N_DIN, + .set = pctrl->gpio_bank[id].base + NPCM8XX_GP_N_DOUT, + .dirin = pctrl->gpio_bank[id].base + NPCM8XX_GP_N_IEM, + .flags = BGPIOF_READ_OUTPUT_REG_SET, + }; + + ret = gpio_generic_chip_init(&pctrl->gpio_bank[id].chip, &config); if (ret) - return dev_err_probe(dev, ret, "bgpio_init() failed\n"); + return dev_err_probe(dev, ret, + "failed to initialize the generic GPIO chip\n"); ret = fwnode_property_get_reference_args(child, "gpio-ranges", NULL, 3, 0, &args); if (ret < 0) @@ -2353,26 +2355,26 @@ static int npcm8xx_gpio_fw(struct npcm8xx_pinctrl *pctrl) pctrl->gpio_bank[id].irq_chip = npcmgpio_irqchip; pctrl->gpio_bank[id].irqbase = id * NPCM8XX_GPIO_PER_BANK; pctrl->gpio_bank[id].pinctrl_id = args.args[0]; - pctrl->gpio_bank[id].gc.base = -1; - pctrl->gpio_bank[id].gc.ngpio = args.args[2]; - pctrl->gpio_bank[id].gc.owner = THIS_MODULE; - pctrl->gpio_bank[id].gc.parent = dev; - pctrl->gpio_bank[id].gc.fwnode = child; - pctrl->gpio_bank[id].gc.label = devm_kasprintf(dev, GFP_KERNEL, "%pfw", child); - if (pctrl->gpio_bank[id].gc.label == NULL) + pctrl->gpio_bank[id].chip.gc.base = -1; + pctrl->gpio_bank[id].chip.gc.ngpio = args.args[2]; + pctrl->gpio_bank[id].chip.gc.owner = THIS_MODULE; + pctrl->gpio_bank[id].chip.gc.parent = dev; + pctrl->gpio_bank[id].chip.gc.fwnode = child; + pctrl->gpio_bank[id].chip.gc.label = devm_kasprintf(dev, GFP_KERNEL, "%pfw", child); + if (pctrl->gpio_bank[id].chip.gc.label == NULL) return -ENOMEM; - pctrl->gpio_bank[id].gc.dbg_show = npcmgpio_dbg_show; - pctrl->gpio_bank[id].direction_input = pctrl->gpio_bank[id].gc.direction_input; - pctrl->gpio_bank[id].gc.direction_input = npcmgpio_direction_input; - pctrl->gpio_bank[id].direction_output = pctrl->gpio_bank[id].gc.direction_output; - pctrl->gpio_bank[id].gc.direction_output = npcmgpio_direction_output; - pctrl->gpio_bank[id].request = pctrl->gpio_bank[id].gc.request; - pctrl->gpio_bank[id].gc.request = npcmgpio_gpio_request; - pctrl->gpio_bank[id].gc.free = pinctrl_gpio_free; + pctrl->gpio_bank[id].chip.gc.dbg_show = npcmgpio_dbg_show; + pctrl->gpio_bank[id].direction_input = pctrl->gpio_bank[id].chip.gc.direction_input; + pctrl->gpio_bank[id].chip.gc.direction_input = npcmgpio_direction_input; + pctrl->gpio_bank[id].direction_output = pctrl->gpio_bank[id].chip.gc.direction_output; + pctrl->gpio_bank[id].chip.gc.direction_output = npcmgpio_direction_output; + pctrl->gpio_bank[id].request = pctrl->gpio_bank[id].chip.gc.request; + pctrl->gpio_bank[id].chip.gc.request = npcmgpio_gpio_request; + pctrl->gpio_bank[id].chip.gc.free = pinctrl_gpio_free; for (i = 0 ; i < NPCM8XX_DEBOUNCE_MAX ; i++) pctrl->gpio_bank[id].debounce.set_val[i] = false; - pctrl->gpio_bank[id].gc.add_pin_ranges = npcmgpio_add_pin_ranges; + pctrl->gpio_bank[id].chip.gc.add_pin_ranges = npcmgpio_add_pin_ranges; id++; } @@ -2387,7 +2389,7 @@ static int npcm8xx_gpio_register(struct npcm8xx_pinctrl *pctrl) for (id = 0 ; id < pctrl->bank_num ; id++) { struct gpio_irq_chip *girq; - girq = &pctrl->gpio_bank[id].gc.irq; + girq = &pctrl->gpio_bank[id].chip.gc.irq; girq->chip = &pctrl->gpio_bank[id].irq_chip; girq->parent_handler = npcmgpio_irq_handler; girq->num_parents = 1; @@ -2401,7 +2403,7 @@ static int npcm8xx_gpio_register(struct npcm8xx_pinctrl *pctrl) girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_level_irq; ret = devm_gpiochip_add_data(pctrl->dev, - &pctrl->gpio_bank[id].gc, + &pctrl->gpio_bank[id].chip.gc, &pctrl->gpio_bank[id]); if (ret) return dev_err_probe(pctrl->dev, ret, "Failed to add GPIO chip %u\n", id); From 9e546aa9d5e032cd89529cd377631a60b0dfe35a Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 11 Aug 2025 17:02:03 +0200 Subject: [PATCH 01327/11391] pinctrl: npcm7xx: use new generic GPIO chip API Convert the driver to using the new generic GPIO chip interfaces from linux/gpio/generic.h. Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/20250811-gpio-mmio-pinctrl-conv-v1-4-a84c5da2be20@linaro.org Signed-off-by: Linus Walleij --- drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c | 181 +++++++++++----------- 1 file changed, 90 insertions(+), 91 deletions(-) diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c index b8872d8f5930..c2ca71ebb973 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c +++ b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -77,7 +78,7 @@ /* Structure for register banks */ struct npcm7xx_gpio { void __iomem *base; - struct gpio_chip gc; + struct gpio_generic_chip chip; int irqbase; int irq; u32 pinctrl_id; @@ -99,32 +100,26 @@ struct npcm7xx_pinctrl { }; /* GPIO handling in the pinctrl driver */ -static void npcm_gpio_set(struct gpio_chip *gc, void __iomem *reg, +static void npcm_gpio_set(struct gpio_generic_chip *chip, void __iomem *reg, unsigned int pinmask) { - unsigned long flags; unsigned long val; - raw_spin_lock_irqsave(&gc->bgpio_lock, flags); + guard(gpio_generic_lock_irqsave)(chip); val = ioread32(reg) | pinmask; iowrite32(val, reg); - - raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); } -static void npcm_gpio_clr(struct gpio_chip *gc, void __iomem *reg, +static void npcm_gpio_clr(struct gpio_generic_chip *chip, void __iomem *reg, unsigned int pinmask) { - unsigned long flags; unsigned long val; - raw_spin_lock_irqsave(&gc->bgpio_lock, flags); + guard(gpio_generic_lock_irqsave)(chip); val = ioread32(reg) & ~pinmask; iowrite32(val, reg); - - raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); } static void npcmgpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) @@ -132,9 +127,9 @@ static void npcmgpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) struct npcm7xx_gpio *bank = gpiochip_get_data(chip); seq_printf(s, "-- module %d [gpio%d - %d]\n", - bank->gc.base / bank->gc.ngpio, - bank->gc.base, - bank->gc.base + bank->gc.ngpio); + bank->chip.gc.base / bank->chip.gc.ngpio, + bank->chip.gc.base, + bank->chip.gc.base + bank->chip.gc.ngpio); seq_printf(s, "DIN :%.8x DOUT:%.8x IE :%.8x OE :%.8x\n", ioread32(bank->base + NPCM7XX_GP_N_DIN), ioread32(bank->base + NPCM7XX_GP_N_DOUT), @@ -220,7 +215,7 @@ static void npcmgpio_irq_handler(struct irq_desc *desc) chained_irq_enter(chip, desc); sts = ioread32(bank->base + NPCM7XX_GP_N_EVST); en = ioread32(bank->base + NPCM7XX_GP_N_EVEN); - dev_dbg(bank->gc.parent, "==> got irq sts %.8lx %.8lx\n", sts, + dev_dbg(bank->chip.gc.parent, "==> got irq sts %.8lx %.8lx\n", sts, en); sts &= en; @@ -235,42 +230,42 @@ static int npcmgpio_set_irq_type(struct irq_data *d, unsigned int type) struct npcm7xx_gpio *bank = gpiochip_get_data(gc); unsigned int gpio = BIT(irqd_to_hwirq(d)); - dev_dbg(bank->gc.parent, "setirqtype: %u.%u = %u\n", gpio, + dev_dbg(bank->chip.gc.parent, "setirqtype: %u.%u = %u\n", gpio, d->irq, type); switch (type) { case IRQ_TYPE_EDGE_RISING: - dev_dbg(bank->gc.parent, "edge.rising\n"); - npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_EVBE, gpio); - npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_POL, gpio); + dev_dbg(bank->chip.gc.parent, "edge.rising\n"); + npcm_gpio_clr(&bank->chip, bank->base + NPCM7XX_GP_N_EVBE, gpio); + npcm_gpio_clr(&bank->chip, bank->base + NPCM7XX_GP_N_POL, gpio); break; case IRQ_TYPE_EDGE_FALLING: - dev_dbg(bank->gc.parent, "edge.falling\n"); - npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_EVBE, gpio); - npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_POL, gpio); + dev_dbg(bank->chip.gc.parent, "edge.falling\n"); + npcm_gpio_clr(&bank->chip, bank->base + NPCM7XX_GP_N_EVBE, gpio); + npcm_gpio_set(&bank->chip, bank->base + NPCM7XX_GP_N_POL, gpio); break; case IRQ_TYPE_EDGE_BOTH: - dev_dbg(bank->gc.parent, "edge.both\n"); - npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_EVBE, gpio); + dev_dbg(bank->chip.gc.parent, "edge.both\n"); + npcm_gpio_set(&bank->chip, bank->base + NPCM7XX_GP_N_EVBE, gpio); break; case IRQ_TYPE_LEVEL_LOW: - dev_dbg(bank->gc.parent, "level.low\n"); - npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_POL, gpio); + dev_dbg(bank->chip.gc.parent, "level.low\n"); + npcm_gpio_set(&bank->chip, bank->base + NPCM7XX_GP_N_POL, gpio); break; case IRQ_TYPE_LEVEL_HIGH: - dev_dbg(bank->gc.parent, "level.high\n"); - npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_POL, gpio); + dev_dbg(bank->chip.gc.parent, "level.high\n"); + npcm_gpio_clr(&bank->chip, bank->base + NPCM7XX_GP_N_POL, gpio); break; default: - dev_dbg(bank->gc.parent, "invalid irq type\n"); + dev_dbg(bank->chip.gc.parent, "invalid irq type\n"); return -EINVAL; } if (type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { - npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_EVTYP, gpio); + npcm_gpio_clr(&bank->chip, bank->base + NPCM7XX_GP_N_EVTYP, gpio); irq_set_handler_locked(d, handle_level_irq); } else if (type & (IRQ_TYPE_EDGE_BOTH | IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) { - npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_EVTYP, gpio); + npcm_gpio_set(&bank->chip, bank->base + NPCM7XX_GP_N_EVTYP, gpio); irq_set_handler_locked(d, handle_edge_irq); } @@ -283,7 +278,7 @@ static void npcmgpio_irq_ack(struct irq_data *d) struct npcm7xx_gpio *bank = gpiochip_get_data(gc); unsigned int gpio = irqd_to_hwirq(d); - dev_dbg(bank->gc.parent, "irq_ack: %u.%u\n", gpio, d->irq); + dev_dbg(bank->chip.gc.parent, "irq_ack: %u.%u\n", gpio, d->irq); iowrite32(BIT(gpio), bank->base + NPCM7XX_GP_N_EVST); } @@ -295,7 +290,7 @@ static void npcmgpio_irq_mask(struct irq_data *d) unsigned int gpio = irqd_to_hwirq(d); /* Clear events */ - dev_dbg(bank->gc.parent, "irq_mask: %u.%u\n", gpio, d->irq); + dev_dbg(bank->chip.gc.parent, "irq_mask: %u.%u\n", gpio, d->irq); iowrite32(BIT(gpio), bank->base + NPCM7XX_GP_N_EVENC); gpiochip_disable_irq(gc, gpio); } @@ -309,7 +304,7 @@ static void npcmgpio_irq_unmask(struct irq_data *d) /* Enable events */ gpiochip_enable_irq(gc, gpio); - dev_dbg(bank->gc.parent, "irq_unmask: %u.%u\n", gpio, d->irq); + dev_dbg(bank->chip.gc.parent, "irq_unmask: %u.%u\n", gpio, d->irq); iowrite32(BIT(gpio), bank->base + NPCM7XX_GP_N_EVENS); } @@ -1423,7 +1418,7 @@ static int npcm7xx_get_slew_rate(struct npcm7xx_gpio *bank, struct regmap *gcr_regmap, unsigned int pin) { u32 val; - int gpio = (pin % bank->gc.ngpio); + int gpio = (pin % bank->chip.gc.ngpio); unsigned long pinmask = BIT(gpio); if (pincfg[pin].flag & SLEW) @@ -1443,16 +1438,16 @@ static int npcm7xx_set_slew_rate(struct npcm7xx_gpio *bank, struct regmap *gcr_regmap, unsigned int pin, int arg) { - int gpio = BIT(pin % bank->gc.ngpio); + int gpio = BIT(pin % bank->chip.gc.ngpio); if (pincfg[pin].flag & SLEW) { switch (arg) { case 0: - npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_OSRC, + npcm_gpio_clr(&bank->chip, bank->base + NPCM7XX_GP_N_OSRC, gpio); return 0; case 1: - npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_OSRC, + npcm_gpio_set(&bank->chip, bank->base + NPCM7XX_GP_N_OSRC, gpio); return 0; default: @@ -1485,7 +1480,7 @@ static int npcm7xx_get_drive_strength(struct pinctrl_dev *pctldev, struct npcm7xx_pinctrl *npcm = pinctrl_dev_get_drvdata(pctldev); struct npcm7xx_gpio *bank = &npcm->gpio_bank[pin / NPCM7XX_GPIO_PER_BANK]; - int gpio = (pin % bank->gc.ngpio); + int gpio = (pin % bank->chip.gc.ngpio); unsigned long pinmask = BIT(gpio); u32 ds = 0; int flg, val; @@ -1496,7 +1491,7 @@ static int npcm7xx_get_drive_strength(struct pinctrl_dev *pctldev, val = ioread32(bank->base + NPCM7XX_GP_N_ODSC) & pinmask; ds = val ? DSHI(flg) : DSLO(flg); - dev_dbg(bank->gc.parent, + dev_dbg(bank->chip.gc.parent, "pin %d strength %d = %d\n", pin, val, ds); return ds; } @@ -1511,20 +1506,20 @@ static int npcm7xx_set_drive_strength(struct npcm7xx_pinctrl *npcm, int v; struct npcm7xx_gpio *bank = &npcm->gpio_bank[pin / NPCM7XX_GPIO_PER_BANK]; - int gpio = BIT(pin % bank->gc.ngpio); + int gpio = BIT(pin % bank->chip.gc.ngpio); v = (pincfg[pin].flag & DRIVE_STRENGTH_MASK); if (!nval || !v) return -ENOTSUPP; if (DSLO(v) == nval) { - dev_dbg(bank->gc.parent, + dev_dbg(bank->chip.gc.parent, "setting pin %d to low strength [%d]\n", pin, nval); - npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_ODSC, gpio); + npcm_gpio_clr(&bank->chip, bank->base + NPCM7XX_GP_N_ODSC, gpio); return 0; } else if (DSHI(v) == nval) { - dev_dbg(bank->gc.parent, + dev_dbg(bank->chip.gc.parent, "setting pin %d to high strength [%d]\n", pin, nval); - npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_ODSC, gpio); + npcm_gpio_set(&bank->chip, bank->base + NPCM7XX_GP_N_ODSC, gpio); return 0; } @@ -1657,9 +1652,9 @@ static int npcm_gpio_set_direction(struct pinctrl_dev *pctldev, struct npcm7xx_pinctrl *npcm = pinctrl_dev_get_drvdata(pctldev); struct npcm7xx_gpio *bank = &npcm->gpio_bank[offset / NPCM7XX_GPIO_PER_BANK]; - int gpio = BIT(offset % bank->gc.ngpio); + int gpio = BIT(offset % bank->chip.gc.ngpio); - dev_dbg(bank->gc.parent, "GPIO Set Direction: %d = %d\n", offset, + dev_dbg(bank->chip.gc.parent, "GPIO Set Direction: %d = %d\n", offset, input); if (input) iowrite32(gpio, bank->base + NPCM7XX_GP_N_OEC); @@ -1687,7 +1682,7 @@ static int npcm7xx_config_get(struct pinctrl_dev *pctldev, unsigned int pin, struct npcm7xx_pinctrl *npcm = pinctrl_dev_get_drvdata(pctldev); struct npcm7xx_gpio *bank = &npcm->gpio_bank[pin / NPCM7XX_GPIO_PER_BANK]; - int gpio = (pin % bank->gc.ngpio); + int gpio = (pin % bank->chip.gc.ngpio); unsigned long pinmask = BIT(gpio); u32 ie, oe, pu, pd; int rc = 0; @@ -1750,38 +1745,38 @@ static int npcm7xx_config_set_one(struct npcm7xx_pinctrl *npcm, u16 arg = pinconf_to_config_argument(config); struct npcm7xx_gpio *bank = &npcm->gpio_bank[pin / NPCM7XX_GPIO_PER_BANK]; - int gpio = BIT(pin % bank->gc.ngpio); + int gpio = BIT(pin % bank->chip.gc.ngpio); - dev_dbg(bank->gc.parent, "param=%d %d[GPIO]\n", param, pin); + dev_dbg(bank->chip.gc.parent, "param=%d %d[GPIO]\n", param, pin); switch (param) { case PIN_CONFIG_BIAS_DISABLE: - npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_PU, gpio); - npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_PD, gpio); + npcm_gpio_clr(&bank->chip, bank->base + NPCM7XX_GP_N_PU, gpio); + npcm_gpio_clr(&bank->chip, bank->base + NPCM7XX_GP_N_PD, gpio); break; case PIN_CONFIG_BIAS_PULL_DOWN: - npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_PU, gpio); - npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_PD, gpio); + npcm_gpio_clr(&bank->chip, bank->base + NPCM7XX_GP_N_PU, gpio); + npcm_gpio_set(&bank->chip, bank->base + NPCM7XX_GP_N_PD, gpio); break; case PIN_CONFIG_BIAS_PULL_UP: - npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_PD, gpio); - npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_PU, gpio); + npcm_gpio_clr(&bank->chip, bank->base + NPCM7XX_GP_N_PD, gpio); + npcm_gpio_set(&bank->chip, bank->base + NPCM7XX_GP_N_PU, gpio); break; case PIN_CONFIG_INPUT_ENABLE: iowrite32(gpio, bank->base + NPCM7XX_GP_N_OEC); - bank->direction_input(&bank->gc, pin % bank->gc.ngpio); + bank->direction_input(&bank->chip.gc, pin % bank->chip.gc.ngpio); break; case PIN_CONFIG_OUTPUT: - bank->direction_output(&bank->gc, pin % bank->gc.ngpio, arg); + bank->direction_output(&bank->chip.gc, pin % bank->chip.gc.ngpio, arg); iowrite32(gpio, bank->base + NPCM7XX_GP_N_OES); break; case PIN_CONFIG_DRIVE_PUSH_PULL: - npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_OTYP, gpio); + npcm_gpio_clr(&bank->chip, bank->base + NPCM7XX_GP_N_OTYP, gpio); break; case PIN_CONFIG_DRIVE_OPEN_DRAIN: - npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_OTYP, gpio); + npcm_gpio_set(&bank->chip, bank->base + NPCM7XX_GP_N_OTYP, gpio); break; case PIN_CONFIG_INPUT_DEBOUNCE: - npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_DBNC, gpio); + npcm_gpio_set(&bank->chip, bank->base + NPCM7XX_GP_N_DBNC, gpio); break; case PIN_CONFIG_SLEW_RATE: return npcm7xx_set_slew_rate(bank, npcm->gcr_regmap, pin, arg); @@ -1829,6 +1824,7 @@ static const struct pinctrl_desc npcm7xx_pinctrl_desc = { static int npcm7xx_gpio_of(struct npcm7xx_pinctrl *pctrl) { + struct gpio_generic_chip_config config; int ret = -ENXIO; struct device *dev = pctrl->dev; struct fwnode_reference_args args; @@ -1840,15 +1836,18 @@ static int npcm7xx_gpio_of(struct npcm7xx_pinctrl *pctrl) if (!pctrl->gpio_bank[id].base) return -EINVAL; - ret = bgpio_init(&pctrl->gpio_bank[id].gc, dev, 4, - pctrl->gpio_bank[id].base + NPCM7XX_GP_N_DIN, - pctrl->gpio_bank[id].base + NPCM7XX_GP_N_DOUT, - NULL, - NULL, - pctrl->gpio_bank[id].base + NPCM7XX_GP_N_IEM, - BGPIOF_READ_OUTPUT_REG_SET); + config = (typeof(config)){ + .dev = dev, + .sz = 4, + .dat = pctrl->gpio_bank[id].base + NPCM7XX_GP_N_DIN, + .set = pctrl->gpio_bank[id].base + NPCM7XX_GP_N_DOUT, + .dirin = pctrl->gpio_bank[id].base + NPCM7XX_GP_N_IEM, + .flags = BGPIOF_READ_OUTPUT_REG_SET, + }; + + ret = gpio_generic_chip_init(&pctrl->gpio_bank[id].chip, &config); if (ret) { - dev_err(dev, "bgpio_init() failed\n"); + dev_err(dev, "failed to initialize the generic GPIO chip\n"); return ret; } @@ -1866,23 +1865,23 @@ static int npcm7xx_gpio_of(struct npcm7xx_pinctrl *pctrl) pctrl->gpio_bank[id].irq = ret; pctrl->gpio_bank[id].irqbase = id * NPCM7XX_GPIO_PER_BANK; pctrl->gpio_bank[id].pinctrl_id = args.args[0]; - pctrl->gpio_bank[id].gc.base = args.args[1]; - pctrl->gpio_bank[id].gc.ngpio = args.args[2]; - pctrl->gpio_bank[id].gc.owner = THIS_MODULE; - pctrl->gpio_bank[id].gc.parent = dev; - pctrl->gpio_bank[id].gc.fwnode = child; - pctrl->gpio_bank[id].gc.label = devm_kasprintf(dev, GFP_KERNEL, "%pfw", child); - if (pctrl->gpio_bank[id].gc.label == NULL) + pctrl->gpio_bank[id].chip.gc.base = args.args[1]; + pctrl->gpio_bank[id].chip.gc.ngpio = args.args[2]; + pctrl->gpio_bank[id].chip.gc.owner = THIS_MODULE; + pctrl->gpio_bank[id].chip.gc.parent = dev; + pctrl->gpio_bank[id].chip.gc.fwnode = child; + pctrl->gpio_bank[id].chip.gc.label = devm_kasprintf(dev, GFP_KERNEL, "%pfw", child); + if (pctrl->gpio_bank[id].chip.gc.label == NULL) return -ENOMEM; - pctrl->gpio_bank[id].gc.dbg_show = npcmgpio_dbg_show; - pctrl->gpio_bank[id].direction_input = pctrl->gpio_bank[id].gc.direction_input; - pctrl->gpio_bank[id].gc.direction_input = npcmgpio_direction_input; - pctrl->gpio_bank[id].direction_output = pctrl->gpio_bank[id].gc.direction_output; - pctrl->gpio_bank[id].gc.direction_output = npcmgpio_direction_output; - pctrl->gpio_bank[id].request = pctrl->gpio_bank[id].gc.request; - pctrl->gpio_bank[id].gc.request = npcmgpio_gpio_request; - pctrl->gpio_bank[id].gc.free = pinctrl_gpio_free; + pctrl->gpio_bank[id].chip.gc.dbg_show = npcmgpio_dbg_show; + pctrl->gpio_bank[id].direction_input = pctrl->gpio_bank[id].chip.gc.direction_input; + pctrl->gpio_bank[id].chip.gc.direction_input = npcmgpio_direction_input; + pctrl->gpio_bank[id].direction_output = pctrl->gpio_bank[id].chip.gc.direction_output; + pctrl->gpio_bank[id].chip.gc.direction_output = npcmgpio_direction_output; + pctrl->gpio_bank[id].request = pctrl->gpio_bank[id].chip.gc.request; + pctrl->gpio_bank[id].chip.gc.request = npcmgpio_gpio_request; + pctrl->gpio_bank[id].chip.gc.free = pinctrl_gpio_free; id++; } @@ -1897,7 +1896,7 @@ static int npcm7xx_gpio_register(struct npcm7xx_pinctrl *pctrl) for (id = 0 ; id < pctrl->bank_num ; id++) { struct gpio_irq_chip *girq; - girq = &pctrl->gpio_bank[id].gc.irq; + girq = &pctrl->gpio_bank[id].chip.gc.irq; gpio_irq_chip_set_chip(girq, &npcmgpio_irqchip); girq->parent_handler = npcmgpio_irq_handler; girq->num_parents = 1; @@ -1912,21 +1911,21 @@ static int npcm7xx_gpio_register(struct npcm7xx_pinctrl *pctrl) girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_level_irq; ret = devm_gpiochip_add_data(pctrl->dev, - &pctrl->gpio_bank[id].gc, + &pctrl->gpio_bank[id].chip.gc, &pctrl->gpio_bank[id]); if (ret) { dev_err(pctrl->dev, "Failed to add GPIO chip %u\n", id); goto err_register; } - ret = gpiochip_add_pin_range(&pctrl->gpio_bank[id].gc, + ret = gpiochip_add_pin_range(&pctrl->gpio_bank[id].chip.gc, dev_name(pctrl->dev), pctrl->gpio_bank[id].pinctrl_id, - pctrl->gpio_bank[id].gc.base, - pctrl->gpio_bank[id].gc.ngpio); + pctrl->gpio_bank[id].chip.gc.base, + pctrl->gpio_bank[id].chip.gc.ngpio); if (ret < 0) { dev_err(pctrl->dev, "Failed to add GPIO bank %u\n", id); - gpiochip_remove(&pctrl->gpio_bank[id].gc); + gpiochip_remove(&pctrl->gpio_bank[id].chip.gc); goto err_register; } } @@ -1935,7 +1934,7 @@ static int npcm7xx_gpio_register(struct npcm7xx_pinctrl *pctrl) err_register: for (; id > 0; id--) - gpiochip_remove(&pctrl->gpio_bank[id - 1].gc); + gpiochip_remove(&pctrl->gpio_bank[id - 1].chip.gc); return ret; } From 051f7141673aa112a9c4119e1b5e0d0f580951f3 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 11 Aug 2025 17:02:04 +0200 Subject: [PATCH 01328/11391] pinctrl: wpcm450: use new generic GPIO chip API Convert the driver to using the new generic GPIO chip interfaces from linux/gpio/generic.h. Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/20250811-gpio-mmio-pinctrl-conv-v1-5-a84c5da2be20@linaro.org Signed-off-by: Linus Walleij --- drivers/pinctrl/nuvoton/pinctrl-wpcm450.c | 44 ++++++++++++++--------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/drivers/pinctrl/nuvoton/pinctrl-wpcm450.c b/drivers/pinctrl/nuvoton/pinctrl-wpcm450.c index 8d8314ba0e4c..4dd8a3daa83e 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-wpcm450.c +++ b/drivers/pinctrl/nuvoton/pinctrl-wpcm450.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -47,7 +48,7 @@ struct wpcm450_pinctrl; struct wpcm450_bank; struct wpcm450_gpio { - struct gpio_chip gc; + struct gpio_generic_chip chip; struct wpcm450_pinctrl *pctrl; const struct wpcm450_bank *bank; }; @@ -184,11 +185,12 @@ static void wpcm450_gpio_irq_unmask(struct irq_data *d) } /* - * This is an implementation of the gpio_chip->get() function, for use in - * wpcm450_gpio_fix_evpol. Unfortunately, we can't use the bgpio-provided - * implementation there, because it would require taking gpio_chip->bgpio_lock, - * which is a spin lock, but wpcm450_gpio_fix_evpol must work in contexts where - * a raw spin lock is held. + * FIXME: This is an implementation of the gpio_chip->get() function, for use + * in wpcm450_gpio_fix_evpol(). It was implemented back when gpio-mmio used a + * regular spinlock internally, while wpcm450_gpio_fix_evpol() needed to work + * in contexts with a raw spinlock held. Since then, the gpio generic chip has + * been switched to using a raw spinlock so this should be converted to using + * the locking interfaces provided in linux/gpio/gneneric.h. */ static int wpcm450_gpio_get(struct wpcm450_gpio *gpio, int offset) { @@ -329,7 +331,7 @@ static void wpcm450_gpio_irqhandler(struct irq_desc *desc) for_each_set_bit(bit, &pending, 32) { int offset = wpcm450_irq_bitnum_to_gpio(gpio, bit); - generic_handle_domain_irq(gpio->gc.irq.domain, offset); + generic_handle_domain_irq(gpio->chip.gc.irq.domain, offset); } chained_irq_exit(chip, desc); } @@ -1012,7 +1014,7 @@ static int wpcm450_gpio_add_pin_ranges(struct gpio_chip *chip) struct wpcm450_gpio *gpio = gpiochip_get_data(chip); const struct wpcm450_bank *bank = gpio->bank; - return gpiochip_add_pin_range(&gpio->gc, dev_name(gpio->pctrl->dev), + return gpiochip_add_pin_range(&gpio->chip.gc, dev_name(gpio->pctrl->dev), 0, bank->base, bank->length); } @@ -1029,6 +1031,7 @@ static int wpcm450_gpio_register(struct platform_device *pdev, "Resource fail for GPIO controller\n"); for_each_gpiochip_node(dev, child) { + struct gpio_generic_chip_config config; void __iomem *dat = NULL; void __iomem *set = NULL; void __iomem *dirout = NULL; @@ -1060,17 +1063,26 @@ static int wpcm450_gpio_register(struct platform_device *pdev, } else { flags = BGPIOF_NO_OUTPUT; } - ret = bgpio_init(&gpio->gc, dev, 4, - dat, set, NULL, dirout, NULL, flags); + + config = (typeof(config)){ + .dev = dev, + .sz = 4, + .dat = dat, + .set = set, + .dirout = dirout, + .flags = flags, + }; + + ret = gpio_generic_chip_init(&gpio->chip, &config); if (ret < 0) return dev_err_probe(dev, ret, "GPIO initialization failed\n"); - gpio->gc.ngpio = bank->length; - gpio->gc.set_config = wpcm450_gpio_set_config; - gpio->gc.fwnode = child; - gpio->gc.add_pin_ranges = wpcm450_gpio_add_pin_ranges; + gpio->chip.gc.ngpio = bank->length; + gpio->chip.gc.set_config = wpcm450_gpio_set_config; + gpio->chip.gc.fwnode = child; + gpio->chip.gc.add_pin_ranges = wpcm450_gpio_add_pin_ranges; - girq = &gpio->gc.irq; + girq = &gpio->chip.gc.irq; gpio_irq_chip_set_chip(girq, &wpcm450_gpio_irqchip); girq->parent_handler = wpcm450_gpio_irqhandler; girq->parents = devm_kcalloc(dev, WPCM450_NUM_GPIO_IRQS, @@ -1094,7 +1106,7 @@ static int wpcm450_gpio_register(struct platform_device *pdev, girq->num_parents++; } - ret = devm_gpiochip_add_data(dev, &gpio->gc, gpio); + ret = devm_gpiochip_add_data(dev, &gpio->chip.gc, gpio); if (ret) return dev_err_probe(dev, ret, "Failed to add GPIO chip\n"); } From 6f21672c42fc432d69d8fd51e5d8cea145d5be5b Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Tue, 12 Aug 2025 21:03:39 +0100 Subject: [PATCH 01329/11391] arm64: dts: renesas: r9a09g077m44-rzt2h-evk: Enable I2C0 and I2C1 support Enable I2C0 and I2C1 on the RZ/T2H evaluation board. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250812200344.3253781-9-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- .../dts/renesas/r9a09g077m44-rzt2h-evk.dts | 36 +++++++++++++++++++ .../dts/renesas/rzt2h-n2h-evk-common.dtsi | 2 ++ 2 files changed, 38 insertions(+) diff --git a/arch/arm64/boot/dts/renesas/r9a09g077m44-rzt2h-evk.dts b/arch/arm64/boot/dts/renesas/r9a09g077m44-rzt2h-evk.dts index 486584fefead..51ea295b3241 100644 --- a/arch/arm64/boot/dts/renesas/r9a09g077m44-rzt2h-evk.dts +++ b/arch/arm64/boot/dts/renesas/r9a09g077m44-rzt2h-evk.dts @@ -7,6 +7,8 @@ /dts-v1/; +#include + #include "r9a09g077m44.dtsi" #include "rzt2h-n2h-evk-common.dtsi" @@ -14,3 +16,37 @@ / { model = "Renesas RZ/T2H EVK Board based on r9a09g077m44"; compatible = "renesas,rzt2h-evk", "renesas,r9a09g077m44", "renesas,r9a09g077"; }; + +&i2c0 { + pinctrl-0 = <&i2c0_pins>; + pinctrl-names = "default"; + clock-frequency = <400000>; + status = "okay"; +}; + +&i2c1 { + pinctrl-0 = <&i2c1_pins>; + pinctrl-names = "default"; + clock-frequency = <400000>; + status = "okay"; +}; + +&pinctrl { + /* + * I2C0 Pin Configuration: + * ------------------------ + * Signal | Pin | SW6 + * -------|---------|-------------- + * SCL | P23_3 | 7: ON, 8: OFF + * SDA | P23_4 | 9: ON, 10: OFF + */ + i2c0_pins: i2c0-pins { + pinmux = , + ; + }; + + i2c1_pins: i2c1-pins { + pinmux = , /* SDA */ + ; /* SCL */ + }; +}; diff --git a/arch/arm64/boot/dts/renesas/rzt2h-n2h-evk-common.dtsi b/arch/arm64/boot/dts/renesas/rzt2h-n2h-evk-common.dtsi index 5f17996bcd6b..263509cc3dc4 100644 --- a/arch/arm64/boot/dts/renesas/rzt2h-n2h-evk-common.dtsi +++ b/arch/arm64/boot/dts/renesas/rzt2h-n2h-evk-common.dtsi @@ -7,6 +7,8 @@ / { aliases { + i2c0 = &i2c0; + i2c1 = &i2c1; serial0 = &sci0; }; From 91d7789fd016e0616913313b3306b83f8a608489 Mon Sep 17 00:00:00 2001 From: Joy Zou Date: Wed, 6 Aug 2025 19:41:10 +0800 Subject: [PATCH 01330/11391] dt-bindings: soc: imx-blk-ctrl: add i.MX91 blk-ctrl compatible Add new compatible string "fsl,imx91-media-blk-ctrl" for i.MX91, which has different input clocks compared to i.MX93. Update the clock-names list and handle it in the if-else branch accordingly. Keep the same restriction for the existed compatible strings. Reviewed-by: Rob Herring (Arm) Reviewed-by: Frank Li Signed-off-by: Joy Zou Link: https://lore.kernel.org/r/20250806114119.1948624-3-joy.zou@nxp.com Signed-off-by: Ulf Hansson --- .../soc/imx/fsl,imx93-media-blk-ctrl.yaml | 59 +++++++++++++++---- 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml index b3554e7f9e76..34aea58094e5 100644 --- a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml +++ b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml @@ -18,7 +18,9 @@ description: properties: compatible: items: - - const: fsl,imx93-media-blk-ctrl + - enum: + - fsl,imx91-media-blk-ctrl + - fsl,imx93-media-blk-ctrl - const: syscon reg: @@ -31,21 +33,54 @@ properties: maxItems: 1 clocks: + minItems: 8 maxItems: 10 clock-names: - items: - - const: apb - - const: axi - - const: nic - - const: disp - - const: cam - - const: pxp - - const: lcdif - - const: isi - - const: csi - - const: dsi + minItems: 8 + maxItems: 10 +allOf: + - if: + properties: + compatible: + contains: + const: fsl,imx91-media-blk-ctrl + then: + properties: + clocks: + maxItems: 8 + clock-names: + items: + - const: apb + - const: axi + - const: nic + - const: disp + - const: cam + - const: lcdif + - const: isi + - const: csi + - if: + properties: + compatible: + contains: + const: fsl,imx93-media-blk-ctrl + then: + properties: + clocks: + minItems: 10 + clock-names: + items: + - const: apb + - const: axi + - const: nic + - const: disp + - const: cam + - const: pxp + - const: lcdif + - const: isi + - const: csi + - const: dsi required: - compatible - reg From 88f9d89871014559557ecc9b9ae9c9c0821a6e96 Mon Sep 17 00:00:00 2001 From: Joy Zou Date: Wed, 6 Aug 2025 19:41:17 +0800 Subject: [PATCH 01331/11391] pmdomain: imx93-blk-ctrl: use ARRAY_SIZE() instead of hardcode number Optimize i.MX93 num_clks hardcode with ARRAY_SIZE(). Reviewed-by: Frank Li Signed-off-by: Joy Zou Link: https://lore.kernel.org/r/20250806114119.1948624-10-joy.zou@nxp.com Signed-off-by: Ulf Hansson --- drivers/pmdomain/imx/imx93-blk-ctrl.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/pmdomain/imx/imx93-blk-ctrl.c b/drivers/pmdomain/imx/imx93-blk-ctrl.c index 0e2ba8ec55d7..1dcb84593e01 100644 --- a/drivers/pmdomain/imx/imx93-blk-ctrl.c +++ b/drivers/pmdomain/imx/imx93-blk-ctrl.c @@ -418,11 +418,15 @@ static const struct regmap_access_table imx93_media_blk_ctl_access_table = { .n_yes_ranges = ARRAY_SIZE(imx93_media_blk_ctl_yes_ranges), }; +static const char * const media_blk_clk_names[] = { + "axi", "apb", "nic" +}; + static const struct imx93_blk_ctrl_data imx93_media_blk_ctl_dev_data = { .domains = imx93_media_blk_ctl_domain_data, .num_domains = ARRAY_SIZE(imx93_media_blk_ctl_domain_data), - .clk_names = (const char *[]){ "axi", "apb", "nic", }, - .num_clks = 3, + .clk_names = media_blk_clk_names, + .num_clks = ARRAY_SIZE(media_blk_clk_names), .reg_access_table = &imx93_media_blk_ctl_access_table, }; From a83a7a7b205018a436cbdbd9676cfaaf01773f47 Mon Sep 17 00:00:00 2001 From: Joy Zou Date: Wed, 6 Aug 2025 19:41:18 +0800 Subject: [PATCH 01332/11391] pmdomain: imx93-blk-ctrl: mask DSI and PXP PD domain register on i.MX91 The i.MX91 is derived from i.MX93, but there is no DSI and PXP in i.MX91, Add skip_mask in struct imx93_blk_ctrl_data, then skip DSI and PXP for i.MX91 Soc. Signed-off-by: Joy Zou Reviewed-by: Frank Li Link: https://lore.kernel.org/r/20250806114119.1948624-11-joy.zou@nxp.com Signed-off-by: Ulf Hansson --- drivers/pmdomain/imx/imx93-blk-ctrl.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/pmdomain/imx/imx93-blk-ctrl.c b/drivers/pmdomain/imx/imx93-blk-ctrl.c index 1dcb84593e01..e094fe5a42bf 100644 --- a/drivers/pmdomain/imx/imx93-blk-ctrl.c +++ b/drivers/pmdomain/imx/imx93-blk-ctrl.c @@ -86,6 +86,7 @@ struct imx93_blk_ctrl_domain { struct imx93_blk_ctrl_data { const struct imx93_blk_ctrl_domain_data *domains; + u32 skip_mask; int num_domains; const char * const *clk_names; int num_clks; @@ -250,6 +251,8 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev) int j; domain->data = data; + if (bc_data->skip_mask & BIT(i)) + continue; for (j = 0; j < data->num_clks; j++) domain->clks[j].id = data->clk_names[j]; @@ -422,6 +425,15 @@ static const char * const media_blk_clk_names[] = { "axi", "apb", "nic" }; +static const struct imx93_blk_ctrl_data imx91_media_blk_ctl_dev_data = { + .domains = imx93_media_blk_ctl_domain_data, + .skip_mask = BIT(IMX93_MEDIABLK_PD_MIPI_DSI) | BIT(IMX93_MEDIABLK_PD_PXP), + .num_domains = ARRAY_SIZE(imx93_media_blk_ctl_domain_data), + .clk_names = media_blk_clk_names, + .num_clks = ARRAY_SIZE(media_blk_clk_names), + .reg_access_table = &imx93_media_blk_ctl_access_table, +}; + static const struct imx93_blk_ctrl_data imx93_media_blk_ctl_dev_data = { .domains = imx93_media_blk_ctl_domain_data, .num_domains = ARRAY_SIZE(imx93_media_blk_ctl_domain_data), @@ -432,6 +444,9 @@ static const struct imx93_blk_ctrl_data imx93_media_blk_ctl_dev_data = { static const struct of_device_id imx93_blk_ctrl_of_match[] = { { + .compatible = "fsl,imx91-media-blk-ctrl", + .data = &imx91_media_blk_ctl_dev_data + }, { .compatible = "fsl,imx93-media-blk-ctrl", .data = &imx93_media_blk_ctl_dev_data }, { From 87660a84bb2897344a368aabe990789cdced5954 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 13 Aug 2025 18:15:00 +0200 Subject: [PATCH 01333/11391] pmdomain: 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-15-wsa+renesas@sang-engineering.com Signed-off-by: Ulf Hansson --- drivers/pmdomain/imx/gpc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/pmdomain/imx/gpc.c b/drivers/pmdomain/imx/gpc.c index f18c7e6e75dd..33991f3c6b55 100644 --- a/drivers/pmdomain/imx/gpc.c +++ b/drivers/pmdomain/imx/gpc.c @@ -343,7 +343,6 @@ static const struct regmap_config imx_gpc_regmap_config = { .rd_table = &access_table, .wr_table = &access_table, .max_register = 0x2ac, - .fast_io = true, }; static struct generic_pm_domain *imx_gpc_onecell_domains[] = { From d8f3ae7b38fea546e64a6cfcdc7d061c85f086e2 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 13 Aug 2025 15:04:24 +0200 Subject: [PATCH 01334/11391] pmdomain: renesas: rcar-sysc: Make rcar_sysc_onecell_np __initdata rcar_sysc_onecell_np() is only used by functions marked __init, so it can be freed when init memory is freed. Fixes: c5ae5a0c6112 ("pmdomain: renesas: rcar-sysc: Add genpd OF provider at postcore_initcall") Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/e20a848ff952924f8f58c335f9a0242cb2565921.1755090234.git.geert+renesas@glider.be Signed-off-by: Ulf Hansson --- drivers/pmdomain/renesas/rcar-sysc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pmdomain/renesas/rcar-sysc.c b/drivers/pmdomain/renesas/rcar-sysc.c index 4b310c1d35fa..2d4161170c63 100644 --- a/drivers/pmdomain/renesas/rcar-sysc.c +++ b/drivers/pmdomain/renesas/rcar-sysc.c @@ -342,7 +342,7 @@ struct rcar_pm_domains { }; static struct genpd_onecell_data *rcar_sysc_onecell_data; -static struct device_node *rcar_sysc_onecell_np; +static struct device_node *rcar_sysc_onecell_np __initdata = NULL; static int __init rcar_sysc_pd_init(void) { From 89934dbf169e358b57c2b394bb51a57d3f259dc0 Mon Sep 17 00:00:00 2001 From: Vineeth Karumanchi Date: Thu, 14 Aug 2025 12:40:57 +0530 Subject: [PATCH 01335/11391] net: macb: Add TAPRIO traffic scheduling support Implement Time-Aware Traffic Scheduling (TAPRIO) offload support for Cadence MACB/GEM ethernet controllers to enable IEEE 802.1Qbv compliant time-sensitive networking (TSN) capabilities. Key Features: 1. Enhanced Scheduled Traffic (ENST) Register Management - Per-queue ENST registers: ENST_START_TIME, ENST_ON_TIME, ENST_OFF_TIME - Centralized control via ENST_CONTROL for gate enable/disable - Infrastructure enhancements: * Extended macb_queue structure with ENST timing control registers * Mapped ENST register offsets into queue management framework * Introduced macb_queue_enst_config for per-entry TC configuration - Timing conversion utility: * enst_ns_to_hw_units(): Converts nanoseconds to hardware units * Timing values are programmed as hardware units based on link speed * Conversion formula: time_bytes = time_ns / divisor * Speed-specific divisors: 1Gbps=8, 100Mbps=80, 10Mbps=800 - Hardware limit utility: * enst_max_hw_interval(): Returns max interval for given speed 2. TAPRIO Configuration via "tc qdisc replace" - macb_taprio_setup_replace(): Configures TAPRIO hardware offload - Parameter validation checks performed: * TC entry limit validation against available hardware queues * Base time non-negativity enforcement * Speed-adaptive timing constraint verification * Cycle time vs. total gate time consistency checks * Single-queue gate mask enforcement per scheduling entry - Programming sequence: * GEM doesn't support changing ENST registers if ENST is enabled, hence disable ENST before programming * Atomic timing register configuration (START_TIME, ON_TIME, OFF_TIME) * Enable queues via ENST_CONTROL 3. TAPRIO Cleanup via "tc qdisc destroy" - macb_taprio_destroy(): Safely removes TAPRIO configuration - Restores default queue behavior - Cleanup steps: * Reset TC state * Disable ENST * Clear timing registers * Ensure atomic updates with locking 4. Traffic Control Offload Infrastructure - macb_setup_taprio(): TAPRIO command dispatcher * Verifies hardware support * Handles runtime suspend state - macb_setup_tc(): TC_SETUP_QDISC_TAPRIO entry point - Supports REPLACE and DESTROY operations Tested on Xilinx Versal platforms with QBV-capable MACB controllers. Signed-off-by: Vineeth Karumanchi Link: https://patch.msgid.link/20250814071058.3062453-2-vineeth.karumanchi@amd.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/cadence/macb.h | 66 +++++++ drivers/net/ethernet/cadence/macb_main.c | 223 +++++++++++++++++++++++ 2 files changed, 289 insertions(+) diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index c9a5c8beb2fa..d1a98b45c92c 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -184,6 +184,13 @@ #define GEM_DCFG8 0x029C /* Design Config 8 */ #define GEM_DCFG10 0x02A4 /* Design Config 10 */ #define GEM_DCFG12 0x02AC /* Design Config 12 */ +#define GEM_ENST_START_TIME_Q0 0x0800 /* ENST Q0 start time */ +#define GEM_ENST_START_TIME_Q1 0x0804 /* ENST Q1 start time */ +#define GEM_ENST_ON_TIME_Q0 0x0820 /* ENST Q0 on time */ +#define GEM_ENST_ON_TIME_Q1 0x0824 /* ENST Q1 on time */ +#define GEM_ENST_OFF_TIME_Q0 0x0840 /* ENST Q0 off time */ +#define GEM_ENST_OFF_TIME_Q1 0x0844 /* ENST Q1 off time */ +#define GEM_ENST_CONTROL 0x0880 /* ENST control register */ #define GEM_USX_CONTROL 0x0A80 /* High speed PCS control register */ #define GEM_USX_STATUS 0x0A88 /* High speed PCS status register */ @@ -221,6 +228,13 @@ #define GEM_IDR(hw_q) (0x0620 + ((hw_q) << 2)) #define GEM_IMR(hw_q) (0x0640 + ((hw_q) << 2)) +#define GEM_ENST_START_TIME(hw_q) (0x0800 + ((hw_q) << 2)) +#define GEM_ENST_ON_TIME(hw_q) (0x0820 + ((hw_q) << 2)) +#define GEM_ENST_OFF_TIME(hw_q) (0x0840 + ((hw_q) << 2)) + +/* Bitfields in ENST_CONTROL */ +#define GEM_ENST_DISABLE_QUEUE_OFFSET 16 + /* Bitfields in NCR */ #define MACB_LB_OFFSET 0 /* reserved */ #define MACB_LB_SIZE 1 @@ -554,6 +568,23 @@ #define GEM_HIGH_SPEED_OFFSET 26 #define GEM_HIGH_SPEED_SIZE 1 +/* Bitfields in ENST_START_TIME_Qx. */ +#define GEM_START_TIME_SEC_OFFSET 30 +#define GEM_START_TIME_SEC_SIZE 2 +#define GEM_START_TIME_NSEC_OFFSET 0 +#define GEM_START_TIME_NSEC_SIZE 30 + +/* Bitfields in ENST_ON_TIME_Qx. */ +#define GEM_ON_TIME_OFFSET 0 +#define GEM_ON_TIME_SIZE 17 + +/* Bitfields in ENST_OFF_TIME_Qx. */ +#define GEM_OFF_TIME_OFFSET 0 +#define GEM_OFF_TIME_SIZE 17 + +/* Hardware ENST timing registers granularity */ +#define ENST_TIME_GRANULARITY_NS 8 + /* Bitfields in USX_CONTROL. */ #define GEM_USX_CTRL_SPEED_OFFSET 14 #define GEM_USX_CTRL_SPEED_SIZE 3 @@ -1219,6 +1250,11 @@ struct macb_queue { unsigned int RBQP; unsigned int RBQPH; + /* ENST register offsets for this queue */ + unsigned int ENST_START_TIME; + unsigned int ENST_ON_TIME; + unsigned int ENST_OFF_TIME; + /* Lock to protect tx_head and tx_tail */ spinlock_t tx_ptr_lock; unsigned int tx_head, tx_tail; @@ -1397,6 +1433,19 @@ static inline bool gem_has_ptp(struct macb *bp) return IS_ENABLED(CONFIG_MACB_USE_HWSTAMP) && (bp->caps & MACB_CAPS_GEM_HAS_PTP); } +/* ENST Helper functions */ +static inline u64 enst_ns_to_hw_units(size_t ns, u32 speed_mbps) +{ + return DIV_ROUND_UP((ns) * (speed_mbps), + (ENST_TIME_GRANULARITY_NS * 1000)); +} + +static inline u64 enst_max_hw_interval(u32 speed_mbps) +{ + return DIV_ROUND_UP(GENMASK(GEM_ON_TIME_SIZE - 1, 0) * + ENST_TIME_GRANULARITY_NS * 1000, (speed_mbps)); +} + /** * struct macb_platform_data - platform data for MACB Ethernet used for PCI registration * @pclk: platform clock @@ -1407,4 +1456,21 @@ struct macb_platform_data { struct clk *hclk; }; +/** + * struct macb_queue_enst_config - Configuration for Enhanced Scheduled Traffic + * @start_time_mask: Bitmask representing the start time for the queue + * @on_time_bytes: "on" time nsec expressed in bytes + * @off_time_bytes: "off" time nsec expressed in bytes + * @queue_id: Identifier for the queue + * + * This structure holds the configuration parameters for an ENST queue, + * used to control time-based transmission scheduling in the MACB driver. + */ +struct macb_queue_enst_config { + u32 start_time_mask; + u32 on_time_bytes; + u32 off_time_bytes; + u8 queue_id; +}; + #endif /* _MACB_H */ diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index ce55a1f59b50..a42304eb2bf8 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "macb.h" /* This structure is only used for MACB on SiFive FU540 devices */ @@ -4084,6 +4085,223 @@ static void macb_restore_features(struct macb *bp) macb_set_rxflow_feature(bp, features); } +static int macb_taprio_setup_replace(struct net_device *ndev, + struct tc_taprio_qopt_offload *conf) +{ + u64 total_on_time = 0, start_time_sec = 0, start_time = conf->base_time; + u32 configured_queues = 0, speed = 0, start_time_nsec; + struct macb_queue_enst_config *enst_queue; + struct tc_taprio_sched_entry *entry; + struct macb *bp = netdev_priv(ndev); + struct ethtool_link_ksettings kset; + struct macb_queue *queue; + size_t i; + int err; + + if (conf->num_entries > bp->num_queues) { + netdev_err(ndev, "Too many TAPRIO entries: %zu > %d queues\n", + conf->num_entries, bp->num_queues); + return -EINVAL; + } + + if (start_time < 0) { + netdev_err(ndev, "Invalid base_time: must be 0 or positive, got %lld\n", + conf->base_time); + return -ERANGE; + } + + /* Get the current link speed */ + err = phylink_ethtool_ksettings_get(bp->phylink, &kset); + if (unlikely(err)) { + netdev_err(ndev, "Failed to get link settings: %d\n", err); + return err; + } + + speed = kset.base.speed; + if (unlikely(speed <= 0)) { + netdev_err(ndev, "Invalid speed: %d\n", speed); + return -EINVAL; + } + + enst_queue = kcalloc(conf->num_entries, sizeof(*enst_queue), GFP_KERNEL); + if (unlikely(!enst_queue)) + return -ENOMEM; + + /* Pre-validate all entries before making any hardware changes */ + for (i = 0; i < conf->num_entries; i++) { + entry = &conf->entries[i]; + + if (entry->command != TC_TAPRIO_CMD_SET_GATES) { + netdev_err(ndev, "Entry %zu: unsupported command %d\n", + i, entry->command); + err = -EOPNOTSUPP; + goto cleanup; + } + + /* Validate gate_mask: must be nonzero, single queue, and within range */ + if (!is_power_of_2(entry->gate_mask)) { + netdev_err(ndev, "Entry %zu: gate_mask 0x%x is not a power of 2 (only one queue per entry allowed)\n", + i, entry->gate_mask); + err = -EINVAL; + goto cleanup; + } + + /* gate_mask must not select queues outside the valid queue_mask */ + if (entry->gate_mask & ~bp->queue_mask) { + netdev_err(ndev, "Entry %zu: gate_mask 0x%x exceeds queue range (max_queues=%d)\n", + i, entry->gate_mask, bp->num_queues); + err = -EINVAL; + goto cleanup; + } + + /* Check for start time limits */ + start_time_sec = start_time; + start_time_nsec = do_div(start_time_sec, NSEC_PER_SEC); + if (start_time_sec > GENMASK(GEM_START_TIME_SEC_SIZE - 1, 0)) { + netdev_err(ndev, "Entry %zu: Start time %llu s exceeds hardware limit\n", + i, start_time_sec); + err = -ERANGE; + goto cleanup; + } + + /* Check for on time limit */ + if (entry->interval > enst_max_hw_interval(speed)) { + netdev_err(ndev, "Entry %zu: interval %u ns exceeds hardware limit %llu ns\n", + i, entry->interval, enst_max_hw_interval(speed)); + err = -ERANGE; + goto cleanup; + } + + /* Check for off time limit*/ + if ((conf->cycle_time - entry->interval) > enst_max_hw_interval(speed)) { + netdev_err(ndev, "Entry %zu: off_time %llu ns exceeds hardware limit %llu ns\n", + i, conf->cycle_time - entry->interval, + enst_max_hw_interval(speed)); + err = -ERANGE; + goto cleanup; + } + + enst_queue[i].queue_id = order_base_2(entry->gate_mask); + enst_queue[i].start_time_mask = + (start_time_sec << GEM_START_TIME_SEC_OFFSET) | + start_time_nsec; + enst_queue[i].on_time_bytes = + enst_ns_to_hw_units(entry->interval, speed); + enst_queue[i].off_time_bytes = + enst_ns_to_hw_units(conf->cycle_time - entry->interval, speed); + + configured_queues |= entry->gate_mask; + total_on_time += entry->interval; + start_time += entry->interval; + } + + /* Check total interval doesn't exceed cycle time */ + if (total_on_time > conf->cycle_time) { + netdev_err(ndev, "Total ON %llu ns exceeds cycle time %llu ns\n", + total_on_time, conf->cycle_time); + err = -EINVAL; + goto cleanup; + } + + netdev_dbg(ndev, "TAPRIO setup: %zu entries, base_time=%lld ns, cycle_time=%llu ns\n", + conf->num_entries, conf->base_time, conf->cycle_time); + + /* All validations passed - proceed with hardware configuration */ + scoped_guard(spinlock_irqsave, &bp->lock) { + /* Disable ENST queues if running before configuring */ + gem_writel(bp, ENST_CONTROL, + bp->queue_mask << GEM_ENST_DISABLE_QUEUE_OFFSET); + + for (i = 0; i < conf->num_entries; i++) { + queue = &bp->queues[enst_queue[i].queue_id]; + /* Configure queue timing registers */ + queue_writel(queue, ENST_START_TIME, + enst_queue[i].start_time_mask); + queue_writel(queue, ENST_ON_TIME, + enst_queue[i].on_time_bytes); + queue_writel(queue, ENST_OFF_TIME, + enst_queue[i].off_time_bytes); + } + + /* Enable ENST for all configured queues in one write */ + gem_writel(bp, ENST_CONTROL, configured_queues); + } + + netdev_info(ndev, "TAPRIO configuration completed successfully: %zu entries, %d queues configured\n", + conf->num_entries, hweight32(configured_queues)); + +cleanup: + kfree(enst_queue); + return err; +} + +static void macb_taprio_destroy(struct net_device *ndev) +{ + struct macb *bp = netdev_priv(ndev); + struct macb_queue *queue; + u32 enst_disable_mask; + unsigned int q; + + netdev_reset_tc(ndev); + enst_disable_mask = bp->queue_mask << GEM_ENST_DISABLE_QUEUE_OFFSET; + + scoped_guard(spinlock_irqsave, &bp->lock) { + /* Single disable command for all queues */ + gem_writel(bp, ENST_CONTROL, enst_disable_mask); + + /* Clear all queue ENST registers in batch */ + for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { + queue_writel(queue, ENST_START_TIME, 0); + queue_writel(queue, ENST_ON_TIME, 0); + queue_writel(queue, ENST_OFF_TIME, 0); + } + } + netdev_info(ndev, "TAPRIO destroy: All gates disabled\n"); +} + +static int macb_setup_taprio(struct net_device *ndev, + struct tc_taprio_qopt_offload *taprio) +{ + struct macb *bp = netdev_priv(ndev); + int err = 0; + + if (unlikely(!(ndev->hw_features & NETIF_F_HW_TC))) + return -EOPNOTSUPP; + + /* Check if Device is in runtime suspend */ + if (unlikely(pm_runtime_suspended(&bp->pdev->dev))) { + netdev_err(ndev, "Device is in runtime suspend\n"); + return -EOPNOTSUPP; + } + + switch (taprio->cmd) { + case TAPRIO_CMD_REPLACE: + err = macb_taprio_setup_replace(ndev, taprio); + break; + case TAPRIO_CMD_DESTROY: + macb_taprio_destroy(ndev); + break; + default: + err = -EOPNOTSUPP; + } + + return err; +} + +static int macb_setup_tc(struct net_device *dev, enum tc_setup_type type, + void *type_data) +{ + if (!dev || !type_data) + return -EINVAL; + + switch (type) { + case TC_SETUP_QDISC_TAPRIO: + return macb_setup_taprio(dev, type_data); + default: + return -EOPNOTSUPP; + } +} + static const struct net_device_ops macb_netdev_ops = { .ndo_open = macb_open, .ndo_stop = macb_close, @@ -4101,6 +4319,7 @@ static const struct net_device_ops macb_netdev_ops = { .ndo_features_check = macb_features_check, .ndo_hwtstamp_set = macb_hwtstamp_set, .ndo_hwtstamp_get = macb_hwtstamp_get, + .ndo_setup_tc = macb_setup_tc, }; /* Configure peripheral capabilities according to device tree @@ -4327,6 +4546,10 @@ static int macb_init(struct platform_device *pdev) #endif } + queue->ENST_START_TIME = GEM_ENST_START_TIME(hw_q); + queue->ENST_ON_TIME = GEM_ENST_ON_TIME(hw_q); + queue->ENST_OFF_TIME = GEM_ENST_OFF_TIME(hw_q); + /* get irq: here we use the linux queue index, not the hardware * queue index. the queue irq definitions in the device tree * must remove the optional gaps that could exist in the From d739ce4bebf4c708020a900548e36d005236388f Mon Sep 17 00:00:00 2001 From: Vineeth Karumanchi Date: Thu, 14 Aug 2025 12:40:58 +0530 Subject: [PATCH 01336/11391] net: macb: Add capability-based QBV detection and Versal support The 'exclude_qbv' bit in the designcfg_debug1 register varies across MACB/GEM IP revisions, making direct probing unreliable for detecting QBV support. This patch introduces a capability-based approach for consistent QBV feature identification across the IP family. Platform support updates: - Establish foundation for QBV detection in TAPRIO implementation - Enable MACB_CAPS_QBV for Xilinx Versal platform configuration - Fix capability line wrapping, ensuring code stays within 80 columns Signed-off-by: Vineeth Karumanchi Link: https://patch.msgid.link/20250814071058.3062453-3-vineeth.karumanchi@amd.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/cadence/macb.h | 1 + drivers/net/ethernet/cadence/macb_main.c | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index d1a98b45c92c..904954610611 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -770,6 +770,7 @@ #define MACB_CAPS_MIIONRGMII 0x00000200 #define MACB_CAPS_NEED_TSUCLK 0x00000400 #define MACB_CAPS_QUEUE_DISABLE 0x00000800 +#define MACB_CAPS_QBV 0x00001000 #define MACB_CAPS_PCS 0x01000000 #define MACB_CAPS_HIGH_SPEED 0x02000000 #define MACB_CAPS_CLK_HW_CHG 0x04000000 diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index a42304eb2bf8..124ef0b0bcad 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -4602,6 +4602,10 @@ static int macb_init(struct platform_device *pdev) dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_RXCSUM; if (bp->caps & MACB_CAPS_SG_DISABLED) dev->hw_features &= ~NETIF_F_SG; + /* Enable HW_TC if hardware supports QBV */ + if (bp->caps & MACB_CAPS_QBV) + dev->hw_features |= NETIF_F_HW_TC; + dev->features = dev->hw_features; /* Check RX Flow Filters support. @@ -5354,8 +5358,9 @@ static const struct macb_config sama7g5_emac_config = { static const struct macb_config versal_config = { .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_JUMBO | - MACB_CAPS_GEM_HAS_PTP | MACB_CAPS_BD_RD_PREFETCH | MACB_CAPS_NEED_TSUCLK | - MACB_CAPS_QUEUE_DISABLE, + MACB_CAPS_GEM_HAS_PTP | MACB_CAPS_BD_RD_PREFETCH | + MACB_CAPS_NEED_TSUCLK | MACB_CAPS_QUEUE_DISABLE | + MACB_CAPS_QBV, .dma_burst_length = 16, .clk_init = macb_clk_init, .init = init_reset_optional, From faba66cfcef6374020d2ac7bed091b2793eefeec Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Tue, 12 Aug 2025 16:12:43 +0800 Subject: [PATCH 01337/11391] pinctrl: bcm: use PTR_ERR_OR_ZERO() to simplify code Use the standard error pointer macro to shorten the code and simplify. Signed-off-by: Xichao Zhao Link: https://lore.kernel.org/20250812081243.22659-1-zhao.xichao@vivo.com Signed-off-by: Linus Walleij --- drivers/pinctrl/bcm/pinctrl-bcm6358.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pinctrl/bcm/pinctrl-bcm6358.c b/drivers/pinctrl/bcm/pinctrl-bcm6358.c index 891de49d76e7..4c8cd65fc31e 100644 --- a/drivers/pinctrl/bcm/pinctrl-bcm6358.c +++ b/drivers/pinctrl/bcm/pinctrl-bcm6358.c @@ -343,10 +343,8 @@ static int bcm6358_pinctrl_probe(struct platform_device *pdev) pc = platform_get_drvdata(pdev); priv->overlays = devm_regmap_field_alloc(dev, pc->regs, overlays); - if (IS_ERR(priv->overlays)) - return PTR_ERR(priv->overlays); - return 0; + return PTR_ERR_OR_ZERO(priv->overlays); } static const struct of_device_id bcm6358_pinctrl_match[] = { From a8bdd935d1ddb7186358fb60ffe84253e85340c8 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 14 Aug 2025 09:51:16 +0200 Subject: [PATCH 01338/11391] net: airoha: Add wlan flowtable TX offload Introduce support to offload the traffic received on the ethernet NIC and forwarded to the wireless one using HW Packet Processor Engine (PPE) capabilities. Signed-off-by: Lorenzo Bianconi Link: https://patch.msgid.link/20250814-airoha-en7581-wlan-tx-offload-v1-1-72e0a312003e@kernel.org Signed-off-by: Paolo Abeni --- drivers/net/ethernet/airoha/airoha_eth.h | 11 +++ drivers/net/ethernet/airoha/airoha_ppe.c | 95 +++++++++++++++++------- 2 files changed, 81 insertions(+), 25 deletions(-) diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h index a970b789cf23..9f721e2b972f 100644 --- a/drivers/net/ethernet/airoha/airoha_eth.h +++ b/drivers/net/ethernet/airoha/airoha_eth.h @@ -252,6 +252,10 @@ enum { #define AIROHA_FOE_MAC_SMAC_ID GENMASK(20, 16) #define AIROHA_FOE_MAC_PPPOE_ID GENMASK(15, 0) +#define AIROHA_FOE_MAC_WDMA_QOS GENMASK(15, 12) +#define AIROHA_FOE_MAC_WDMA_BAND BIT(11) +#define AIROHA_FOE_MAC_WDMA_WCID GENMASK(10, 0) + struct airoha_foe_mac_info_common { u16 vlan1; u16 etype; @@ -481,6 +485,13 @@ struct airoha_flow_table_entry { unsigned long cookie; }; +struct airoha_wdma_info { + u8 idx; + u8 queue; + u16 wcid; + u8 bss; +}; + /* RX queue to IRQ mapping: BIT(q) in IRQ(n) */ #define RX_IRQ0_BANK_PIN_MASK 0x839f #define RX_IRQ1_BANK_PIN_MASK 0x7fe00000 diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c index 82163392332c..2bf1c584ba7b 100644 --- a/drivers/net/ethernet/airoha/airoha_ppe.c +++ b/drivers/net/ethernet/airoha/airoha_ppe.c @@ -190,6 +190,31 @@ static int airoha_ppe_flow_mangle_ipv4(const struct flow_action_entry *act, return 0; } +static int airoha_ppe_get_wdma_info(struct net_device *dev, const u8 *addr, + struct airoha_wdma_info *info) +{ + struct net_device_path_stack stack; + struct net_device_path *path; + int err; + + if (!dev) + return -ENODEV; + + err = dev_fill_forward_path(dev, addr, &stack); + if (err) + return err; + + path = &stack.path[stack.num_paths - 1]; + if (path->type != DEV_PATH_MTK_WDMA) + return -1; + + info->idx = path->mtk_wdma.wdma_idx; + info->bss = path->mtk_wdma.bss; + info->wcid = path->mtk_wdma.wcid; + + return 0; +} + static int airoha_get_dsa_port(struct net_device **dev) { #if IS_ENABLED(CONFIG_NET_DSA) @@ -220,9 +245,9 @@ static int airoha_ppe_foe_entry_prepare(struct airoha_eth *eth, struct airoha_flow_data *data, int l4proto) { - int dsa_port = airoha_get_dsa_port(&dev); + u32 qdata = FIELD_PREP(AIROHA_FOE_SHAPER_ID, 0x7f), ports_pad, val; + int wlan_etype = -EINVAL, dsa_port = airoha_get_dsa_port(&dev); struct airoha_foe_mac_info_common *l2; - u32 qdata, ports_pad, val; u8 smac_id = 0xf; memset(hwe, 0, sizeof(*hwe)); @@ -236,31 +261,47 @@ static int airoha_ppe_foe_entry_prepare(struct airoha_eth *eth, AIROHA_FOE_IB1_BIND_TTL; hwe->ib1 = val; - val = FIELD_PREP(AIROHA_FOE_IB2_PORT_AG, 0x1f) | - AIROHA_FOE_IB2_PSE_QOS; - if (dsa_port >= 0) - val |= FIELD_PREP(AIROHA_FOE_IB2_NBQ, dsa_port); - + val = FIELD_PREP(AIROHA_FOE_IB2_PORT_AG, 0x1f); if (dev) { - struct airoha_gdm_port *port = netdev_priv(dev); - u8 pse_port; + struct airoha_wdma_info info = {}; - if (!airoha_is_valid_gdm_port(eth, port)) - return -EINVAL; + if (!airoha_ppe_get_wdma_info(dev, data->eth.h_dest, &info)) { + val |= FIELD_PREP(AIROHA_FOE_IB2_NBQ, info.idx) | + FIELD_PREP(AIROHA_FOE_IB2_PSE_PORT, + FE_PSE_PORT_CDM4); + qdata |= FIELD_PREP(AIROHA_FOE_ACTDP, info.bss); + wlan_etype = FIELD_PREP(AIROHA_FOE_MAC_WDMA_BAND, + info.idx) | + FIELD_PREP(AIROHA_FOE_MAC_WDMA_WCID, + info.wcid); + } else { + struct airoha_gdm_port *port = netdev_priv(dev); + u8 pse_port; - if (dsa_port >= 0) - pse_port = port->id == 4 ? FE_PSE_PORT_GDM4 : port->id; - else - pse_port = 2; /* uplink relies on GDM2 loopback */ - val |= FIELD_PREP(AIROHA_FOE_IB2_PSE_PORT, pse_port); + if (!airoha_is_valid_gdm_port(eth, port)) + return -EINVAL; - /* For downlink traffic consume SRAM memory for hw forwarding - * descriptors queue. - */ - if (airhoa_is_lan_gdm_port(port)) - val |= AIROHA_FOE_IB2_FAST_PATH; + if (dsa_port >= 0) + pse_port = port->id == 4 ? FE_PSE_PORT_GDM4 + : port->id; + else + pse_port = 2; /* uplink relies on GDM2 + * loopback + */ - smac_id = port->id; + val |= FIELD_PREP(AIROHA_FOE_IB2_PSE_PORT, pse_port) | + AIROHA_FOE_IB2_PSE_QOS; + /* For downlink traffic consume SRAM memory for hw + * forwarding descriptors queue. + */ + if (airhoa_is_lan_gdm_port(port)) + val |= AIROHA_FOE_IB2_FAST_PATH; + if (dsa_port >= 0) + val |= FIELD_PREP(AIROHA_FOE_IB2_NBQ, + dsa_port); + + smac_id = port->id; + } } if (is_multicast_ether_addr(data->eth.h_dest)) @@ -272,7 +313,6 @@ static int airoha_ppe_foe_entry_prepare(struct airoha_eth *eth, if (type == PPE_PKT_TYPE_IPV6_ROUTE_3T) hwe->ipv6.ports = ports_pad; - qdata = FIELD_PREP(AIROHA_FOE_SHAPER_ID, 0x7f); if (type == PPE_PKT_TYPE_BRIDGE) { airoha_ppe_foe_set_bridge_addrs(&hwe->bridge, &data->eth); hwe->bridge.data = qdata; @@ -313,7 +353,9 @@ static int airoha_ppe_foe_entry_prepare(struct airoha_eth *eth, l2->vlan2 = data->vlan.hdr[1].id; } - if (dsa_port >= 0) { + if (wlan_etype >= 0) { + l2->etype = wlan_etype; + } else if (dsa_port >= 0) { l2->etype = BIT(dsa_port); l2->etype |= !data->vlan.num ? BIT(15) : 0; } else if (data->pppoe.num) { @@ -490,6 +532,10 @@ static void airoha_ppe_foe_flow_stats_update(struct airoha_ppe *ppe, meter = &hwe->ipv4.l2.meter; } + pse_port = FIELD_GET(AIROHA_FOE_IB2_PSE_PORT, *ib2); + if (pse_port == FE_PSE_PORT_CDM4) + return; + airoha_ppe_foe_flow_stat_entry_reset(ppe, npu, index); val = FIELD_GET(AIROHA_FOE_CHANNEL | AIROHA_FOE_QID, *data); @@ -500,7 +546,6 @@ static void airoha_ppe_foe_flow_stats_update(struct airoha_ppe *ppe, AIROHA_FOE_IB2_PSE_QOS | AIROHA_FOE_IB2_FAST_PATH); *meter |= FIELD_PREP(AIROHA_FOE_TUNNEL_MTU, val); - pse_port = FIELD_GET(AIROHA_FOE_IB2_PSE_PORT, *ib2); nbq = pse_port == 1 ? 6 : 5; *ib2 &= ~(AIROHA_FOE_IB2_NBQ | AIROHA_FOE_IB2_PSE_PORT | AIROHA_FOE_IB2_PSE_QOS); From 6e6fe5a99048c020594d815a1c0f8ad183073e66 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 24 Jul 2025 11:54:22 +0100 Subject: [PATCH 01339/11391] 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 01340/11391] 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 01341/11391] 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 01342/11391] 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 01343/11391] 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 @@ 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 01344/11391] 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 01345/11391] 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 01346/11391] 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 01347/11391] 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 01348/11391] 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 01349/11391] 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 01350/11391] 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 01351/11391] 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 01352/11391] 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 01353/11391] 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 01354/11391] 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 01355/11391] 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 01356/11391] 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 800348aa34b2bc40d558bb17b6719c51fac0b6de Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Fri, 15 Aug 2025 23:37:44 +0200 Subject: [PATCH 01357/11391] kcsan: test: 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: Justin Stitt Signed-off-by: Marco Elver --- kernel/kcsan/kcsan_test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/kcsan/kcsan_test.c b/kernel/kcsan/kcsan_test.c index 49ab81faaed9..ea1cb4c8a894 100644 --- a/kernel/kcsan/kcsan_test.c +++ b/kernel/kcsan/kcsan_test.c @@ -125,7 +125,7 @@ static void probe_console(void *ignore, const char *buf, size_t len) goto out; /* No second line of interest. */ - strcpy(observed.lines[nlines++], ""); + strscpy(observed.lines[nlines++], ""); } } @@ -231,7 +231,7 @@ static bool __report_matches(const struct expect_report *r) if (!r->access[1].fn) { /* Dummy string if no second access is available. */ - strcpy(cur, ""); + strscpy(expect[2], ""); break; } } From 4afc5bf0a1849f0ed3ea1d9fd9d0e79b23a67f96 Mon Sep 17 00:00:00 2001 From: Carlos Llamas Date: Sun, 27 Jul 2025 18:29:04 +0000 Subject: [PATCH 01358/11391] 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 @@ static void binder_transaction(struct binder_proc *proc, 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 @@ static void binder_transaction(struct binder_proc *proc, 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 01359/11391] 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 01360/11391] 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 @@ static void binder_transaction(struct binder_proc *proc, 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 01361/11391] 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 01362/11391] 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 01363/11391] 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 01364/11391] 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 bba95412064207ea3a0ea1776daec6480e5f8b0f Mon Sep 17 00:00:00 2001 From: Shankari Anand Date: Sat, 16 Aug 2025 17:53:23 +0530 Subject: [PATCH 01365/11391] rust: pid_namespace: update AlwaysRefCounted imports from sync::aref Update call sites in `pid_namespace.rs` to import `AlwaysRefCounted` from `sync::aref` instead of `types`. This aligns with the ongoing effort to move `ARef` and `AlwaysRefCounted` to `sync`. Suggested-by: Benno Lossin Link: https://github.com/Rust-for-Linux/linux/issues/1173 Signed-off-by: Shankari Anand Link: https://lore.kernel.org/20250816122323.11657-1-shankari.ak0208@gmail.com Reviewed-by: Benno Lossin Signed-off-by: Christian Brauner --- rust/kernel/pid_namespace.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/rust/kernel/pid_namespace.rs b/rust/kernel/pid_namespace.rs index 0e93808e4639..979a9718f153 100644 --- a/rust/kernel/pid_namespace.rs +++ b/rust/kernel/pid_namespace.rs @@ -7,10 +7,7 @@ //! C header: [`include/linux/pid_namespace.h`](srctree/include/linux/pid_namespace.h) and //! [`include/linux/pid.h`](srctree/include/linux/pid.h) -use crate::{ - bindings, - types::{AlwaysRefCounted, Opaque}, -}; +use crate::{bindings, sync::aref::AlwaysRefCounted, types::Opaque}; use core::ptr; /// Wraps the kernel's `struct pid_namespace`. Thread safe. From 8e7e265d558e0257d6dacc78ec64aff4ba75f61e Mon Sep 17 00:00:00 2001 From: Charalampos Mitrodimas Date: Sat, 16 Aug 2025 14:14:37 +0000 Subject: [PATCH 01366/11391] debugfs: fix mount options not being applied Mount options (uid, gid, mode) are silently ignored when debugfs is mounted. This is a regression introduced during the conversion to the new mount API. When the mount API conversion was done, the parsed options were never applied to the superblock when it was reused. As a result, the mount options were ignored when debugfs was mounted. Fix this by following the same pattern as the tracefs fix in commit e4d32142d1de ("tracing: Fix tracefs mount options"). Call debugfs_reconfigure() in debugfs_get_tree() to apply the mount options to the superblock after it has been created or reused. As an example, with the bug the "mode" mount option is ignored: $ mount -o mode=0666 -t debugfs debugfs /tmp/debugfs_test $ mount | grep debugfs_test debugfs on /tmp/debugfs_test type debugfs (rw,relatime) $ ls -ld /tmp/debugfs_test drwx------ 25 root root 0 Aug 4 14:16 /tmp/debugfs_test With the fix applied, it works as expected: $ mount -o mode=0666 -t debugfs debugfs /tmp/debugfs_test $ mount | grep debugfs_test debugfs on /tmp/debugfs_test type debugfs (rw,relatime,mode=666) $ ls -ld /tmp/debugfs_test drw-rw-rw- 37 root root 0 Aug 2 17:28 /tmp/debugfs_test Fixes: a20971c18752 ("vfs: Convert debugfs to use the new mount API") Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220406 Cc: stable@vger.kernel.org Reviewed-by: Eric Sandeen Signed-off-by: Charalampos Mitrodimas Link: https://lore.kernel.org/20250816-debugfs-mount-opts-v3-1-d271dad57b5b@posteo.net Signed-off-by: Christian Brauner --- fs/debugfs/inode.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index a0357b0cf362..c12d649df6a5 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -183,6 +183,9 @@ static int debugfs_reconfigure(struct fs_context *fc) struct debugfs_fs_info *sb_opts = sb->s_fs_info; struct debugfs_fs_info *new_opts = fc->s_fs_info; + if (!new_opts) + return 0; + sync_filesystem(sb); /* structure copy of new mount options to sb */ @@ -282,10 +285,16 @@ static int debugfs_fill_super(struct super_block *sb, struct fs_context *fc) static int debugfs_get_tree(struct fs_context *fc) { + int err; + if (!(debugfs_allow & DEBUGFS_ALLOW_API)) return -EPERM; - return get_tree_single(fc, debugfs_fill_super); + err = get_tree_single(fc, debugfs_fill_super); + if (err) + return err; + + return debugfs_reconfigure(fc); } static void debugfs_free_fc(struct fs_context *fc) From 1d6249c1ce826fcf03c695973095eb4a50fb7fd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Mon, 11 Aug 2025 11:13:35 +0200 Subject: [PATCH 01367/11391] sysfs: remove bin_attribute::read_new/write_new() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These transitional fields are now unused and unnecessary. Remove them and their logic in the sysfs core. Signed-off-by: Thomas Weißschuh Link: https://lore.kernel.org/r/20250811-sysfs-const-bin_attr-final-v4-1-7b6053fd58bb@weissschuh.net Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/file.c | 22 +++++----------------- include/linux/sysfs.h | 4 ---- 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 1ca143d2f22a..3825e780cc58 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -97,12 +97,9 @@ static ssize_t sysfs_kf_bin_read(struct kernfs_open_file *of, char *buf, count = size - pos; } - if (!battr->read && !battr->read_new) + if (!battr->read) return -EIO; - if (battr->read_new) - return battr->read_new(of->file, kobj, battr, buf, pos, count); - return battr->read(of->file, kobj, battr, buf, pos, count); } @@ -161,12 +158,9 @@ static ssize_t sysfs_kf_bin_write(struct kernfs_open_file *of, char *buf, if (!count) return 0; - if (!battr->write && !battr->write_new) + if (!battr->write) return -EIO; - if (battr->write_new) - return battr->write_new(of->file, kobj, battr, buf, pos, count); - return battr->write(of->file, kobj, battr, buf, pos, count); } @@ -335,19 +329,13 @@ int sysfs_add_bin_file_mode_ns(struct kernfs_node *parent, const struct kernfs_ops *ops; struct kernfs_node *kn; - if (battr->read && battr->read_new) - return -EINVAL; - - if (battr->write && battr->write_new) - return -EINVAL; - if (battr->mmap) ops = &sysfs_bin_kfops_mmap; - else if ((battr->read || battr->read_new) && (battr->write || battr->write_new)) + else if (battr->read && battr->write) ops = &sysfs_bin_kfops_rw; - else if (battr->read || battr->read_new) + else if (battr->read) ops = &sysfs_bin_kfops_ro; - else if (battr->write || battr->write_new) + else if (battr->write) ops = &sysfs_bin_kfops_wo; else ops = &sysfs_file_kfops_empty; diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index f418aae4f113..7544f6d81c05 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -308,12 +308,8 @@ struct bin_attribute { struct address_space *(*f_mapping)(void); ssize_t (*read)(struct file *, struct kobject *, const struct bin_attribute *, char *, loff_t, size_t); - ssize_t (*read_new)(struct file *, struct kobject *, const struct bin_attribute *, - char *, loff_t, size_t); ssize_t (*write)(struct file *, struct kobject *, const struct bin_attribute *, char *, loff_t, size_t); - ssize_t (*write_new)(struct file *, struct kobject *, - const struct bin_attribute *, char *, loff_t, size_t); loff_t (*llseek)(struct file *, struct kobject *, const struct bin_attribute *, loff_t, int); int (*mmap)(struct file *, struct kobject *, const struct bin_attribute *attr, From 44d454fcffa8b08d6d66df132121c1d387fa85db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Mon, 11 Aug 2025 11:13:36 +0200 Subject: [PATCH 01368/11391] sysfs: remove attribute_group::bin_attrs_new MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This transitional field is now unused and unnecessary. Remove it. Signed-off-by: Thomas Weißschuh Link: https://lore.kernel.org/r/20250811-sysfs-const-bin_attr-final-v4-2-7b6053fd58bb@weissschuh.net Signed-off-by: Greg Kroah-Hartman --- include/linux/sysfs.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 7544f6d81c05..9a25a2911652 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -106,10 +106,7 @@ struct attribute_group { const struct bin_attribute *, int); struct attribute **attrs; - union { - const struct bin_attribute *const *bin_attrs; - const struct bin_attribute *const *bin_attrs_new; - }; + const struct bin_attribute *const *bin_attrs; }; #define SYSFS_PREALLOC 010000 @@ -293,7 +290,7 @@ __ATTRIBUTE_GROUPS(_name) #define BIN_ATTRIBUTE_GROUPS(_name) \ static const struct attribute_group _name##_group = { \ - .bin_attrs_new = _name##_attrs, \ + .bin_attrs = _name##_attrs, \ }; \ __ATTRIBUTE_GROUPS(_name) From eef32050636a3390724dfe532ab9af9d58c854c3 Mon Sep 17 00:00:00 2001 From: Andrea della Porta Date: Tue, 12 Aug 2025 11:26:18 +0200 Subject: [PATCH 01369/11391] pinctrl: rp1: Add regmap ranges to RP1 gpio controller The current gpio driver for RP1 shows only the very first register from sysfs, e.g.: $ cat /sys/kernel/debug/regmap/1f000d0000.gpio-rp1-pinctrl/registers 0: 0abe0000 Add the correct ranges to the regmap configuration. Signed-off-by: Andrea della Porta Link: https://lore.kernel.org/20250812092618.14270-1-andrea.porta@suse.com Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-rp1.c | 95 +++++++++++++++++++++++++++++++++-- 1 file changed, 90 insertions(+), 5 deletions(-) diff --git a/drivers/pinctrl/pinctrl-rp1.c b/drivers/pinctrl/pinctrl-rp1.c index dadafc935dbb..b231efc62ff3 100644 --- a/drivers/pinctrl/pinctrl-rp1.c +++ b/drivers/pinctrl/pinctrl-rp1.c @@ -1623,12 +1623,97 @@ MODULE_DEVICE_TABLE(of, rp1_pinctrl_match); static struct rp1_pinctrl rp1_pinctrl_data = {}; -static const struct regmap_config rp1_pinctrl_regmap_cfg = { +static const struct regmap_range rp1_gpio_reg_ranges[] = { + /* BANK 0 */ + regmap_reg_range(0x2004, 0x20dc), + regmap_reg_range(0x3004, 0x30dc), + regmap_reg_range(0x0004, 0x00dc), + regmap_reg_range(0x0124, 0x0124), + regmap_reg_range(0x211c, 0x211c), + regmap_reg_range(0x311c, 0x311c), + /* BANK 1 */ + regmap_reg_range(0x6004, 0x602c), + regmap_reg_range(0x7004, 0x702c), + regmap_reg_range(0x4004, 0x402c), + regmap_reg_range(0x4124, 0x4124), + regmap_reg_range(0x611c, 0x611c), + regmap_reg_range(0x711c, 0x711c), + /* BANK 2 */ + regmap_reg_range(0xa004, 0xa09c), + regmap_reg_range(0xb004, 0xb09c), + regmap_reg_range(0x8004, 0x809c), + regmap_reg_range(0x8124, 0x8124), + regmap_reg_range(0xa11c, 0xa11c), + regmap_reg_range(0xb11c, 0xb11c), +}; + +static const struct regmap_range rp1_rio_reg_ranges[] = { + /* BANK 0 */ + regmap_reg_range(0x2000, 0x2004), + regmap_reg_range(0x3000, 0x3004), + regmap_reg_range(0x0004, 0x0008), + /* BANK 1 */ + regmap_reg_range(0x6000, 0x6004), + regmap_reg_range(0x7000, 0x7004), + regmap_reg_range(0x4004, 0x4008), + /* BANK 2 */ + regmap_reg_range(0xa000, 0xa004), + regmap_reg_range(0xb000, 0xb004), + regmap_reg_range(0x8004, 0x8008), +}; + +static const struct regmap_range rp1_pads_reg_ranges[] = { + /* BANK 0 */ + regmap_reg_range(0x0004, 0x0070), + /* BANK 1 */ + regmap_reg_range(0x4004, 0x4018), + /* BANK 2 */ + regmap_reg_range(0x8004, 0x8050), +}; + +static const struct regmap_access_table rp1_gpio_reg_table = { + .yes_ranges = rp1_gpio_reg_ranges, + .n_yes_ranges = ARRAY_SIZE(rp1_gpio_reg_ranges), +}; + +static const struct regmap_access_table rp1_rio_reg_table = { + .yes_ranges = rp1_rio_reg_ranges, + .n_yes_ranges = ARRAY_SIZE(rp1_rio_reg_ranges), +}; + +static const struct regmap_access_table rp1_pads_reg_table = { + .yes_ranges = rp1_pads_reg_ranges, + .n_yes_ranges = ARRAY_SIZE(rp1_pads_reg_ranges), +}; + +static const struct regmap_config rp1_pinctrl_gpio_regmap_cfg = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, .fast_io = true, - .name = "rp1-pinctrl", + .rd_table = &rp1_gpio_reg_table, + .name = "rp1-gpio", + .max_register = 0xb11c, +}; + +static const struct regmap_config rp1_pinctrl_rio_regmap_cfg = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .fast_io = true, + .rd_table = &rp1_rio_reg_table, + .name = "rp1-rio", + .max_register = 0xb004, +}; + +static const struct regmap_config rp1_pinctrl_pads_regmap_cfg = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .fast_io = true, + .rd_table = &rp1_pads_reg_table, + .name = "rp1-pads", + .max_register = 0x8050, }; static int rp1_gen_regfield(struct device *dev, @@ -1685,17 +1770,17 @@ static int rp1_pinctrl_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(pc->pads_base), "could not get PADS IO memory\n"); gpio_regmap = devm_regmap_init_mmio(dev, pc->gpio_base, - &rp1_pinctrl_regmap_cfg); + &rp1_pinctrl_gpio_regmap_cfg); if (IS_ERR(gpio_regmap)) return dev_err_probe(dev, PTR_ERR(gpio_regmap), "could not init GPIO regmap\n"); rio_regmap = devm_regmap_init_mmio(dev, pc->rio_base, - &rp1_pinctrl_regmap_cfg); + &rp1_pinctrl_rio_regmap_cfg); if (IS_ERR(rio_regmap)) return dev_err_probe(dev, PTR_ERR(rio_regmap), "could not init RIO regmap\n"); pads_regmap = devm_regmap_init_mmio(dev, pc->pads_base, - &rp1_pinctrl_regmap_cfg); + &rp1_pinctrl_pads_regmap_cfg); if (IS_ERR(pads_regmap)) return dev_err_probe(dev, PTR_ERR(pads_regmap), "could not init PADS regmap\n"); From 15e3363af00a9e5b4f5c10b17940733a8613ef57 Mon Sep 17 00:00:00 2001 From: Aaron Kling Date: Tue, 12 Aug 2025 16:24:40 -0500 Subject: [PATCH 01370/11391] dt-bindings: pinctrl: Document Tegra186 pin controllers Tegra186 contains two pin controllers. Document their compatible strings and describe the list of pins and functions that they provide. Reviewed-by: Rob Herring (Arm) Signed-off-by: Aaron Kling Link: https://lore.kernel.org/20250812-tegra186-pinctrl-v3-1-115714eeecb1@gmail.com Signed-off-by: Linus Walleij --- .../pinctrl/nvidia,tegra186-pinmux.yaml | 285 ++++++++++++++++++ 1 file changed, 285 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/nvidia,tegra186-pinmux.yaml diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra186-pinmux.yaml b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra186-pinmux.yaml new file mode 100644 index 000000000000..ac764d0ac4b6 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra186-pinmux.yaml @@ -0,0 +1,285 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/nvidia,tegra186-pinmux.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NVIDIA Tegra186 Pinmux Controller + +maintainers: + - Thierry Reding + - Jon Hunter + +properties: + compatible: + enum: + - nvidia,tegra186-pinmux + - nvidia,tegra186-pinmux-aon + + reg: + items: + - description: pinmux registers + +patternProperties: + "^pinmux(-[a-z0-9-]+)?$": + type: object + + # pin groups + additionalProperties: + $ref: nvidia,tegra-pinmux-common.yaml + unevaluatedProperties: false + properties: + nvidia,function: + enum: [ aud, can0, can1, ccla, dca, dcb, dcc, directdc, directdc1, + displaya, displayb, dmic1, dmic2, dmic3, dmic4, dmic5, dp, + dspk0, dspk1, dtv, eqos, extperiph1, extperiph2, extperiph3, + extperiph4, gp, gpio, hdmi, i2c1, i2c2, i2c3, i2c5, i2c7, + i2c8, i2c9, i2s1, i2s2, i2s3, i2s4, i2s5, i2s6, iqc0, iqc1, + nv, pe, pe0, pe1, pe2, qspi, rsvd0, rsvd1, rsvd2, rsvd3, + sata, sce, sdmmc1, sdmmc2, sdmmc3, sdmmc4, soc, spdif, spi1, + spi2, spi3, spi4, touch, uarta, uartb, uartc, uartd, uarte, + uartf, uartg, ufs0, usb, vgp1, vgp2, vgp3, vgp4, vgp5, vgp6, + wdt ] + + nvidia,pull: true + nvidia,tristate: true + nvidia,schmitt: true + nvidia,enable-input: true + nvidia,open-drain: true + nvidia,lock: true + nvidia,drive-type: true + nvidia,io-hv: true + + required: + - nvidia,pins + +additionalProperties: false + +allOf: + - if: + properties: + compatible: + const: nvidia,tegra186-pinmux + then: + patternProperties: + "^pinmux(-[a-z0-9-]+)?$": + type: object + additionalProperties: + properties: + nvidia,pins: + description: An array of strings. Each string contains the name + of a pin or group. Valid values for these names are listed + below. + items: + enum: [ pex_l0_rst_n_pa0, pex_l0_clkreq_n_pa1, + pex_wake_n_pa2, pex_l1_rst_n_pa3, + pex_l1_clkreq_n_pa4, pex_l2_rst_n_pa5, + pex_l2_clkreq_n_pa6, uart4_tx_pb0, uart4_rx_pb1, + uart4_rts_pb2, uart4_cts_pb3, gpio_wan1_pb4, + gpio_wan2_pb5, gpio_wan3_pb6, gpio_wan4_pc0, + dap2_sclk_pc1, dap2_dout_pc2, dap2_din_pc3, + dap2_fs_pc4, gen1_i2c_scl_pc5, gen1_i2c_sda_pc6, + sdmmc1_clk_pd0, sdmmc1_cmd_pd1, sdmmc1_dat0_pd2, + sdmmc1_dat1_pd3, sdmmc1_dat2_pd4, sdmmc1_dat3_pd5, + eqos_txc_pe0, eqos_td0_pe1, eqos_td1_pe2, + eqos_td2_pe3, eqos_td3_pe4, eqos_tx_ctl_pe5, + eqos_rd0_pe6, eqos_rd1_pe7, eqos_rd2_pf0, + eqos_rd3_pf1, eqos_rx_ctl_pf2, eqos_rxc_pf3, + eqos_mdio_pf4, eqos_mdc_pf5, sdmmc3_clk_pg0, + sdmmc3_cmd_pg1, sdmmc3_dat0_pg2, sdmmc3_dat1_pg3, + sdmmc3_dat2_pg4, sdmmc3_dat3_pg5, gpio_wan5_ph0, + gpio_wan6_ph1, gpio_wan7_ph2, gpio_wan8_ph3, + bcpu_pwr_req_ph4, mcpu_pwr_req_ph5, gpu_pwr_req_ph6, + gpio_pq0_pi0, gpio_pq1_pi1, gpio_pq2_pi2, + gpio_pq3_pi3, gpio_pq4_pi4, gpio_pq5_pi5, + gpio_pq6_pi6, gpio_pq7_pi7, dap1_sclk_pj0, + dap1_dout_pj1, dap1_din_pj2, dap1_fs_pj3, + aud_mclk_pj4, gpio_aud0_pj5, gpio_aud1_pj6, + gpio_aud2_pj7, gpio_aud3_pk0, gen7_i2c_scl_pl0, + gen7_i2c_sda_pl1, gen9_i2c_scl_pl2, gen9_i2c_sda_pl3, + usb_vbus_en0_pl4, usb_vbus_en1_pl5, gp_pwm6_pl6, + gp_pwm7_pl7, dmic1_dat_pm0, dmic1_clk_pm1, + dmic2_dat_pm2, dmic2_clk_pm3, dmic4_dat_pm4, + dmic4_clk_pm5, gpio_cam1_pn0, gpio_cam2_pn1, + gpio_cam3_pn2, gpio_cam4_pn3, gpio_cam6_pn5, + gpio_cam7_pn6, extperiph1_clk_po0, + extperiph2_clk_po1, cam_i2c_scl_po2, cam_i2c_sda_po3, + dp_aux_ch0_hpd_pp0, dp_aux_ch1_hpd_pp1, hdmi_cec_pp2, + gpio_edp0_pp3, gpio_edp1_pp4, gpio_edp2_pp5, + gpio_edp3_pp6, directdc1_clk_pq0, directdc1_in_pq1, + directdc1_out0_pq2, directdc1_out1_pq3, + directdc1_out2_pq4, directdc1_out3_pq5, + qspi_sck_pr0, qspi_io0_pr1, qspi_io1_pr2, + qspi_io2_pr3, qspi_io3_pr4, qspi_cs_n_pr5, + uart1_tx_pt0, uart1_rx_pt1, uart1_rts_pt2, + uart1_cts_pt3, uart2_tx_px0, uart2_rx_px1, + uart2_rts_px2, uart2_cts_px3, uart5_tx_px4, + uart5_rx_px5, uart5_rts_px6, uart5_cts_px7, + gpio_mdm1_py0, gpio_mdm2_py1, gpio_mdm3_py2, + gpio_mdm4_py3, gpio_mdm5_py4, gpio_mdm6_py5, + gpio_mdm7_py6, ufs0_ref_clk_pbb0, ufs0_rst_pbb1, + dap4_sclk_pcc0, dap4_dout_pcc1, dap4_din_pcc2, + dap4_fs_pcc3, directdc_comp, sdmmc1_comp, eqos_comp, + sdmmc3_comp, qspi_comp, + # drive groups + drive_gpio_aud3_pk0, drive_gpio_aud2_pj7, + drive_gpio_aud1_pj6, drive_gpio_aud0_pj5, + drive_aud_mclk_pj4, drive_dap1_fs_pj3, + drive_dap1_din_pj2, drive_dap1_dout_pj1, + drive_dap1_sclk_pj0, drive_dmic1_clk_pm1, + drive_dmic1_dat_pm0, drive_dmic2_dat_pm2, + drive_dmic2_clk_pm3, drive_dmic4_dat_pm4, + drive_dmic4_clk_pm5, drive_dap4_fs_pcc3, + drive_dap4_din_pcc2, drive_dap4_dout_pcc1, + drive_dap4_sclk_pcc0, drive_extperiph2_clk_po1, + drive_extperiph1_clk_po0, drive_cam_i2c_sda_po3, + drive_cam_i2c_scl_po2, drive_gpio_cam1_pn0, + drive_gpio_cam2_pn1, drive_gpio_cam3_pn2, + drive_gpio_cam4_pn3, drive_gpio_cam5_pn4, + drive_gpio_cam6_pn5, drive_gpio_cam7_pn6, + drive_dap2_din_pc3, drive_dap2_dout_pc2, + drive_dap2_fs_pc4, drive_dap2_sclk_pc1, + drive_uart4_cts_pb3, drive_uart4_rts_pb2, + drive_uart4_rx_pb1, drive_uart4_tx_pb0, + drive_gpio_wan4_pc0, drive_gpio_wan3_pb6, + drive_gpio_wan2_pb5, drive_gpio_wan1_pb4, + drive_gen1_i2c_scl_pc5, drive_gen1_i2c_sda_pc6, + drive_uart1_cts_pt3, drive_uart1_rts_pt2, + drive_uart1_rx_pt1, drive_uart1_tx_pt0, + drive_directdc1_out3_pq5, drive_directdc1_out2_pq4, + drive_directdc1_out1_pq3, drive_directdc1_out0_pq2, + drive_directdc1_in_pq1, drive_directdc1_clk_pq0, + drive_gpio_pq0_pi0, drive_gpio_pq1_pi1, + drive_gpio_pq2_pi2, drive_gpio_pq3_pi3, + drive_gpio_pq4_pi4, drive_gpio_pq5_pi5, + drive_gpio_pq6_pi6, drive_gpio_pq7_pi7, + drive_gpio_edp2_pp5, drive_gpio_edp3_pp6, + drive_gpio_edp0_pp3, drive_gpio_edp1_pp4, + drive_dp_aux_ch0_hpd_pp0, drive_dp_aux_ch1_hpd_pp1, + drive_hdmi_cec_pp2, drive_pex_l2_clkreq_n_pa6, + drive_pex_wake_n_pa2, drive_pex_l1_clkreq_n_pa4, + drive_pex_l1_rst_n_pa3, drive_pex_l0_clkreq_n_pa1, + drive_pex_l0_rst_n_pa0, drive_pex_l2_rst_n_pa5, + drive_sdmmc1_clk_pd0, drive_sdmmc1_cmd_pd1, + drive_sdmmc1_dat3_pd5, drive_sdmmc1_dat2_pd4, + drive_sdmmc1_dat1_pd3, drive_sdmmc1_dat0_pd2, + drive_eqos_td3_pe4, drive_eqos_td2_pe3, + drive_eqos_td1_pe2, drive_eqos_td0_pe1, + drive_eqos_rd3_pf1, drive_eqos_rd2_pf0, + drive_eqos_rd1_pe7, drive_eqos_mdio_pf4, + drive_eqos_rd0_pe6, drive_eqos_mdc_pf5, + drive_eqos_txc_pe0, drive_eqos_rxc_pf3, + drive_eqos_tx_ctl_pe5, drive_eqos_rx_ctl_pf2, + drive_sdmmc3_dat3_pg5, drive_sdmmc3_dat2_pg4, + drive_sdmmc3_dat1_pg3, drive_sdmmc3_dat0_pg2, + drive_sdmmc3_cmd_pg1, drive_sdmmc3_clk_pg0, + drive_qspi_io3_pr4, drive_qspi_io2_pr3, + drive_qspi_io1_pr2, drive_qspi_io0_pr1, + drive_qspi_sck_pr0, drive_qspi_cs_n_pr5, + drive_gpio_wan8_ph3, drive_gpio_wan7_ph2, + drive_gpio_wan6_ph1, drive_gpio_wan5_ph0, + drive_uart2_tx_px0, drive_uart2_rx_px1, + drive_uart2_rts_px2, drive_uart2_cts_px3, + drive_uart5_rx_px5, drive_uart5_tx_px4, + drive_uart5_rts_px6, drive_uart5_cts_px7, + drive_gpio_mdm1_py0, drive_gpio_mdm2_py1, + drive_gpio_mdm3_py2, drive_gpio_mdm4_py3, + drive_gpio_mdm5_py4, drive_gpio_mdm6_py5, + drive_gpio_mdm7_py6, drive_bcpu_pwr_req_ph4, + drive_mcpu_pwr_req_ph5, drive_gpu_pwr_req_ph6, + drive_gen7_i2c_scl_pl0, drive_gen7_i2c_sda_pl1, + drive_gen9_i2c_sda_pl3, drive_gen9_i2c_scl_pl2, + drive_usb_vbus_en0_pl4, drive_usb_vbus_en1_pl5, + drive_gp_pwm7_pl7, drive_gp_pwm6_pl6, + drive_ufs0_rst_pbb1, drive_ufs0_ref_clk_pbb0, + drive_directdc_comp, drive_sdmmc1_comp, + drive_eqos_comp, drive_sdmmc3_comp, drive_sdmmc4_clk, + drive_sdmmc4_cmd, drive_sdmmc4_dqs, + drive_sdmmc4_dat7, drive_sdmmc4_dat6, + drive_sdmmc4_dat5, drive_sdmmc4_dat4, + drive_sdmmc4_dat3, drive_sdmmc4_dat2, + drive_sdmmc4_dat1, drive_sdmmc4_dat0, + drive_qspi_comp ] + + - if: + properties: + compatible: + const: nvidia,tegra186-pinmux-aon + then: + patternProperties: + "^pinmux(-[a-z0-9-]+)?$": + type: object + additionalProperties: + properties: + nvidia,pins: + items: + enum: [ pwr_i2c_scl_ps0, pwr_i2c_sda_ps1, batt_oc_ps2, + safe_state_ps3, vcomp_alert_ps4, gpio_dis0_pu0, + gpio_dis1_pu1, gpio_dis2_pu2, gpio_dis3_pu3, + gpio_dis4_pu4, gpio_dis5_pu5, gpio_sen0_pv0, + gpio_sen1_pv1, gpio_sen2_pv2, gpio_sen3_pv3, + gpio_sen4_pv4, gpio_sen5_pv5, gpio_sen6_pv6, + gpio_sen7_pv7, gen8_i2c_scl_pw0, gen8_i2c_sda_pw1, + uart3_tx_pw2, uart3_rx_pw3, uart3_rts_pw4, + uart3_cts_pw5, uart7_tx_pw6, uart7_rx_pw7, + can1_dout_pz0, can1_din_pz1, can0_dout_pz2, + can0_din_pz3, can_gpio0_paa0, can_gpio1_paa1, + can_gpio2_paa2, can_gpio3_paa3, can_gpio4_paa4, + can_gpio5_paa5, can_gpio6_paa6, can_gpio7_paa7, + gpio_sen8_pee0, gpio_sen9_pee1, touch_clk_pee2, + power_on_pff0, gpio_sw1_pff1, gpio_sw2_pff2, + gpio_sw3_pff3, gpio_sw4_pff4, shutdown, pmu_int, + soc_pwr_req, clk_32k_in, + # drive groups + drive_touch_clk_pee2, drive_uart3_cts_pw5, + drive_uart3_rts_pw4, drive_uart3_rx_pw3, + drive_uart3_tx_pw2, drive_gen8_i2c_sda_pw1, + drive_gen8_i2c_scl_pw0, drive_uart7_rx_pw7, + drive_uart7_tx_pw6, drive_gpio_sen0_pv0, + drive_gpio_sen1_pv1, drive_gpio_sen2_pv2, + drive_gpio_sen3_pv3, drive_gpio_sen4_pv4, + drive_gpio_sen5_pv5, drive_gpio_sen6_pv6, + drive_gpio_sen7_pv7, drive_gpio_sen8_pee0, + drive_gpio_sen9_pee1, drive_can_gpio7_paa7, + drive_can1_dout_pz0, drive_can1_din_pz1, + drive_can0_dout_pz2, drive_can0_din_pz3, + drive_can_gpio0_paa0, drive_can_gpio1_paa1, + drive_can_gpio2_paa2, drive_can_gpio3_paa3, + drive_can_gpio4_paa4, drive_can_gpio5_paa5, + drive_can_gpio6_paa6, drive_gpio_sw1_pff1, + drive_gpio_sw2_pff2, drive_gpio_sw3_pff3, + drive_gpio_sw4_pff4, drive_shutdown, drive_pmu_int, + drive_safe_state_ps3, drive_vcomp_alert_ps4, + drive_soc_pwr_req, drive_batt_oc_ps2, + drive_clk_32k_in, drive_power_on_pff0, + drive_pwr_i2c_scl_ps0, drive_pwr_i2c_sda_ps1, + drive_gpio_dis0_pu0, drive_gpio_dis1_pu1, + drive_gpio_dis2_pu2, drive_gpio_dis3_pu3, + drive_gpio_dis4_pu4, drive_gpio_dis5_pu5 ] + +required: + - compatible + - reg + +examples: + - | + #include + + pinmux@2430000 { + compatible = "nvidia,tegra186-pinmux"; + reg = <0x2430000 0x15000>; + + pinctrl-names = "jetson_io"; + pinctrl-0 = <&jetson_io_pinmux>; + + jetson_io_pinmux: pinmux { + hdr40-pin7 { + nvidia,pins = "aud_mclk_pj4"; + nvidia,function = "aud"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + }; + }; + }; +... From eed8e4c07d85c8955a44502bc1f61e4155c94051 Mon Sep 17 00:00:00 2001 From: Shankari Anand Date: Thu, 14 Aug 2025 15:31:01 +0530 Subject: [PATCH 01371/11391] rust: fs: update ARef and AlwaysRefCounted imports from sync::aref Update call sites in the fs subsystem to import `ARef` and `AlwaysRefCounted` from `sync::aref` instead of `types`. This aligns with the ongoing effort to move `ARef` and `AlwaysRefCounted` to sync. Suggested-by: Benno Lossin Link: https://github.com/Rust-for-Linux/linux/issues/1173 Acked-by: Alice Ryhl Signed-off-by: Shankari Anand Link: https://lore.kernel.org/20250814100101.304408-1-shankari.ak0208@gmail.com Signed-off-by: Christian Brauner --- rust/kernel/fs/file.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rust/kernel/fs/file.rs b/rust/kernel/fs/file.rs index 35fd5db35c46..18cf579d3312 100644 --- a/rust/kernel/fs/file.rs +++ b/rust/kernel/fs/file.rs @@ -11,7 +11,8 @@ bindings, cred::Credential, error::{code::*, Error, Result}, - types::{ARef, AlwaysRefCounted, NotThreadSafe, Opaque}, + sync::aref::{ARef, AlwaysRefCounted}, + types::{NotThreadSafe, Opaque}, }; use core::ptr; From 542baf77f092b435ddd2b340e82dbb7b14559d56 Mon Sep 17 00:00:00 2001 From: Aaron Kling Date: Tue, 12 Aug 2025 16:24:41 -0500 Subject: [PATCH 01372/11391] pinctrl: tegra: Add Tegra186 pinmux driver This is based on Nvidia's downstream 5.10 driver, rewritten to match the mainline Tegra194 pinmux driver. Signed-off-by: Aaron Kling Link: https://lore.kernel.org/20250812-tegra186-pinctrl-v3-2-115714eeecb1@gmail.com Signed-off-by: Linus Walleij --- drivers/pinctrl/tegra/Kconfig | 4 + drivers/pinctrl/tegra/Makefile | 1 + drivers/pinctrl/tegra/pinctrl-tegra186.c | 1979 ++++++++++++++++++++++ drivers/soc/tegra/Kconfig | 1 + 4 files changed, 1985 insertions(+) create mode 100644 drivers/pinctrl/tegra/pinctrl-tegra186.c diff --git a/drivers/pinctrl/tegra/Kconfig b/drivers/pinctrl/tegra/Kconfig index 4e87d19323ba..660d101ea367 100644 --- a/drivers/pinctrl/tegra/Kconfig +++ b/drivers/pinctrl/tegra/Kconfig @@ -24,6 +24,10 @@ config PINCTRL_TEGRA210 bool select PINCTRL_TEGRA +config PINCTRL_TEGRA186 + bool + select PINCTRL_TEGRA + config PINCTRL_TEGRA194 bool select PINCTRL_TEGRA diff --git a/drivers/pinctrl/tegra/Makefile b/drivers/pinctrl/tegra/Makefile index a93973701d4c..82176526549e 100644 --- a/drivers/pinctrl/tegra/Makefile +++ b/drivers/pinctrl/tegra/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o obj-$(CONFIG_PINCTRL_TEGRA114) += pinctrl-tegra114.o obj-$(CONFIG_PINCTRL_TEGRA124) += pinctrl-tegra124.o obj-$(CONFIG_PINCTRL_TEGRA210) += pinctrl-tegra210.o +obj-$(CONFIG_PINCTRL_TEGRA186) += pinctrl-tegra186.o obj-$(CONFIG_PINCTRL_TEGRA194) += pinctrl-tegra194.o obj-$(CONFIG_PINCTRL_TEGRA234) += pinctrl-tegra234.o obj-$(CONFIG_PINCTRL_TEGRA_XUSB) += pinctrl-tegra-xusb.o diff --git a/drivers/pinctrl/tegra/pinctrl-tegra186.c b/drivers/pinctrl/tegra/pinctrl-tegra186.c new file mode 100644 index 000000000000..4a1d6476af9b --- /dev/null +++ b/drivers/pinctrl/tegra/pinctrl-tegra186.c @@ -0,0 +1,1979 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Pinctrl data for the NVIDIA Tegra186 pinmux + * + * Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + */ + +#include +#include +#include +#include +#include + +#include "pinctrl-tegra.h" + +/* Define unique ID for each pins */ +enum { + TEGRA_PIN_PEX_L0_RST_N_PA0, + TEGRA_PIN_PEX_L0_CLKREQ_N_PA1, + TEGRA_PIN_PEX_WAKE_N_PA2, + TEGRA_PIN_PEX_L1_RST_N_PA3, + TEGRA_PIN_PEX_L1_CLKREQ_N_PA4, + TEGRA_PIN_PEX_L2_RST_N_PA5, + TEGRA_PIN_PEX_L2_CLKREQ_N_PA6, + TEGRA_PIN_UART4_TX_PB0, + TEGRA_PIN_UART4_RX_PB1, + TEGRA_PIN_UART4_RTS_PB2, + TEGRA_PIN_UART4_CTS_PB3, + TEGRA_PIN_GPIO_WAN1_PB4, + TEGRA_PIN_GPIO_WAN2_PB5, + TEGRA_PIN_GPIO_WAN3_PB6, + TEGRA_PIN_GPIO_WAN4_PC0, + TEGRA_PIN_DAP2_SCLK_PC1, + TEGRA_PIN_DAP2_DOUT_PC2, + TEGRA_PIN_DAP2_DIN_PC3, + TEGRA_PIN_DAP2_FS_PC4, + TEGRA_PIN_GEN1_I2C_SCL_PC5, + TEGRA_PIN_GEN1_I2C_SDA_PC6, + TEGRA_PIN_SDMMC1_CLK_PD0, + TEGRA_PIN_SDMMC1_CMD_PD1, + TEGRA_PIN_SDMMC1_DAT0_PD2, + TEGRA_PIN_SDMMC1_DAT1_PD3, + TEGRA_PIN_SDMMC1_DAT2_PD4, + TEGRA_PIN_SDMMC1_DAT3_PD5, + TEGRA_PIN_EQOS_TXC_PE0, + TEGRA_PIN_EQOS_TD0_PE1, + TEGRA_PIN_EQOS_TD1_PE2, + TEGRA_PIN_EQOS_TD2_PE3, + TEGRA_PIN_EQOS_TD3_PE4, + TEGRA_PIN_EQOS_TX_CTL_PE5, + TEGRA_PIN_EQOS_RD0_PE6, + TEGRA_PIN_EQOS_RD1_PE7, + TEGRA_PIN_EQOS_RD2_PF0, + TEGRA_PIN_EQOS_RD3_PF1, + TEGRA_PIN_EQOS_RX_CTL_PF2, + TEGRA_PIN_EQOS_RXC_PF3, + TEGRA_PIN_EQOS_MDIO_PF4, + TEGRA_PIN_EQOS_MDC_PF5, + TEGRA_PIN_SDMMC3_CLK_PG0, + TEGRA_PIN_SDMMC3_CMD_PG1, + TEGRA_PIN_SDMMC3_DAT0_PG2, + TEGRA_PIN_SDMMC3_DAT1_PG3, + TEGRA_PIN_SDMMC3_DAT2_PG4, + TEGRA_PIN_SDMMC3_DAT3_PG5, + TEGRA_PIN_GPIO_WAN5_PH0, + TEGRA_PIN_GPIO_WAN6_PH1, + TEGRA_PIN_GPIO_WAN7_PH2, + TEGRA_PIN_GPIO_WAN8_PH3, + TEGRA_PIN_BCPU_PWR_REQ_PH4, + TEGRA_PIN_MCPU_PWR_REQ_PH5, + TEGRA_PIN_GPU_PWR_REQ_PH6, + TEGRA_PIN_GPIO_PQ0_PI0, + TEGRA_PIN_GPIO_PQ1_PI1, + TEGRA_PIN_GPIO_PQ2_PI2, + TEGRA_PIN_GPIO_PQ3_PI3, + TEGRA_PIN_GPIO_PQ4_PI4, + TEGRA_PIN_GPIO_PQ5_PI5, + TEGRA_PIN_GPIO_PQ6_PI6, + TEGRA_PIN_GPIO_PQ7_PI7, + TEGRA_PIN_DAP1_SCLK_PJ0, + TEGRA_PIN_DAP1_DOUT_PJ1, + TEGRA_PIN_DAP1_DIN_PJ2, + TEGRA_PIN_DAP1_FS_PJ3, + TEGRA_PIN_AUD_MCLK_PJ4, + TEGRA_PIN_GPIO_AUD0_PJ5, + TEGRA_PIN_GPIO_AUD1_PJ6, + TEGRA_PIN_GPIO_AUD2_PJ7, + TEGRA_PIN_GPIO_AUD3_PK0, + TEGRA_PIN_GEN7_I2C_SCL_PL0, + TEGRA_PIN_GEN7_I2C_SDA_PL1, + TEGRA_PIN_GEN9_I2C_SCL_PL2, + TEGRA_PIN_GEN9_I2C_SDA_PL3, + TEGRA_PIN_USB_VBUS_EN0_PL4, + TEGRA_PIN_USB_VBUS_EN1_PL5, + TEGRA_PIN_GP_PWM6_PL6, + TEGRA_PIN_GP_PWM7_PL7, + TEGRA_PIN_DMIC1_DAT_PM0, + TEGRA_PIN_DMIC1_CLK_PM1, + TEGRA_PIN_DMIC2_DAT_PM2, + TEGRA_PIN_DMIC2_CLK_PM3, + TEGRA_PIN_DMIC4_DAT_PM4, + TEGRA_PIN_DMIC4_CLK_PM5, + TEGRA_PIN_GPIO_CAM1_PN0, + TEGRA_PIN_GPIO_CAM2_PN1, + TEGRA_PIN_GPIO_CAM3_PN2, + TEGRA_PIN_GPIO_CAM4_PN3, + TEGRA_PIN_GPIO_CAM5_PN4, + TEGRA_PIN_GPIO_CAM6_PN5, + TEGRA_PIN_GPIO_CAM7_PN6, + TEGRA_PIN_EXTPERIPH1_CLK_PO0, + TEGRA_PIN_EXTPERIPH2_CLK_PO1, + TEGRA_PIN_CAM_I2C_SCL_PO2, + TEGRA_PIN_CAM_I2C_SDA_PO3, + TEGRA_PIN_DP_AUX_CH0_HPD_PP0, + TEGRA_PIN_DP_AUX_CH1_HPD_PP1, + TEGRA_PIN_HDMI_CEC_PP2, + TEGRA_PIN_GPIO_EDP0_PP3, + TEGRA_PIN_GPIO_EDP1_PP4, + TEGRA_PIN_GPIO_EDP2_PP5, + TEGRA_PIN_GPIO_EDP3_PP6, + TEGRA_PIN_DIRECTDC1_CLK_PQ0, + TEGRA_PIN_DIRECTDC1_IN_PQ1, + TEGRA_PIN_DIRECTDC1_OUT0_PQ2, + TEGRA_PIN_DIRECTDC1_OUT1_PQ3, + TEGRA_PIN_DIRECTDC1_OUT2_PQ4, + TEGRA_PIN_DIRECTDC1_OUT3_PQ5, + TEGRA_PIN_QSPI_SCK_PR0, + TEGRA_PIN_QSPI_IO0_PR1, + TEGRA_PIN_QSPI_IO1_PR2, + TEGRA_PIN_QSPI_IO2_PR3, + TEGRA_PIN_QSPI_IO3_PR4, + TEGRA_PIN_QSPI_CS_N_PR5, + TEGRA_PIN_UART1_TX_PT0, + TEGRA_PIN_UART1_RX_PT1, + TEGRA_PIN_UART1_RTS_PT2, + TEGRA_PIN_UART1_CTS_PT3, + TEGRA_PIN_UART2_TX_PX0, + TEGRA_PIN_UART2_RX_PX1, + TEGRA_PIN_UART2_RTS_PX2, + TEGRA_PIN_UART2_CTS_PX3, + TEGRA_PIN_UART5_TX_PX4, + TEGRA_PIN_UART5_RX_PX5, + TEGRA_PIN_UART5_RTS_PX6, + TEGRA_PIN_UART5_CTS_PX7, + TEGRA_PIN_GPIO_MDM1_PY0, + TEGRA_PIN_GPIO_MDM2_PY1, + TEGRA_PIN_GPIO_MDM3_PY2, + TEGRA_PIN_GPIO_MDM4_PY3, + TEGRA_PIN_GPIO_MDM5_PY4, + TEGRA_PIN_GPIO_MDM6_PY5, + TEGRA_PIN_GPIO_MDM7_PY6, + TEGRA_PIN_UFS0_REF_CLK_PBB0, + TEGRA_PIN_UFS0_RST_PBB1, + TEGRA_PIN_DAP4_SCLK_PCC0, + TEGRA_PIN_DAP4_DOUT_PCC1, + TEGRA_PIN_DAP4_DIN_PCC2, + TEGRA_PIN_DAP4_FS_PCC3, + TEGRA_PIN_DIRECTDC_COMP, + TEGRA_PIN_SDMMC1_COMP, + TEGRA_PIN_EQOS_COMP, + TEGRA_PIN_SDMMC3_COMP, + TEGRA_PIN_QSPI_COMP, +}; + +enum { + TEGRA_PIN_PWR_I2C_SCL_PS0, + TEGRA_PIN_PWR_I2C_SDA_PS1, + TEGRA_PIN_BATT_OC_PS2, + TEGRA_PIN_SAFE_STATE_PS3, + TEGRA_PIN_VCOMP_ALERT_PS4, + TEGRA_PIN_GPIO_DIS0_PU0, + TEGRA_PIN_GPIO_DIS1_PU1, + TEGRA_PIN_GPIO_DIS2_PU2, + TEGRA_PIN_GPIO_DIS3_PU3, + TEGRA_PIN_GPIO_DIS4_PU4, + TEGRA_PIN_GPIO_DIS5_PU5, + TEGRA_PIN_GPIO_SEN0_PV0, + TEGRA_PIN_GPIO_SEN1_PV1, + TEGRA_PIN_GPIO_SEN2_PV2, + TEGRA_PIN_GPIO_SEN3_PV3, + TEGRA_PIN_GPIO_SEN4_PV4, + TEGRA_PIN_GPIO_SEN5_PV5, + TEGRA_PIN_GPIO_SEN6_PV6, + TEGRA_PIN_GPIO_SEN7_PV7, + TEGRA_PIN_GEN8_I2C_SCL_PW0, + TEGRA_PIN_GEN8_I2C_SDA_PW1, + TEGRA_PIN_UART3_TX_PW2, + TEGRA_PIN_UART3_RX_PW3, + TEGRA_PIN_UART3_RTS_PW4, + TEGRA_PIN_UART3_CTS_PW5, + TEGRA_PIN_UART7_TX_PW6, + TEGRA_PIN_UART7_RX_PW7, + TEGRA_PIN_CAN1_DOUT_PZ0, + TEGRA_PIN_CAN1_DIN_PZ1, + TEGRA_PIN_CAN0_DOUT_PZ2, + TEGRA_PIN_CAN0_DIN_PZ3, + TEGRA_PIN_CAN_GPIO0_PAA0, + TEGRA_PIN_CAN_GPIO1_PAA1, + TEGRA_PIN_CAN_GPIO2_PAA2, + TEGRA_PIN_CAN_GPIO3_PAA3, + TEGRA_PIN_CAN_GPIO4_PAA4, + TEGRA_PIN_CAN_GPIO5_PAA5, + TEGRA_PIN_CAN_GPIO6_PAA6, + TEGRA_PIN_CAN_GPIO7_PAA7, + TEGRA_PIN_GPIO_SEN8_PEE0, + TEGRA_PIN_GPIO_SEN9_PEE1, + TEGRA_PIN_TOUCH_CLK_PEE2, + TEGRA_PIN_POWER_ON_PFF0, + TEGRA_PIN_GPIO_SW1_PFF1, + TEGRA_PIN_GPIO_SW2_PFF2, + TEGRA_PIN_GPIO_SW3_PFF3, + TEGRA_PIN_GPIO_SW4_PFF4, + TEGRA_PIN_SHUTDOWN, + TEGRA_PIN_PMU_INT, + TEGRA_PIN_SOC_PWR_REQ, + TEGRA_PIN_CLK_32K_IN, +}; + +/* Table for pin descriptor */ +static const struct pinctrl_pin_desc tegra186_pins[] = { + PINCTRL_PIN(TEGRA_PIN_PEX_L0_RST_N_PA0, "PEX_L0_RST_N_PA0"), + PINCTRL_PIN(TEGRA_PIN_PEX_L0_CLKREQ_N_PA1, "PEX_L0_CLKREQ_N_PA1"), + PINCTRL_PIN(TEGRA_PIN_PEX_WAKE_N_PA2, "PEX_WAKE_N_PA2"), + PINCTRL_PIN(TEGRA_PIN_PEX_L1_RST_N_PA3, "PEX_L1_RST_N_PA3"), + PINCTRL_PIN(TEGRA_PIN_PEX_L1_CLKREQ_N_PA4, "PEX_L1_CLKREQ_N_PA4"), + PINCTRL_PIN(TEGRA_PIN_PEX_L2_RST_N_PA5, "PEX_L2_RST_N_PA5"), + PINCTRL_PIN(TEGRA_PIN_PEX_L2_CLKREQ_N_PA6, "PEX_L2_CLKREQ_N_PA6"), + PINCTRL_PIN(TEGRA_PIN_UART4_TX_PB0, "UART4_TX_PB0"), + PINCTRL_PIN(TEGRA_PIN_UART4_RX_PB1, "UART4_RX_PB1"), + PINCTRL_PIN(TEGRA_PIN_UART4_RTS_PB2, "UART4_RTS_PB2"), + PINCTRL_PIN(TEGRA_PIN_UART4_CTS_PB3, "UART4_CTS_PB3"), + PINCTRL_PIN(TEGRA_PIN_GPIO_WAN1_PB4, "GPIO_WAN1_PB4"), + PINCTRL_PIN(TEGRA_PIN_GPIO_WAN2_PB5, "GPIO_WAN2_PB5"), + PINCTRL_PIN(TEGRA_PIN_GPIO_WAN3_PB6, "GPIO_WAN3_PB6"), + PINCTRL_PIN(TEGRA_PIN_GPIO_WAN4_PC0, "GPIO_WAN4_PC0"), + PINCTRL_PIN(TEGRA_PIN_DAP2_SCLK_PC1, "DAP2_SCLK_PC1"), + PINCTRL_PIN(TEGRA_PIN_DAP2_DOUT_PC2, "DAP2_DOUT_PC2"), + PINCTRL_PIN(TEGRA_PIN_DAP2_DIN_PC3, "DAP2_DIN_PC3"), + PINCTRL_PIN(TEGRA_PIN_DAP2_FS_PC4, "DAP2_FS_PC4"), + PINCTRL_PIN(TEGRA_PIN_GEN1_I2C_SCL_PC5, "GEN1_I2C_SCL_PC5"), + PINCTRL_PIN(TEGRA_PIN_GEN1_I2C_SDA_PC6, "GEN1_I2C_SDA_PC6"), + PINCTRL_PIN(TEGRA_PIN_SDMMC1_CLK_PD0, "SDMMC1_CLK_PD0"), + PINCTRL_PIN(TEGRA_PIN_SDMMC1_CMD_PD1, "SDMMC1_CMD_PD1"), + PINCTRL_PIN(TEGRA_PIN_SDMMC1_DAT0_PD2, "SDMMC1_DAT0_PD2"), + PINCTRL_PIN(TEGRA_PIN_SDMMC1_DAT1_PD3, "SDMMC1_DAT1_PD3"), + PINCTRL_PIN(TEGRA_PIN_SDMMC1_DAT2_PD4, "SDMMC1_DAT2_PD4"), + PINCTRL_PIN(TEGRA_PIN_SDMMC1_DAT3_PD5, "SDMMC1_DAT3_PD5"), + PINCTRL_PIN(TEGRA_PIN_EQOS_TXC_PE0, "EQOS_TXC_PE0"), + PINCTRL_PIN(TEGRA_PIN_EQOS_TD0_PE1, "EQOS_TD0_PE1"), + PINCTRL_PIN(TEGRA_PIN_EQOS_TD1_PE2, "EQOS_TD1_PE2"), + PINCTRL_PIN(TEGRA_PIN_EQOS_TD2_PE3, "EQOS_TD2_PE3"), + PINCTRL_PIN(TEGRA_PIN_EQOS_TD3_PE4, "EQOS_TD3_PE4"), + PINCTRL_PIN(TEGRA_PIN_EQOS_TX_CTL_PE5, "EQOS_TX_CTL_PE5"), + PINCTRL_PIN(TEGRA_PIN_EQOS_RD0_PE6, "EQOS_RD0_PE6"), + PINCTRL_PIN(TEGRA_PIN_EQOS_RD1_PE7, "EQOS_RD1_PE7"), + PINCTRL_PIN(TEGRA_PIN_EQOS_RD2_PF0, "EQOS_RD2_PF0"), + PINCTRL_PIN(TEGRA_PIN_EQOS_RD3_PF1, "EQOS_RD3_PF1"), + PINCTRL_PIN(TEGRA_PIN_EQOS_RX_CTL_PF2, "EQOS_RX_CTL_PF2"), + PINCTRL_PIN(TEGRA_PIN_EQOS_RXC_PF3, "EQOS_RXC_PF3"), + PINCTRL_PIN(TEGRA_PIN_EQOS_MDIO_PF4, "EQOS_MDIO_PF4"), + PINCTRL_PIN(TEGRA_PIN_EQOS_MDC_PF5, "EQOS_MDC_PF5"), + PINCTRL_PIN(TEGRA_PIN_SDMMC3_CLK_PG0, "SDMMC3_CLK_PG0"), + PINCTRL_PIN(TEGRA_PIN_SDMMC3_CMD_PG1, "SDMMC3_CMD_PG1"), + PINCTRL_PIN(TEGRA_PIN_SDMMC3_DAT0_PG2, "SDMMC3_DAT0_PG2"), + PINCTRL_PIN(TEGRA_PIN_SDMMC3_DAT1_PG3, "SDMMC3_DAT1_PG3"), + PINCTRL_PIN(TEGRA_PIN_SDMMC3_DAT2_PG4, "SDMMC3_DAT2_PG4"), + PINCTRL_PIN(TEGRA_PIN_SDMMC3_DAT3_PG5, "SDMMC3_DAT3_PG5"), + PINCTRL_PIN(TEGRA_PIN_GPIO_WAN5_PH0, "GPIO_WAN5_PH0"), + PINCTRL_PIN(TEGRA_PIN_GPIO_WAN6_PH1, "GPIO_WAN6_PH1"), + PINCTRL_PIN(TEGRA_PIN_GPIO_WAN7_PH2, "GPIO_WAN7_PH2"), + PINCTRL_PIN(TEGRA_PIN_GPIO_WAN8_PH3, "GPIO_WAN8_PH3"), + PINCTRL_PIN(TEGRA_PIN_BCPU_PWR_REQ_PH4, "BCPU_PWR_REQ_PH4"), + PINCTRL_PIN(TEGRA_PIN_MCPU_PWR_REQ_PH5, "MCPU_PWR_REQ_PH5"), + PINCTRL_PIN(TEGRA_PIN_GPU_PWR_REQ_PH6, "GPU_PWR_REQ_PH6"), + PINCTRL_PIN(TEGRA_PIN_GPIO_PQ0_PI0, "GPIO_PQ0_PI0"), + PINCTRL_PIN(TEGRA_PIN_GPIO_PQ1_PI1, "GPIO_PQ1_PI1"), + PINCTRL_PIN(TEGRA_PIN_GPIO_PQ2_PI2, "GPIO_PQ2_PI2"), + PINCTRL_PIN(TEGRA_PIN_GPIO_PQ3_PI3, "GPIO_PQ3_PI3"), + PINCTRL_PIN(TEGRA_PIN_GPIO_PQ4_PI4, "GPIO_PQ4_PI4"), + PINCTRL_PIN(TEGRA_PIN_GPIO_PQ5_PI5, "GPIO_PQ5_PI5"), + PINCTRL_PIN(TEGRA_PIN_GPIO_PQ6_PI6, "GPIO_PQ6_PI6"), + PINCTRL_PIN(TEGRA_PIN_GPIO_PQ7_PI7, "GPIO_PQ7_PI7"), + PINCTRL_PIN(TEGRA_PIN_DAP1_SCLK_PJ0, "DAP1_SCLK_PJ0"), + PINCTRL_PIN(TEGRA_PIN_DAP1_DOUT_PJ1, "DAP1_DOUT_PJ1"), + PINCTRL_PIN(TEGRA_PIN_DAP1_DIN_PJ2, "DAP1_DIN_PJ2"), + PINCTRL_PIN(TEGRA_PIN_DAP1_FS_PJ3, "DAP1_FS_PJ3"), + PINCTRL_PIN(TEGRA_PIN_AUD_MCLK_PJ4, "AUD_MCLK_PJ4"), + PINCTRL_PIN(TEGRA_PIN_GPIO_AUD0_PJ5, "GPIO_AUD0_PJ5"), + PINCTRL_PIN(TEGRA_PIN_GPIO_AUD1_PJ6, "GPIO_AUD1_PJ6"), + PINCTRL_PIN(TEGRA_PIN_GPIO_AUD2_PJ7, "GPIO_AUD2_PJ7"), + PINCTRL_PIN(TEGRA_PIN_GPIO_AUD3_PK0, "GPIO_AUD3_PK0"), + PINCTRL_PIN(TEGRA_PIN_GEN7_I2C_SCL_PL0, "GEN7_I2C_SCL_PL0"), + PINCTRL_PIN(TEGRA_PIN_GEN7_I2C_SDA_PL1, "GEN7_I2C_SDA_PL1"), + PINCTRL_PIN(TEGRA_PIN_GEN9_I2C_SCL_PL2, "GEN9_I2C_SCL_PL2"), + PINCTRL_PIN(TEGRA_PIN_GEN9_I2C_SDA_PL3, "GEN9_I2C_SDA_PL3"), + PINCTRL_PIN(TEGRA_PIN_USB_VBUS_EN0_PL4, "USB_VBUS_EN0_PL4"), + PINCTRL_PIN(TEGRA_PIN_USB_VBUS_EN1_PL5, "USB_VBUS_EN1_PL5"), + PINCTRL_PIN(TEGRA_PIN_GP_PWM6_PL6, "GP_PWM6_PL6"), + PINCTRL_PIN(TEGRA_PIN_GP_PWM7_PL7, "GP_PWM7_PL7"), + PINCTRL_PIN(TEGRA_PIN_DMIC1_DAT_PM0, "DMIC1_DAT_PM0"), + PINCTRL_PIN(TEGRA_PIN_DMIC1_CLK_PM1, "DMIC1_CLK_PM1"), + PINCTRL_PIN(TEGRA_PIN_DMIC2_DAT_PM2, "DMIC2_DAT_PM2"), + PINCTRL_PIN(TEGRA_PIN_DMIC2_CLK_PM3, "DMIC2_CLK_PM3"), + PINCTRL_PIN(TEGRA_PIN_DMIC4_DAT_PM4, "DMIC4_DAT_PM4"), + PINCTRL_PIN(TEGRA_PIN_DMIC4_CLK_PM5, "DMIC4_CLK_PM5"), + PINCTRL_PIN(TEGRA_PIN_GPIO_CAM1_PN0, "GPIO_CAM1_PN0"), + PINCTRL_PIN(TEGRA_PIN_GPIO_CAM2_PN1, "GPIO_CAM2_PN1"), + PINCTRL_PIN(TEGRA_PIN_GPIO_CAM3_PN2, "GPIO_CAM3_PN2"), + PINCTRL_PIN(TEGRA_PIN_GPIO_CAM4_PN3, "GPIO_CAM4_PN3"), + PINCTRL_PIN(TEGRA_PIN_GPIO_CAM5_PN4, "GPIO_CAM6_PN5"), + PINCTRL_PIN(TEGRA_PIN_GPIO_CAM6_PN5, "GPIO_CAM6_PN5"), + PINCTRL_PIN(TEGRA_PIN_GPIO_CAM7_PN6, "GPIO_CAM7_PN6"), + PINCTRL_PIN(TEGRA_PIN_EXTPERIPH1_CLK_PO0, "EXTPERIPH1_CLK_PO0"), + PINCTRL_PIN(TEGRA_PIN_EXTPERIPH2_CLK_PO1, "EXTPERIPH2_CLK_PO1"), + PINCTRL_PIN(TEGRA_PIN_CAM_I2C_SCL_PO2, "CAM_I2C_SCL_PO2"), + PINCTRL_PIN(TEGRA_PIN_CAM_I2C_SDA_PO3, "CAM_I2C_SDA_PO3"), + PINCTRL_PIN(TEGRA_PIN_DP_AUX_CH0_HPD_PP0, "DP_AUX_CH0_HPD_PP0"), + PINCTRL_PIN(TEGRA_PIN_DP_AUX_CH1_HPD_PP1, "DP_AUX_CH1_HPD_PP1"), + PINCTRL_PIN(TEGRA_PIN_HDMI_CEC_PP2, "HDMI_CEC_PP2"), + PINCTRL_PIN(TEGRA_PIN_GPIO_EDP0_PP3, "GPIO_EDP0_PP3"), + PINCTRL_PIN(TEGRA_PIN_GPIO_EDP1_PP4, "GPIO_EDP1_PP4"), + PINCTRL_PIN(TEGRA_PIN_GPIO_EDP2_PP5, "GPIO_EDP2_PP5"), + PINCTRL_PIN(TEGRA_PIN_GPIO_EDP3_PP6, "GPIO_EDP3_PP6"), + PINCTRL_PIN(TEGRA_PIN_DIRECTDC1_CLK_PQ0, "DIRECTDC1_CLK_PQ0"), + PINCTRL_PIN(TEGRA_PIN_DIRECTDC1_IN_PQ1, "DIRECTDC1_IN_PQ1"), + PINCTRL_PIN(TEGRA_PIN_DIRECTDC1_OUT0_PQ2, "DIRECTDC1_OUT0_PQ2"), + PINCTRL_PIN(TEGRA_PIN_DIRECTDC1_OUT1_PQ3, "DIRECTDC1_OUT1_PQ3"), + PINCTRL_PIN(TEGRA_PIN_DIRECTDC1_OUT2_PQ4, "DIRECTDC1_OUT2_PQ4"), + PINCTRL_PIN(TEGRA_PIN_DIRECTDC1_OUT3_PQ5, "DIRECTDC1_OUT3_PQ5"), + PINCTRL_PIN(TEGRA_PIN_QSPI_SCK_PR0, "QSPI_SCK_PR0"), + PINCTRL_PIN(TEGRA_PIN_QSPI_IO0_PR1, "QSPI_IO0_PR1"), + PINCTRL_PIN(TEGRA_PIN_QSPI_IO1_PR2, "QSPI_IO1_PR2"), + PINCTRL_PIN(TEGRA_PIN_QSPI_IO2_PR3, "QSPI_IO2_PR3"), + PINCTRL_PIN(TEGRA_PIN_QSPI_IO3_PR4, "QSPI_IO3_PR4"), + PINCTRL_PIN(TEGRA_PIN_QSPI_CS_N_PR5, "QSPI_CS_N_PR5"), + PINCTRL_PIN(TEGRA_PIN_UART1_TX_PT0, "UART1_TX_PT0"), + PINCTRL_PIN(TEGRA_PIN_UART1_RX_PT1, "UART1_RX_PT1"), + PINCTRL_PIN(TEGRA_PIN_UART1_RTS_PT2, "UART1_RTS_PT2"), + PINCTRL_PIN(TEGRA_PIN_UART1_CTS_PT3, "UART1_CTS_PT3"), + PINCTRL_PIN(TEGRA_PIN_UART2_TX_PX0, "UART2_TX_PX0"), + PINCTRL_PIN(TEGRA_PIN_UART2_RX_PX1, "UART2_RX_PX1"), + PINCTRL_PIN(TEGRA_PIN_UART2_RTS_PX2, "UART2_RTS_PX2"), + PINCTRL_PIN(TEGRA_PIN_UART2_CTS_PX3, "UART2_CTS_PX3"), + PINCTRL_PIN(TEGRA_PIN_UART5_TX_PX4, "UART5_TX_PX4"), + PINCTRL_PIN(TEGRA_PIN_UART5_RX_PX5, "UART5_RX_PX5"), + PINCTRL_PIN(TEGRA_PIN_UART5_RTS_PX6, "UART5_RTS_PX6"), + PINCTRL_PIN(TEGRA_PIN_UART5_CTS_PX7, "UART5_CTS_PX7"), + PINCTRL_PIN(TEGRA_PIN_GPIO_MDM1_PY0, "GPIO_MDM1_PY0"), + PINCTRL_PIN(TEGRA_PIN_GPIO_MDM2_PY1, "GPIO_MDM2_PY1"), + PINCTRL_PIN(TEGRA_PIN_GPIO_MDM3_PY2, "GPIO_MDM3_PY2"), + PINCTRL_PIN(TEGRA_PIN_GPIO_MDM4_PY3, "GPIO_MDM4_PY3"), + PINCTRL_PIN(TEGRA_PIN_GPIO_MDM5_PY4, "GPIO_MDM5_PY4"), + PINCTRL_PIN(TEGRA_PIN_GPIO_MDM6_PY5, "GPIO_MDM6_PY5"), + PINCTRL_PIN(TEGRA_PIN_GPIO_MDM7_PY6, "GPIO_MDM7_PY6"), + PINCTRL_PIN(TEGRA_PIN_UFS0_REF_CLK_PBB0, "UFS0_REF_CLK_PBB0"), + PINCTRL_PIN(TEGRA_PIN_UFS0_RST_PBB1, "UFS0_RST_PBB1"), + PINCTRL_PIN(TEGRA_PIN_DAP4_SCLK_PCC0, "DAP4_SCLK_PCC0"), + PINCTRL_PIN(TEGRA_PIN_DAP4_DOUT_PCC1, "DAP4_DOUT_PCC1"), + PINCTRL_PIN(TEGRA_PIN_DAP4_DIN_PCC2, "DAP4_DIN_PCC2"), + PINCTRL_PIN(TEGRA_PIN_DAP4_FS_PCC3, "DAP4_FS_PCC3"), + PINCTRL_PIN(TEGRA_PIN_DIRECTDC_COMP, "DIRECTDC_COMP"), + PINCTRL_PIN(TEGRA_PIN_SDMMC1_COMP, "SDMMC1_COMP"), + PINCTRL_PIN(TEGRA_PIN_EQOS_COMP, "EQOS_COMP"), + PINCTRL_PIN(TEGRA_PIN_SDMMC3_COMP, "SDMMC3_COMP"), + PINCTRL_PIN(TEGRA_PIN_QSPI_COMP, "QSPI_COMP"), +}; + +static const unsigned int pex_l0_rst_n_pa0_pins[] = { + TEGRA_PIN_PEX_L0_RST_N_PA0, +}; + +static const unsigned int pex_l0_clkreq_n_pa1_pins[] = { + TEGRA_PIN_PEX_L0_CLKREQ_N_PA1, +}; + +static const unsigned int pex_wake_n_pa2_pins[] = { + TEGRA_PIN_PEX_WAKE_N_PA2, +}; + +static const unsigned int pex_l1_rst_n_pa3_pins[] = { + TEGRA_PIN_PEX_L1_RST_N_PA3, +}; + +static const unsigned int pex_l1_clkreq_n_pa4_pins[] = { + TEGRA_PIN_PEX_L1_CLKREQ_N_PA4, +}; + +static const unsigned int pex_l2_rst_n_pa5_pins[] = { + TEGRA_PIN_PEX_L2_RST_N_PA5, +}; + +static const unsigned int pex_l2_clkreq_n_pa6_pins[] = { + TEGRA_PIN_PEX_L2_CLKREQ_N_PA6, +}; + +static const unsigned int uart4_tx_pb0_pins[] = { + TEGRA_PIN_UART4_TX_PB0, +}; + +static const unsigned int uart4_rx_pb1_pins[] = { + TEGRA_PIN_UART4_RX_PB1, +}; + +static const unsigned int uart4_rts_pb2_pins[] = { + TEGRA_PIN_UART4_RTS_PB2, +}; + +static const unsigned int uart4_cts_pb3_pins[] = { + TEGRA_PIN_UART4_CTS_PB3, +}; + +static const unsigned int gpio_wan1_pb4_pins[] = { + TEGRA_PIN_GPIO_WAN1_PB4, +}; + +static const unsigned int gpio_wan2_pb5_pins[] = { + TEGRA_PIN_GPIO_WAN2_PB5, +}; + +static const unsigned int gpio_wan3_pb6_pins[] = { + TEGRA_PIN_GPIO_WAN3_PB6, +}; + +static const unsigned int gpio_wan4_pc0_pins[] = { + TEGRA_PIN_GPIO_WAN4_PC0, +}; + +static const unsigned int dap2_sclk_pc1_pins[] = { + TEGRA_PIN_DAP2_SCLK_PC1, +}; + +static const unsigned int dap2_dout_pc2_pins[] = { + TEGRA_PIN_DAP2_DOUT_PC2, +}; + +static const unsigned int dap2_din_pc3_pins[] = { + TEGRA_PIN_DAP2_DIN_PC3, +}; + +static const unsigned int dap2_fs_pc4_pins[] = { + TEGRA_PIN_DAP2_FS_PC4, +}; + +static const unsigned int gen1_i2c_scl_pc5_pins[] = { + TEGRA_PIN_GEN1_I2C_SCL_PC5, +}; + +static const unsigned int gen1_i2c_sda_pc6_pins[] = { + TEGRA_PIN_GEN1_I2C_SDA_PC6, +}; + +static const unsigned int sdmmc1_clk_pd0_pins[] = { + TEGRA_PIN_SDMMC1_CLK_PD0, +}; + +static const unsigned int sdmmc1_cmd_pd1_pins[] = { + TEGRA_PIN_SDMMC1_CMD_PD1, +}; + +static const unsigned int sdmmc1_dat0_pd2_pins[] = { + TEGRA_PIN_SDMMC1_DAT0_PD2, +}; + +static const unsigned int sdmmc1_dat1_pd3_pins[] = { + TEGRA_PIN_SDMMC1_DAT1_PD3, +}; + +static const unsigned int sdmmc1_dat2_pd4_pins[] = { + TEGRA_PIN_SDMMC1_DAT2_PD4, +}; + +static const unsigned int sdmmc1_dat3_pd5_pins[] = { + TEGRA_PIN_SDMMC1_DAT3_PD5, +}; + +static const unsigned int eqos_txc_pe0_pins[] = { + TEGRA_PIN_EQOS_TXC_PE0, +}; + +static const unsigned int eqos_td0_pe1_pins[] = { + TEGRA_PIN_EQOS_TD0_PE1, +}; + +static const unsigned int eqos_td1_pe2_pins[] = { + TEGRA_PIN_EQOS_TD1_PE2, +}; + +static const unsigned int eqos_td2_pe3_pins[] = { + TEGRA_PIN_EQOS_TD2_PE3, +}; + +static const unsigned int eqos_td3_pe4_pins[] = { + TEGRA_PIN_EQOS_TD3_PE4, +}; + +static const unsigned int eqos_tx_ctl_pe5_pins[] = { + TEGRA_PIN_EQOS_TX_CTL_PE5, +}; + +static const unsigned int eqos_rd0_pe6_pins[] = { + TEGRA_PIN_EQOS_RD0_PE6, +}; + +static const unsigned int eqos_rd1_pe7_pins[] = { + TEGRA_PIN_EQOS_RD1_PE7, +}; + +static const unsigned int eqos_rd2_pf0_pins[] = { + TEGRA_PIN_EQOS_RD2_PF0, +}; + +static const unsigned int eqos_rd3_pf1_pins[] = { + TEGRA_PIN_EQOS_RD3_PF1, +}; + +static const unsigned int eqos_rx_ctl_pf2_pins[] = { + TEGRA_PIN_EQOS_RX_CTL_PF2, +}; + +static const unsigned int eqos_rxc_pf3_pins[] = { + TEGRA_PIN_EQOS_RXC_PF3, +}; + +static const unsigned int eqos_mdio_pf4_pins[] = { + TEGRA_PIN_EQOS_MDIO_PF4, +}; + +static const unsigned int eqos_mdc_pf5_pins[] = { + TEGRA_PIN_EQOS_MDC_PF5, +}; + +static const unsigned int sdmmc3_clk_pg0_pins[] = { + TEGRA_PIN_SDMMC3_CLK_PG0, +}; + +static const unsigned int sdmmc3_cmd_pg1_pins[] = { + TEGRA_PIN_SDMMC3_CMD_PG1, +}; + +static const unsigned int sdmmc3_dat0_pg2_pins[] = { + TEGRA_PIN_SDMMC3_DAT0_PG2, +}; + +static const unsigned int sdmmc3_dat1_pg3_pins[] = { + TEGRA_PIN_SDMMC3_DAT1_PG3, +}; + +static const unsigned int sdmmc3_dat2_pg4_pins[] = { + TEGRA_PIN_SDMMC3_DAT2_PG4, +}; + +static const unsigned int sdmmc3_dat3_pg5_pins[] = { + TEGRA_PIN_SDMMC3_DAT3_PG5, +}; + +static const unsigned int gpio_wan5_ph0_pins[] = { + TEGRA_PIN_GPIO_WAN5_PH0, +}; + +static const unsigned int gpio_wan6_ph1_pins[] = { + TEGRA_PIN_GPIO_WAN6_PH1, +}; + +static const unsigned int gpio_wan7_ph2_pins[] = { + TEGRA_PIN_GPIO_WAN7_PH2, +}; + +static const unsigned int gpio_wan8_ph3_pins[] = { + TEGRA_PIN_GPIO_WAN8_PH3, +}; + +static const unsigned int bcpu_pwr_req_ph4_pins[] = { + TEGRA_PIN_BCPU_PWR_REQ_PH4, +}; + +static const unsigned int mcpu_pwr_req_ph5_pins[] = { + TEGRA_PIN_MCPU_PWR_REQ_PH5, +}; + +static const unsigned int gpu_pwr_req_ph6_pins[] = { + TEGRA_PIN_GPU_PWR_REQ_PH6, +}; + +static const unsigned int gpio_pq0_pi0_pins[] = { + TEGRA_PIN_GPIO_PQ0_PI0, +}; + +static const unsigned int gpio_pq1_pi1_pins[] = { + TEGRA_PIN_GPIO_PQ1_PI1, +}; + +static const unsigned int gpio_pq2_pi2_pins[] = { + TEGRA_PIN_GPIO_PQ2_PI2, +}; + +static const unsigned int gpio_pq3_pi3_pins[] = { + TEGRA_PIN_GPIO_PQ3_PI3, +}; + +static const unsigned int gpio_pq4_pi4_pins[] = { + TEGRA_PIN_GPIO_PQ4_PI4, +}; + +static const unsigned int gpio_pq5_pi5_pins[] = { + TEGRA_PIN_GPIO_PQ5_PI5, +}; + +static const unsigned int gpio_pq6_pi6_pins[] = { + TEGRA_PIN_GPIO_PQ6_PI6, +}; + +static const unsigned int gpio_pq7_pi7_pins[] = { + TEGRA_PIN_GPIO_PQ7_PI7, +}; + +static const unsigned int dap1_sclk_pj0_pins[] = { + TEGRA_PIN_DAP1_SCLK_PJ0, +}; + +static const unsigned int dap1_dout_pj1_pins[] = { + TEGRA_PIN_DAP1_DOUT_PJ1, +}; + +static const unsigned int dap1_din_pj2_pins[] = { + TEGRA_PIN_DAP1_DIN_PJ2, +}; + +static const unsigned int dap1_fs_pj3_pins[] = { + TEGRA_PIN_DAP1_FS_PJ3, +}; + +static const unsigned int aud_mclk_pj4_pins[] = { + TEGRA_PIN_AUD_MCLK_PJ4, +}; + +static const unsigned int gpio_aud0_pj5_pins[] = { + TEGRA_PIN_GPIO_AUD0_PJ5, +}; + +static const unsigned int gpio_aud1_pj6_pins[] = { + TEGRA_PIN_GPIO_AUD1_PJ6, +}; + +static const unsigned int gpio_aud2_pj7_pins[] = { + TEGRA_PIN_GPIO_AUD2_PJ7, +}; + +static const unsigned int gpio_aud3_pk0_pins[] = { + TEGRA_PIN_GPIO_AUD3_PK0, +}; + +static const unsigned int gen7_i2c_scl_pl0_pins[] = { + TEGRA_PIN_GEN7_I2C_SCL_PL0, +}; + +static const unsigned int gen7_i2c_sda_pl1_pins[] = { + TEGRA_PIN_GEN7_I2C_SDA_PL1, +}; + +static const unsigned int gen9_i2c_scl_pl2_pins[] = { + TEGRA_PIN_GEN9_I2C_SCL_PL2, +}; + +static const unsigned int gen9_i2c_sda_pl3_pins[] = { + TEGRA_PIN_GEN9_I2C_SDA_PL3, +}; + +static const unsigned int usb_vbus_en0_pl4_pins[] = { + TEGRA_PIN_USB_VBUS_EN0_PL4, +}; + +static const unsigned int usb_vbus_en1_pl5_pins[] = { + TEGRA_PIN_USB_VBUS_EN1_PL5, +}; + +static const unsigned int gp_pwm6_pl6_pins[] = { + TEGRA_PIN_GP_PWM6_PL6, +}; + +static const unsigned int gp_pwm7_pl7_pins[] = { + TEGRA_PIN_GP_PWM7_PL7, +}; + +static const unsigned int dmic1_dat_pm0_pins[] = { + TEGRA_PIN_DMIC1_DAT_PM0, +}; + +static const unsigned int dmic1_clk_pm1_pins[] = { + TEGRA_PIN_DMIC1_CLK_PM1, +}; + +static const unsigned int dmic2_dat_pm2_pins[] = { + TEGRA_PIN_DMIC2_DAT_PM2, +}; + +static const unsigned int dmic2_clk_pm3_pins[] = { + TEGRA_PIN_DMIC2_CLK_PM3, +}; + +static const unsigned int dmic4_dat_pm4_pins[] = { + TEGRA_PIN_DMIC4_DAT_PM4, +}; + +static const unsigned int dmic4_clk_pm5_pins[] = { + TEGRA_PIN_DMIC4_CLK_PM5, +}; + +static const unsigned int gpio_cam1_pn0_pins[] = { + TEGRA_PIN_GPIO_CAM1_PN0, +}; + +static const unsigned int gpio_cam2_pn1_pins[] = { + TEGRA_PIN_GPIO_CAM2_PN1, +}; + +static const unsigned int gpio_cam3_pn2_pins[] = { + TEGRA_PIN_GPIO_CAM3_PN2, +}; + +static const unsigned int gpio_cam4_pn3_pins[] = { + TEGRA_PIN_GPIO_CAM4_PN3, +}; + +static const unsigned int gpio_cam5_pn4_pins[] = { + TEGRA_PIN_GPIO_CAM5_PN4, +}; + +static const unsigned int gpio_cam6_pn5_pins[] = { + TEGRA_PIN_GPIO_CAM6_PN5, +}; + +static const unsigned int gpio_cam7_pn6_pins[] = { + TEGRA_PIN_GPIO_CAM7_PN6, +}; + +static const unsigned int extperiph1_clk_po0_pins[] = { + TEGRA_PIN_EXTPERIPH1_CLK_PO0, +}; + +static const unsigned int extperiph2_clk_po1_pins[] = { + TEGRA_PIN_EXTPERIPH2_CLK_PO1, +}; + +static const unsigned int cam_i2c_scl_po2_pins[] = { + TEGRA_PIN_CAM_I2C_SCL_PO2, +}; + +static const unsigned int cam_i2c_sda_po3_pins[] = { + TEGRA_PIN_CAM_I2C_SDA_PO3, +}; + +static const unsigned int dp_aux_ch0_hpd_pp0_pins[] = { + TEGRA_PIN_DP_AUX_CH0_HPD_PP0, +}; + +static const unsigned int dp_aux_ch1_hpd_pp1_pins[] = { + TEGRA_PIN_DP_AUX_CH1_HPD_PP1, +}; + +static const unsigned int hdmi_cec_pp2_pins[] = { + TEGRA_PIN_HDMI_CEC_PP2, +}; + +static const unsigned int gpio_edp0_pp3_pins[] = { + TEGRA_PIN_GPIO_EDP0_PP3, +}; + +static const unsigned int gpio_edp1_pp4_pins[] = { + TEGRA_PIN_GPIO_EDP1_PP4, +}; + +static const unsigned int gpio_edp2_pp5_pins[] = { + TEGRA_PIN_GPIO_EDP2_PP5, +}; + +static const unsigned int gpio_edp3_pp6_pins[] = { + TEGRA_PIN_GPIO_EDP3_PP6, +}; + +static const unsigned int directdc1_clk_pq0_pins[] = { + TEGRA_PIN_DIRECTDC1_CLK_PQ0, +}; + +static const unsigned int directdc1_in_pq1_pins[] = { + TEGRA_PIN_DIRECTDC1_IN_PQ1, +}; + +static const unsigned int directdc1_out0_pq2_pins[] = { + TEGRA_PIN_DIRECTDC1_OUT0_PQ2, +}; + +static const unsigned int directdc1_out1_pq3_pins[] = { + TEGRA_PIN_DIRECTDC1_OUT1_PQ3, +}; + +static const unsigned int directdc1_out2_pq4_pins[] = { + TEGRA_PIN_DIRECTDC1_OUT2_PQ4, +}; + +static const unsigned int directdc1_out3_pq5_pins[] = { + TEGRA_PIN_DIRECTDC1_OUT3_PQ5, +}; + +static const unsigned int qspi_sck_pr0_pins[] = { + TEGRA_PIN_QSPI_SCK_PR0, +}; + +static const unsigned int qspi_io0_pr1_pins[] = { + TEGRA_PIN_QSPI_IO0_PR1, +}; + +static const unsigned int qspi_io1_pr2_pins[] = { + TEGRA_PIN_QSPI_IO1_PR2, +}; + +static const unsigned int qspi_io2_pr3_pins[] = { + TEGRA_PIN_QSPI_IO2_PR3, +}; + +static const unsigned int qspi_io3_pr4_pins[] = { + TEGRA_PIN_QSPI_IO3_PR4, +}; + +static const unsigned int qspi_cs_n_pr5_pins[] = { + TEGRA_PIN_QSPI_CS_N_PR5, +}; + +static const unsigned int pwr_i2c_scl_ps0_pins[] = { + TEGRA_PIN_PWR_I2C_SCL_PS0, +}; + +static const unsigned int pwr_i2c_sda_ps1_pins[] = { + TEGRA_PIN_PWR_I2C_SDA_PS1, +}; + +static const unsigned int batt_oc_ps2_pins[] = { + TEGRA_PIN_BATT_OC_PS2, +}; + +static const unsigned int safe_state_ps3_pins[] = { + TEGRA_PIN_SAFE_STATE_PS3, +}; + +static const unsigned int vcomp_alert_ps4_pins[] = { + TEGRA_PIN_VCOMP_ALERT_PS4, +}; + +static const unsigned int uart1_tx_pt0_pins[] = { + TEGRA_PIN_UART1_TX_PT0, +}; + +static const unsigned int uart1_rx_pt1_pins[] = { + TEGRA_PIN_UART1_RX_PT1, +}; + +static const unsigned int uart1_rts_pt2_pins[] = { + TEGRA_PIN_UART1_RTS_PT2, +}; + +static const unsigned int uart1_cts_pt3_pins[] = { + TEGRA_PIN_UART1_CTS_PT3, +}; + +static const unsigned int gpio_dis0_pu0_pins[] = { + TEGRA_PIN_GPIO_DIS0_PU0, +}; + +static const unsigned int gpio_dis1_pu1_pins[] = { + TEGRA_PIN_GPIO_DIS1_PU1, +}; + +static const unsigned int gpio_dis2_pu2_pins[] = { + TEGRA_PIN_GPIO_DIS2_PU2, +}; + +static const unsigned int gpio_dis3_pu3_pins[] = { + TEGRA_PIN_GPIO_DIS3_PU3, +}; + +static const unsigned int gpio_dis4_pu4_pins[] = { + TEGRA_PIN_GPIO_DIS4_PU4, +}; + +static const unsigned int gpio_dis5_pu5_pins[] = { + TEGRA_PIN_GPIO_DIS5_PU5, +}; + +static const unsigned int gpio_sen0_pv0_pins[] = { + TEGRA_PIN_GPIO_SEN0_PV0, +}; + +static const unsigned int gpio_sen1_pv1_pins[] = { + TEGRA_PIN_GPIO_SEN1_PV1, +}; + +static const unsigned int gpio_sen2_pv2_pins[] = { + TEGRA_PIN_GPIO_SEN2_PV2, +}; + +static const unsigned int gpio_sen3_pv3_pins[] = { + TEGRA_PIN_GPIO_SEN3_PV3, +}; + +static const unsigned int gpio_sen4_pv4_pins[] = { + TEGRA_PIN_GPIO_SEN4_PV4, +}; + +static const unsigned int gpio_sen5_pv5_pins[] = { + TEGRA_PIN_GPIO_SEN5_PV5, +}; + +static const unsigned int gpio_sen6_pv6_pins[] = { + TEGRA_PIN_GPIO_SEN6_PV6, +}; + +static const unsigned int gpio_sen7_pv7_pins[] = { + TEGRA_PIN_GPIO_SEN7_PV7, +}; + +static const unsigned int gen8_i2c_scl_pw0_pins[] = { + TEGRA_PIN_GEN8_I2C_SCL_PW0, +}; + +static const unsigned int gen8_i2c_sda_pw1_pins[] = { + TEGRA_PIN_GEN8_I2C_SDA_PW1, +}; + +static const unsigned int uart3_tx_pw2_pins[] = { + TEGRA_PIN_UART3_TX_PW2, +}; + +static const unsigned int uart3_rx_pw3_pins[] = { + TEGRA_PIN_UART3_RX_PW3, +}; + +static const unsigned int uart3_rts_pw4_pins[] = { + TEGRA_PIN_UART3_RTS_PW4, +}; + +static const unsigned int uart3_cts_pw5_pins[] = { + TEGRA_PIN_UART3_CTS_PW5, +}; + +static const unsigned int uart7_tx_pw6_pins[] = { + TEGRA_PIN_UART7_TX_PW6, +}; + +static const unsigned int uart7_rx_pw7_pins[] = { + TEGRA_PIN_UART7_RX_PW7, +}; + +static const unsigned int uart2_tx_px0_pins[] = { + TEGRA_PIN_UART2_TX_PX0, +}; + +static const unsigned int uart2_rx_px1_pins[] = { + TEGRA_PIN_UART2_RX_PX1, +}; + +static const unsigned int uart2_rts_px2_pins[] = { + TEGRA_PIN_UART2_RTS_PX2, +}; + +static const unsigned int uart2_cts_px3_pins[] = { + TEGRA_PIN_UART2_CTS_PX3, +}; + +static const unsigned int uart5_tx_px4_pins[] = { + TEGRA_PIN_UART5_TX_PX4, +}; + +static const unsigned int uart5_rx_px5_pins[] = { + TEGRA_PIN_UART5_RX_PX5, +}; + +static const unsigned int uart5_rts_px6_pins[] = { + TEGRA_PIN_UART5_RTS_PX6, +}; + +static const unsigned int uart5_cts_px7_pins[] = { + TEGRA_PIN_UART5_CTS_PX7, +}; + +static const unsigned int gpio_mdm1_py0_pins[] = { + TEGRA_PIN_GPIO_MDM1_PY0, +}; + +static const unsigned int gpio_mdm2_py1_pins[] = { + TEGRA_PIN_GPIO_MDM2_PY1, +}; + +static const unsigned int gpio_mdm3_py2_pins[] = { + TEGRA_PIN_GPIO_MDM3_PY2, +}; + +static const unsigned int gpio_mdm4_py3_pins[] = { + TEGRA_PIN_GPIO_MDM4_PY3, +}; + +static const unsigned int gpio_mdm5_py4_pins[] = { + TEGRA_PIN_GPIO_MDM5_PY4, +}; + +static const unsigned int gpio_mdm6_py5_pins[] = { + TEGRA_PIN_GPIO_MDM6_PY5, +}; + +static const unsigned int gpio_mdm7_py6_pins[] = { + TEGRA_PIN_GPIO_MDM7_PY6, +}; + +static const unsigned int can1_dout_pz0_pins[] = { + TEGRA_PIN_CAN1_DOUT_PZ0, +}; + +static const unsigned int can1_din_pz1_pins[] = { + TEGRA_PIN_CAN1_DIN_PZ1, +}; + +static const unsigned int can0_dout_pz2_pins[] = { + TEGRA_PIN_CAN0_DOUT_PZ2, +}; + +static const unsigned int can0_din_pz3_pins[] = { + TEGRA_PIN_CAN0_DIN_PZ3, +}; + +static const unsigned int can_gpio0_paa0_pins[] = { + TEGRA_PIN_CAN_GPIO0_PAA0, +}; + +static const unsigned int can_gpio1_paa1_pins[] = { + TEGRA_PIN_CAN_GPIO1_PAA1, +}; + +static const unsigned int can_gpio2_paa2_pins[] = { + TEGRA_PIN_CAN_GPIO2_PAA2, +}; + +static const unsigned int can_gpio3_paa3_pins[] = { + TEGRA_PIN_CAN_GPIO3_PAA3, +}; + +static const unsigned int can_gpio4_paa4_pins[] = { + TEGRA_PIN_CAN_GPIO4_PAA4, +}; + +static const unsigned int can_gpio5_paa5_pins[] = { + TEGRA_PIN_CAN_GPIO5_PAA5, +}; + +static const unsigned int can_gpio6_paa6_pins[] = { + TEGRA_PIN_CAN_GPIO6_PAA6, +}; + +static const unsigned int can_gpio7_paa7_pins[] = { + TEGRA_PIN_CAN_GPIO7_PAA7, +}; + +static const unsigned int ufs0_ref_clk_pbb0_pins[] = { + TEGRA_PIN_UFS0_REF_CLK_PBB0, +}; + +static const unsigned int ufs0_rst_pbb1_pins[] = { + TEGRA_PIN_UFS0_RST_PBB1, +}; + +static const unsigned int dap4_sclk_pcc0_pins[] = { + TEGRA_PIN_DAP4_SCLK_PCC0, +}; + +static const unsigned int dap4_dout_pcc1_pins[] = { + TEGRA_PIN_DAP4_DOUT_PCC1, +}; + +static const unsigned int dap4_din_pcc2_pins[] = { + TEGRA_PIN_DAP4_DIN_PCC2, +}; + +static const unsigned int dap4_fs_pcc3_pins[] = { + TEGRA_PIN_DAP4_FS_PCC3, +}; + +static const unsigned int gpio_sen8_pee0_pins[] = { + TEGRA_PIN_GPIO_SEN8_PEE0, +}; + +static const unsigned int gpio_sen9_pee1_pins[] = { + TEGRA_PIN_GPIO_SEN9_PEE1, +}; + +static const unsigned int touch_clk_pee2_pins[] = { + TEGRA_PIN_TOUCH_CLK_PEE2, +}; + +static const unsigned int power_on_pff0_pins[] = { + TEGRA_PIN_POWER_ON_PFF0, +}; + +static const unsigned int gpio_sw1_pff1_pins[] = { + TEGRA_PIN_GPIO_SW1_PFF1, +}; + +static const unsigned int gpio_sw2_pff2_pins[] = { + TEGRA_PIN_GPIO_SW2_PFF2, +}; + +static const unsigned int gpio_sw3_pff3_pins[] = { + TEGRA_PIN_GPIO_SW3_PFF3, +}; + +static const unsigned int gpio_sw4_pff4_pins[] = { + TEGRA_PIN_GPIO_SW4_PFF4, +}; + +static const unsigned int directdc_comp_pins[] = { + TEGRA_PIN_DIRECTDC_COMP, +}; + +static const unsigned int sdmmc1_comp_pins[] = { + TEGRA_PIN_SDMMC1_COMP, +}; + +static const unsigned int eqos_comp_pins[] = { + TEGRA_PIN_EQOS_COMP, +}; + +static const unsigned int sdmmc3_comp_pins[] = { + TEGRA_PIN_SDMMC3_COMP, +}; + +static const unsigned int qspi_comp_pins[] = { + TEGRA_PIN_QSPI_COMP, +}; + +static const unsigned int shutdown_pins[] = { + TEGRA_PIN_SHUTDOWN, +}; + +static const unsigned int pmu_int_pins[] = { + TEGRA_PIN_PMU_INT, +}; + +static const unsigned int soc_pwr_req_pins[] = { + TEGRA_PIN_SOC_PWR_REQ, +}; + +static const unsigned int clk_32k_in_pins[] = { + TEGRA_PIN_CLK_32K_IN, +}; + +static const unsigned int sdmmc4_clk_pins[] = {}; + +static const unsigned int sdmmc4_cmd_pins[] = {}; + +static const unsigned int sdmmc4_dqs_pins[] = {}; + +static const unsigned int sdmmc4_dat7_pins[] = {}; + +static const unsigned int sdmmc4_dat6_pins[] = {}; + +static const unsigned int sdmmc4_dat5_pins[] = {}; + +static const unsigned int sdmmc4_dat4_pins[] = {}; + +static const unsigned int sdmmc4_dat3_pins[] = {}; + +static const unsigned int sdmmc4_dat2_pins[] = {}; + +static const unsigned int sdmmc4_dat1_pins[] = {}; + +static const unsigned int sdmmc4_dat0_pins[] = {}; + +/* Define unique ID for each function */ +enum tegra_mux_dt { + TEGRA_MUX_RSVD0, + TEGRA_MUX_RSVD1, + TEGRA_MUX_RSVD2, + TEGRA_MUX_RSVD3, + TEGRA_MUX_TOUCH, + TEGRA_MUX_UARTC, + TEGRA_MUX_I2C8, + TEGRA_MUX_UARTG, + TEGRA_MUX_SPI2, + TEGRA_MUX_GP, + TEGRA_MUX_DCA, + TEGRA_MUX_WDT, + TEGRA_MUX_I2C2, + TEGRA_MUX_CAN1, + TEGRA_MUX_CAN0, + TEGRA_MUX_DMIC3, + TEGRA_MUX_DMIC5, + TEGRA_MUX_GPIO, + TEGRA_MUX_DSPK1, + TEGRA_MUX_DSPK0, + TEGRA_MUX_SPDIF, + TEGRA_MUX_AUD, + TEGRA_MUX_I2S1, + TEGRA_MUX_DMIC1, + TEGRA_MUX_DMIC2, + TEGRA_MUX_I2S3, + TEGRA_MUX_DMIC4, + TEGRA_MUX_I2S4, + TEGRA_MUX_EXTPERIPH2, + TEGRA_MUX_EXTPERIPH1, + TEGRA_MUX_I2C3, + TEGRA_MUX_VGP1, + TEGRA_MUX_VGP2, + TEGRA_MUX_VGP3, + TEGRA_MUX_VGP4, + TEGRA_MUX_VGP5, + TEGRA_MUX_VGP6, + TEGRA_MUX_EXTPERIPH3, + TEGRA_MUX_EXTPERIPH4, + TEGRA_MUX_SPI4, + TEGRA_MUX_I2S2, + TEGRA_MUX_UARTD, + TEGRA_MUX_I2C1, + TEGRA_MUX_UARTA, + TEGRA_MUX_DIRECTDC1, + TEGRA_MUX_DIRECTDC, + TEGRA_MUX_IQC0, + TEGRA_MUX_IQC1, + TEGRA_MUX_I2S6, + TEGRA_MUX_DTV, + TEGRA_MUX_UARTF, + TEGRA_MUX_SDMMC3, + TEGRA_MUX_SDMMC4, + TEGRA_MUX_SDMMC1, + TEGRA_MUX_DP, + TEGRA_MUX_HDMI, + TEGRA_MUX_PE2, + TEGRA_MUX_SATA, + TEGRA_MUX_PE, + TEGRA_MUX_PE1, + TEGRA_MUX_PE0, + TEGRA_MUX_SOC, + TEGRA_MUX_EQOS, + TEGRA_MUX_SDMMC2, + TEGRA_MUX_QSPI, + TEGRA_MUX_SCE, + TEGRA_MUX_I2C5, + TEGRA_MUX_DISPLAYA, + TEGRA_MUX_DISPLAYB, + TEGRA_MUX_DCC, + TEGRA_MUX_DCB, + TEGRA_MUX_SPI1, + TEGRA_MUX_UARTB, + TEGRA_MUX_UARTE, + TEGRA_MUX_SPI3, + TEGRA_MUX_NV, + TEGRA_MUX_CCLA, + TEGRA_MUX_I2C7, + TEGRA_MUX_I2C9, + TEGRA_MUX_I2S5, + TEGRA_MUX_USB, + TEGRA_MUX_UFS0, +}; + +/* Make list of each function name */ +#define TEGRA_PIN_FUNCTION(lid) #lid + +static const char * const tegra186_functions[] = { + TEGRA_PIN_FUNCTION(rsvd0), + TEGRA_PIN_FUNCTION(rsvd1), + TEGRA_PIN_FUNCTION(rsvd2), + TEGRA_PIN_FUNCTION(rsvd3), + TEGRA_PIN_FUNCTION(touch), + TEGRA_PIN_FUNCTION(uartc), + TEGRA_PIN_FUNCTION(i2c8), + TEGRA_PIN_FUNCTION(uartg), + TEGRA_PIN_FUNCTION(spi2), + TEGRA_PIN_FUNCTION(gp), + TEGRA_PIN_FUNCTION(dca), + TEGRA_PIN_FUNCTION(wdt), + TEGRA_PIN_FUNCTION(i2c2), + TEGRA_PIN_FUNCTION(can1), + TEGRA_PIN_FUNCTION(can0), + TEGRA_PIN_FUNCTION(dmic3), + TEGRA_PIN_FUNCTION(dmic5), + TEGRA_PIN_FUNCTION(gpio), + TEGRA_PIN_FUNCTION(dspk1), + TEGRA_PIN_FUNCTION(dspk0), + TEGRA_PIN_FUNCTION(spdif), + TEGRA_PIN_FUNCTION(aud), + TEGRA_PIN_FUNCTION(i2s1), + TEGRA_PIN_FUNCTION(dmic1), + TEGRA_PIN_FUNCTION(dmic2), + TEGRA_PIN_FUNCTION(i2s3), + TEGRA_PIN_FUNCTION(dmic4), + TEGRA_PIN_FUNCTION(i2s4), + TEGRA_PIN_FUNCTION(extperiph2), + TEGRA_PIN_FUNCTION(extperiph1), + TEGRA_PIN_FUNCTION(i2c3), + TEGRA_PIN_FUNCTION(vgp1), + TEGRA_PIN_FUNCTION(vgp2), + TEGRA_PIN_FUNCTION(vgp3), + TEGRA_PIN_FUNCTION(vgp4), + TEGRA_PIN_FUNCTION(vgp5), + TEGRA_PIN_FUNCTION(vgp6), + TEGRA_PIN_FUNCTION(extperiph3), + TEGRA_PIN_FUNCTION(extperiph4), + TEGRA_PIN_FUNCTION(spi4), + TEGRA_PIN_FUNCTION(i2s2), + TEGRA_PIN_FUNCTION(uartd), + TEGRA_PIN_FUNCTION(i2c1), + TEGRA_PIN_FUNCTION(uarta), + TEGRA_PIN_FUNCTION(directdc1), + TEGRA_PIN_FUNCTION(directdc), + TEGRA_PIN_FUNCTION(iqc0), + TEGRA_PIN_FUNCTION(iqc1), + TEGRA_PIN_FUNCTION(i2s6), + TEGRA_PIN_FUNCTION(dtv), + TEGRA_PIN_FUNCTION(uartf), + TEGRA_PIN_FUNCTION(sdmmc3), + TEGRA_PIN_FUNCTION(sdmmc4), + TEGRA_PIN_FUNCTION(sdmmc1), + TEGRA_PIN_FUNCTION(dp), + TEGRA_PIN_FUNCTION(hdmi), + TEGRA_PIN_FUNCTION(pe2), + TEGRA_PIN_FUNCTION(sata), + TEGRA_PIN_FUNCTION(pe), + TEGRA_PIN_FUNCTION(pe1), + TEGRA_PIN_FUNCTION(pe0), + TEGRA_PIN_FUNCTION(soc), + TEGRA_PIN_FUNCTION(eqos), + TEGRA_PIN_FUNCTION(sdmmc2), + TEGRA_PIN_FUNCTION(qspi), + TEGRA_PIN_FUNCTION(sce), + TEGRA_PIN_FUNCTION(i2c5), + TEGRA_PIN_FUNCTION(displaya), + TEGRA_PIN_FUNCTION(displayb), + TEGRA_PIN_FUNCTION(dcc), + TEGRA_PIN_FUNCTION(dcb), + TEGRA_PIN_FUNCTION(spi1), + TEGRA_PIN_FUNCTION(uartb), + TEGRA_PIN_FUNCTION(uarte), + TEGRA_PIN_FUNCTION(spi3), + TEGRA_PIN_FUNCTION(nv), + TEGRA_PIN_FUNCTION(ccla), + TEGRA_PIN_FUNCTION(i2c7), + TEGRA_PIN_FUNCTION(i2c9), + TEGRA_PIN_FUNCTION(i2s5), + TEGRA_PIN_FUNCTION(usb), + TEGRA_PIN_FUNCTION(ufs0), +}; + +#define PINGROUP_REG_Y(r) ((r)) +#define PINGROUP_REG_N(r) -1 + +#define DRV_PINGROUP_Y(r) ((r)) +#define DRV_PINGROUP_N(r) -1 + +#define DRV_PINGROUP_ENTRY_N(pg_name) \ + .drv_reg = -1, \ + .drv_bank = -1, \ + .drvdn_bit = -1, \ + .drvdn_width = -1, \ + .drvup_bit = -1, \ + .drvup_width = -1, \ + .slwr_bit = -1, \ + .slwr_width = -1, \ + .slwf_bit = -1, \ + .slwf_width = -1 + +#define DRV_PINGROUP_ENTRY_Y(r, drvdn_b, drvdn_w, drvup_b, \ + drvup_w, slwr_b, slwr_w, slwf_b, \ + slwf_w, bank) \ + .drv_reg = ((r)), \ + .drv_bank = bank, \ + .drvdn_bit = drvdn_b, \ + .drvdn_width = drvdn_w, \ + .drvup_bit = drvup_b, \ + .drvup_width = drvup_w, \ + .slwr_bit = slwr_b, \ + .slwr_width = slwr_w, \ + .slwf_bit = slwf_b, \ + .slwf_width = slwf_w + +#define PIN_PINGROUP_ENTRY_N(pg_name) \ + .mux_reg = -1, \ + .pupd_reg = -1, \ + .tri_reg = -1, \ + .einput_bit = -1, \ + .e_io_hv_bit = -1, \ + .odrain_bit = -1, \ + .lock_bit = -1, \ + .parked_bit = -1, \ + .lpmd_bit = -1, \ + .drvtype_bit = -1, \ + .lpdr_bit = -1, \ + .pbias_buf_bit = -1, \ + .preemp_bit = -1, \ + .rfu_in_bit = -1 + +#define PIN_PINGROUP_ENTRY_Y(r, bank, pupd, e_io_hv, e_lpbk, e_input, \ + e_lpdr, e_pbias_buf, gpio_sfio_sel, \ + e_od, schmitt_b, drvtype, epreemp, \ + io_reset, rfu_in) \ + .mux_reg = PINGROUP_REG_Y(r), \ + .lpmd_bit = -1, \ + .lock_bit = -1, \ + .hsm_bit = -1, \ + .mux_bank = bank, \ + .mux_bit = 0, \ + .pupd_reg = PINGROUP_REG_##pupd(r), \ + .pupd_bank = bank, \ + .pupd_bit = 2, \ + .tri_reg = PINGROUP_REG_Y(r), \ + .tri_bank = bank, \ + .tri_bit = 4, \ + .einput_bit = e_input, \ + .sfsel_bit = gpio_sfio_sel, \ + .odrain_bit = e_od, \ + .schmitt_bit = schmitt_b, \ + .drvtype_bit = 13, \ + .lpdr_bit = e_lpdr, \ + +/* main drive pin groups */ +#define drive_gpio_aud3_pk0 DRV_PINGROUP_ENTRY_Y(0x1004, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gpio_aud2_pj7 DRV_PINGROUP_ENTRY_Y(0x100c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gpio_aud1_pj6 DRV_PINGROUP_ENTRY_Y(0x1014, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gpio_aud0_pj5 DRV_PINGROUP_ENTRY_Y(0x101c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_aud_mclk_pj4 DRV_PINGROUP_ENTRY_Y(0x1024, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_dap1_fs_pj3 DRV_PINGROUP_ENTRY_Y(0x102c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_dap1_din_pj2 DRV_PINGROUP_ENTRY_Y(0x1034, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_dap1_dout_pj1 DRV_PINGROUP_ENTRY_Y(0x103c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_dap1_sclk_pj0 DRV_PINGROUP_ENTRY_Y(0x1044, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_dmic1_clk_pm1 DRV_PINGROUP_ENTRY_Y(0x2004, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_dmic1_dat_pm0 DRV_PINGROUP_ENTRY_Y(0x200c, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_dmic2_dat_pm2 DRV_PINGROUP_ENTRY_Y(0x2014, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_dmic2_clk_pm3 DRV_PINGROUP_ENTRY_Y(0x201c, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_dmic4_dat_pm4 DRV_PINGROUP_ENTRY_Y(0x2024, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_dmic4_clk_pm5 DRV_PINGROUP_ENTRY_Y(0x202c, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_dap4_fs_pcc3 DRV_PINGROUP_ENTRY_Y(0x2034, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_dap4_din_pcc2 DRV_PINGROUP_ENTRY_Y(0x203c, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_dap4_dout_pcc1 DRV_PINGROUP_ENTRY_Y(0x2044, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_dap4_sclk_pcc0 DRV_PINGROUP_ENTRY_Y(0x204c, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_extperiph2_clk_po1 DRV_PINGROUP_ENTRY_Y(0x0004, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_extperiph1_clk_po0 DRV_PINGROUP_ENTRY_Y(0x000c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_cam_i2c_sda_po3 DRV_PINGROUP_ENTRY_Y(0x0014, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_cam_i2c_scl_po2 DRV_PINGROUP_ENTRY_Y(0x001c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gpio_cam1_pn0 DRV_PINGROUP_ENTRY_Y(0x0024, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gpio_cam2_pn1 DRV_PINGROUP_ENTRY_Y(0x002c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gpio_cam3_pn2 DRV_PINGROUP_ENTRY_Y(0x0034, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gpio_cam4_pn3 DRV_PINGROUP_ENTRY_Y(0x003c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gpio_cam5_pn4 DRV_PINGROUP_ENTRY_Y(0x0044, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gpio_cam6_pn5 DRV_PINGROUP_ENTRY_Y(0x004c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gpio_cam7_pn6 DRV_PINGROUP_ENTRY_Y(0x0054, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_dap2_din_pc3 DRV_PINGROUP_ENTRY_Y(0x4004, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_dap2_dout_pc2 DRV_PINGROUP_ENTRY_Y(0x400c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_dap2_fs_pc4 DRV_PINGROUP_ENTRY_Y(0x4014, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_dap2_sclk_pc1 DRV_PINGROUP_ENTRY_Y(0x401c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_uart4_cts_pb3 DRV_PINGROUP_ENTRY_Y(0x4024, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_uart4_rts_pb2 DRV_PINGROUP_ENTRY_Y(0x402c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_uart4_rx_pb1 DRV_PINGROUP_ENTRY_Y(0x4034, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_uart4_tx_pb0 DRV_PINGROUP_ENTRY_Y(0x403c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gpio_wan4_pc0 DRV_PINGROUP_ENTRY_Y(0x4044, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gpio_wan3_pb6 DRV_PINGROUP_ENTRY_Y(0x404c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gpio_wan2_pb5 DRV_PINGROUP_ENTRY_Y(0x4054, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gpio_wan1_pb4 DRV_PINGROUP_ENTRY_Y(0x405c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gen1_i2c_scl_pc5 DRV_PINGROUP_ENTRY_Y(0x4064, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gen1_i2c_sda_pc6 DRV_PINGROUP_ENTRY_Y(0x406c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_uart1_cts_pt3 DRV_PINGROUP_ENTRY_Y(0x5004, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_uart1_rts_pt2 DRV_PINGROUP_ENTRY_Y(0x500c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_uart1_rx_pt1 DRV_PINGROUP_ENTRY_Y(0x5014, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_uart1_tx_pt0 DRV_PINGROUP_ENTRY_Y(0x501c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_directdc1_out3_pq5 DRV_PINGROUP_ENTRY_Y(0x502c, 12, 9, 24, 8, -1, -1, -1, -1, 0) +#define drive_directdc1_out2_pq4 DRV_PINGROUP_ENTRY_Y(0x5034, 12, 9, 24, 8, -1, -1, -1, -1, 0) +#define drive_directdc1_out1_pq3 DRV_PINGROUP_ENTRY_Y(0x503c, 12, 9, 24, 8, -1, -1, -1, -1, 0) +#define drive_directdc1_out0_pq2 DRV_PINGROUP_ENTRY_Y(0x5044, 12, 9, 24, 8, -1, -1, -1, -1, 0) +#define drive_directdc1_in_pq1 DRV_PINGROUP_ENTRY_Y(0x504c, 12, 9, 24, 8, -1, -1, -1, -1, 0) +#define drive_directdc1_clk_pq0 DRV_PINGROUP_ENTRY_Y(0x5054, 12, 9, 24, 8, -1, -1, -1, -1, 0) +#define drive_gpio_pq0_pi0 DRV_PINGROUP_ENTRY_Y(0x3004, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_gpio_pq1_pi1 DRV_PINGROUP_ENTRY_Y(0x300c, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_gpio_pq2_pi2 DRV_PINGROUP_ENTRY_Y(0x3014, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_gpio_pq3_pi3 DRV_PINGROUP_ENTRY_Y(0x301c, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_gpio_pq4_pi4 DRV_PINGROUP_ENTRY_Y(0x3024, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_gpio_pq5_pi5 DRV_PINGROUP_ENTRY_Y(0x302c, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_gpio_pq6_pi6 DRV_PINGROUP_ENTRY_Y(0x3034, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_gpio_pq7_pi7 DRV_PINGROUP_ENTRY_Y(0x303c, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_gpio_edp2_pp5 DRV_PINGROUP_ENTRY_Y(0x10004, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gpio_edp3_pp6 DRV_PINGROUP_ENTRY_Y(0x1000c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gpio_edp0_pp3 DRV_PINGROUP_ENTRY_Y(0x10014, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gpio_edp1_pp4 DRV_PINGROUP_ENTRY_Y(0x1001c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_dp_aux_ch0_hpd_pp0 DRV_PINGROUP_ENTRY_Y(0x10024, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_dp_aux_ch1_hpd_pp1 DRV_PINGROUP_ENTRY_Y(0x1002c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_hdmi_cec_pp2 DRV_PINGROUP_ENTRY_Y(0x10034, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_pex_l2_clkreq_n_pa6 DRV_PINGROUP_ENTRY_Y(0x7004, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_pex_wake_n_pa2 DRV_PINGROUP_ENTRY_Y(0x700c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_pex_l1_clkreq_n_pa4 DRV_PINGROUP_ENTRY_Y(0x7014, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_pex_l1_rst_n_pa3 DRV_PINGROUP_ENTRY_Y(0x701c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_pex_l0_clkreq_n_pa1 DRV_PINGROUP_ENTRY_Y(0x7024, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_pex_l0_rst_n_pa0 DRV_PINGROUP_ENTRY_Y(0x702c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_pex_l2_rst_n_pa5 DRV_PINGROUP_ENTRY_Y(0x7034, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_sdmmc1_clk_pd0 DRV_PINGROUP_ENTRY_Y(0x8004, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_sdmmc1_cmd_pd1 DRV_PINGROUP_ENTRY_Y(0x800c, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_sdmmc1_dat3_pd5 DRV_PINGROUP_ENTRY_Y(0x8018, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_sdmmc1_dat2_pd4 DRV_PINGROUP_ENTRY_Y(0x8020, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_sdmmc1_dat1_pd3 DRV_PINGROUP_ENTRY_Y(0x8028, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_sdmmc1_dat0_pd2 DRV_PINGROUP_ENTRY_Y(0x8030, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_eqos_td3_pe4 DRV_PINGROUP_ENTRY_Y(0x9004, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_eqos_td2_pe3 DRV_PINGROUP_ENTRY_Y(0x900c, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_eqos_td1_pe2 DRV_PINGROUP_ENTRY_Y(0x9014, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_eqos_td0_pe1 DRV_PINGROUP_ENTRY_Y(0x901c, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_eqos_rd3_pf1 DRV_PINGROUP_ENTRY_Y(0x9024, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_eqos_rd2_pf0 DRV_PINGROUP_ENTRY_Y(0x902c, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_eqos_rd1_pe7 DRV_PINGROUP_ENTRY_Y(0x9034, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_eqos_mdio_pf4 DRV_PINGROUP_ENTRY_Y(0x903c, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_eqos_rd0_pe6 DRV_PINGROUP_ENTRY_Y(0x9044, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_eqos_mdc_pf5 DRV_PINGROUP_ENTRY_Y(0x904c, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_eqos_txc_pe0 DRV_PINGROUP_ENTRY_Y(0x9058, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_eqos_rxc_pf3 DRV_PINGROUP_ENTRY_Y(0x9060, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_eqos_tx_ctl_pe5 DRV_PINGROUP_ENTRY_Y(0x9068, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_eqos_rx_ctl_pf2 DRV_PINGROUP_ENTRY_Y(0x9070, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_sdmmc3_dat3_pg5 DRV_PINGROUP_ENTRY_Y(0xa004, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_sdmmc3_dat2_pg4 DRV_PINGROUP_ENTRY_Y(0xa00c, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_sdmmc3_dat1_pg3 DRV_PINGROUP_ENTRY_Y(0xa014, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_sdmmc3_dat0_pg2 DRV_PINGROUP_ENTRY_Y(0xa01c, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_sdmmc3_cmd_pg1 DRV_PINGROUP_ENTRY_Y(0xa028, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_sdmmc3_clk_pg0 DRV_PINGROUP_ENTRY_Y(0xa030, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_qspi_io3_pr4 DRV_PINGROUP_ENTRY_Y(0xB004, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_qspi_io2_pr3 DRV_PINGROUP_ENTRY_Y(0xB00C, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_qspi_io1_pr2 DRV_PINGROUP_ENTRY_Y(0xB014, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_qspi_io0_pr1 DRV_PINGROUP_ENTRY_Y(0xB01C, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_qspi_sck_pr0 DRV_PINGROUP_ENTRY_Y(0xB024, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_qspi_cs_n_pr5 DRV_PINGROUP_ENTRY_Y(0xB02C, -1, -1, -1, -1, 28, 2, 30, 2, 0) +#define drive_gpio_wan8_ph3 DRV_PINGROUP_ENTRY_Y(0xd004, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gpio_wan7_ph2 DRV_PINGROUP_ENTRY_Y(0xd00c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gpio_wan6_ph1 DRV_PINGROUP_ENTRY_Y(0xd014, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gpio_wan5_ph0 DRV_PINGROUP_ENTRY_Y(0xd01c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_uart2_tx_px0 DRV_PINGROUP_ENTRY_Y(0xd024, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_uart2_rx_px1 DRV_PINGROUP_ENTRY_Y(0xd02c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_uart2_rts_px2 DRV_PINGROUP_ENTRY_Y(0xd034, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_uart2_cts_px3 DRV_PINGROUP_ENTRY_Y(0xd03c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_uart5_rx_px5 DRV_PINGROUP_ENTRY_Y(0xd044, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_uart5_tx_px4 DRV_PINGROUP_ENTRY_Y(0xd04c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_uart5_rts_px6 DRV_PINGROUP_ENTRY_Y(0xd054, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_uart5_cts_px7 DRV_PINGROUP_ENTRY_Y(0xd05c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gpio_mdm1_py0 DRV_PINGROUP_ENTRY_Y(0xd064, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gpio_mdm2_py1 DRV_PINGROUP_ENTRY_Y(0xd06c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gpio_mdm3_py2 DRV_PINGROUP_ENTRY_Y(0xd074, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gpio_mdm4_py3 DRV_PINGROUP_ENTRY_Y(0xd07c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gpio_mdm5_py4 DRV_PINGROUP_ENTRY_Y(0xd084, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gpio_mdm6_py5 DRV_PINGROUP_ENTRY_Y(0xd08c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gpio_mdm7_py6 DRV_PINGROUP_ENTRY_Y(0xd094, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_bcpu_pwr_req_ph4 DRV_PINGROUP_ENTRY_Y(0xd09c, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_mcpu_pwr_req_ph5 DRV_PINGROUP_ENTRY_Y(0xd0a4, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gpu_pwr_req_ph6 DRV_PINGROUP_ENTRY_Y(0xd0ac, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gen7_i2c_scl_pl0 DRV_PINGROUP_ENTRY_Y(0xd0b4, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gen7_i2c_sda_pl1 DRV_PINGROUP_ENTRY_Y(0xd0bc, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gen9_i2c_sda_pl3 DRV_PINGROUP_ENTRY_Y(0xd0c4, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gen9_i2c_scl_pl2 DRV_PINGROUP_ENTRY_Y(0xd0cc, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_usb_vbus_en0_pl4 DRV_PINGROUP_ENTRY_Y(0xd0d4, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_usb_vbus_en1_pl5 DRV_PINGROUP_ENTRY_Y(0xd0dc, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gp_pwm7_pl7 DRV_PINGROUP_ENTRY_Y(0xd0e4, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_gp_pwm6_pl6 DRV_PINGROUP_ENTRY_Y(0xd0ec, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_ufs0_rst_pbb1 DRV_PINGROUP_ENTRY_Y(0x11004, 12, 9, 24, 8, -1, -1, -1, -1, 0) +#define drive_ufs0_ref_clk_pbb0 DRV_PINGROUP_ENTRY_Y(0x1100c, 12, 9, 24, 8, -1, -1, -1, -1, 0) + +#define drive_directdc_comp DRV_PINGROUP_ENTRY_N(no_entry) +#define drive_sdmmc1_comp DRV_PINGROUP_ENTRY_N(no_entry) +#define drive_eqos_comp DRV_PINGROUP_ENTRY_N(no_entry) +#define drive_sdmmc3_comp DRV_PINGROUP_ENTRY_N(no_entry) +#define drive_sdmmc4_clk DRV_PINGROUP_ENTRY_N(no_entry) +#define drive_sdmmc4_cmd DRV_PINGROUP_ENTRY_N(no_entry) +#define drive_sdmmc4_dqs DRV_PINGROUP_ENTRY_N(no_entry) +#define drive_sdmmc4_dat7 DRV_PINGROUP_ENTRY_N(no_entry) +#define drive_sdmmc4_dat6 DRV_PINGROUP_ENTRY_N(no_entry) +#define drive_sdmmc4_dat5 DRV_PINGROUP_ENTRY_N(no_entry) +#define drive_sdmmc4_dat4 DRV_PINGROUP_ENTRY_N(no_entry) +#define drive_sdmmc4_dat3 DRV_PINGROUP_ENTRY_N(no_entry) +#define drive_sdmmc4_dat2 DRV_PINGROUP_ENTRY_N(no_entry) +#define drive_sdmmc4_dat1 DRV_PINGROUP_ENTRY_N(no_entry) +#define drive_sdmmc4_dat0 DRV_PINGROUP_ENTRY_N(no_entry) +#define drive_qspi_comp DRV_PINGROUP_ENTRY_N(no_entry) + +/* AON drive pin groups */ +#define drive_touch_clk_pee2 DRV_PINGROUP_ENTRY_Y(0x2004, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_uart3_cts_pw5 DRV_PINGROUP_ENTRY_Y(0x200c, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_uart3_rts_pw4 DRV_PINGROUP_ENTRY_Y(0x2014, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_uart3_rx_pw3 DRV_PINGROUP_ENTRY_Y(0x201c, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_uart3_tx_pw2 DRV_PINGROUP_ENTRY_Y(0x2024, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_gen8_i2c_sda_pw1 DRV_PINGROUP_ENTRY_Y(0x202c, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_gen8_i2c_scl_pw0 DRV_PINGROUP_ENTRY_Y(0x2034, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_uart7_rx_pw7 DRV_PINGROUP_ENTRY_Y(0x203c, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_uart7_tx_pw6 DRV_PINGROUP_ENTRY_Y(0x2044, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_gpio_sen0_pv0 DRV_PINGROUP_ENTRY_Y(0x204c, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_gpio_sen1_pv1 DRV_PINGROUP_ENTRY_Y(0x2054, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_gpio_sen2_pv2 DRV_PINGROUP_ENTRY_Y(0x205c, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_gpio_sen3_pv3 DRV_PINGROUP_ENTRY_Y(0x2064, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_gpio_sen4_pv4 DRV_PINGROUP_ENTRY_Y(0x206c, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_gpio_sen5_pv5 DRV_PINGROUP_ENTRY_Y(0x2074, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_gpio_sen6_pv6 DRV_PINGROUP_ENTRY_Y(0x207c, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_gpio_sen7_pv7 DRV_PINGROUP_ENTRY_Y(0x2084, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_gpio_sen8_pee0 DRV_PINGROUP_ENTRY_Y(0x208c, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_gpio_sen9_pee1 DRV_PINGROUP_ENTRY_Y(0x2094, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_can_gpio7_paa7 DRV_PINGROUP_ENTRY_Y(0x3004, -1, -1, -1, -1, 28, 2, 30, 2, 1) +#define drive_can1_dout_pz0 DRV_PINGROUP_ENTRY_Y(0x300C, -1, -1, -1, -1, 28, 2, 30, 2, 1) +#define drive_can1_din_pz1 DRV_PINGROUP_ENTRY_Y(0x3014, -1, -1, -1, -1, 28, 2, 30, 2, 1) +#define drive_can0_dout_pz2 DRV_PINGROUP_ENTRY_Y(0x301c, -1, -1, -1, -1, 28, 2, 30, 2, 1) +#define drive_can0_din_pz3 DRV_PINGROUP_ENTRY_Y(0x3024, -1, -1, -1, -1, 28, 2, 30, 2, 1) +#define drive_can_gpio0_paa0 DRV_PINGROUP_ENTRY_Y(0x302c, -1, -1, -1, -1, 28, 2, 30, 2, 1) +#define drive_can_gpio1_paa1 DRV_PINGROUP_ENTRY_Y(0x3034, -1, -1, -1, -1, 28, 2, 30, 2, 1) +#define drive_can_gpio2_paa2 DRV_PINGROUP_ENTRY_Y(0x303c, -1, -1, -1, -1, 28, 2, 30, 2, 1) +#define drive_can_gpio3_paa3 DRV_PINGROUP_ENTRY_Y(0x3044, -1, -1, -1, -1, 28, 2, 30, 2, 1) +#define drive_can_gpio4_paa4 DRV_PINGROUP_ENTRY_Y(0x304c, -1, -1, -1, -1, 28, 2, 30, 2, 1) +#define drive_can_gpio5_paa5 DRV_PINGROUP_ENTRY_Y(0x3054, -1, -1, -1, -1, 28, 2, 30, 2, 1) +#define drive_can_gpio6_paa6 DRV_PINGROUP_ENTRY_Y(0x305c, -1, -1, -1, -1, 28, 2, 30, 2, 1) +#define drive_gpio_sw1_pff1 DRV_PINGROUP_ENTRY_Y(0x1004, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_gpio_sw2_pff2 DRV_PINGROUP_ENTRY_Y(0x100c, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_gpio_sw3_pff3 DRV_PINGROUP_ENTRY_Y(0x1014, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_gpio_sw4_pff4 DRV_PINGROUP_ENTRY_Y(0x101c, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_shutdown DRV_PINGROUP_ENTRY_Y(0x1024, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_pmu_int DRV_PINGROUP_ENTRY_Y(0x102C, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_safe_state_ps3 DRV_PINGROUP_ENTRY_Y(0x1034, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_vcomp_alert_ps4 DRV_PINGROUP_ENTRY_Y(0x103c, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_soc_pwr_req DRV_PINGROUP_ENTRY_Y(0x1044, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_batt_oc_ps2 DRV_PINGROUP_ENTRY_Y(0x104c, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_clk_32k_in DRV_PINGROUP_ENTRY_Y(0x1054, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_power_on_pff0 DRV_PINGROUP_ENTRY_Y(0x105c, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_pwr_i2c_scl_ps0 DRV_PINGROUP_ENTRY_Y(0x1064, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_pwr_i2c_sda_ps1 DRV_PINGROUP_ENTRY_Y(0x106c, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_gpio_dis0_pu0 DRV_PINGROUP_ENTRY_Y(0x1084, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_gpio_dis1_pu1 DRV_PINGROUP_ENTRY_Y(0x108c, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_gpio_dis2_pu2 DRV_PINGROUP_ENTRY_Y(0x1094, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_gpio_dis3_pu3 DRV_PINGROUP_ENTRY_Y(0x109c, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_gpio_dis4_pu4 DRV_PINGROUP_ENTRY_Y(0x10a4, 12, 5, 20, 5, -1, -1, -1, -1, 1) +#define drive_gpio_dis5_pu5 DRV_PINGROUP_ENTRY_Y(0x10ac, 12, 5, 20, 5, -1, -1, -1, -1, 1) + +#define PINGROUP(pg_name, f0, f1, f2, f3, r, bank, pupd, e_io_hv, e_lpbk, e_input, e_lpdr, e_pbias_buf, \ + gpio_sfio_sel, e_od, schmitt_b, drvtype, epreemp, io_reset, rfu_in) \ + { \ + .name = #pg_name, \ + .pins = pg_name##_pins, \ + .npins = ARRAY_SIZE(pg_name##_pins), \ + .funcs = { \ + TEGRA_MUX_##f0, \ + TEGRA_MUX_##f1, \ + TEGRA_MUX_##f2, \ + TEGRA_MUX_##f3, \ + }, \ + PIN_PINGROUP_ENTRY_Y(r, bank, pupd, e_io_hv, e_lpbk, \ + e_input, e_lpdr, e_pbias_buf, \ + gpio_sfio_sel, e_od, \ + schmitt_b, drvtype, \ + epreemp, io_reset, \ + rfu_in) \ + drive_##pg_name, \ + } + +static const struct tegra_pingroup tegra186_groups[] = { + PINGROUP(gpio_aud3_pk0, RSVD0, DSPK1, SPDIF, RSVD3, 0x1000, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_aud2_pj7, RSVD0, DSPK1, SPDIF, RSVD3, 0x1008, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_aud1_pj6, RSVD0, RSVD1, RSVD2, RSVD3, 0x1010, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_aud0_pj5, RSVD0, RSVD1, RSVD2, RSVD3, 0x1018, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(aud_mclk_pj4, AUD, RSVD1, RSVD2, RSVD3, 0x1020, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(dap1_fs_pj3, I2S1, RSVD1, RSVD2, RSVD3, 0x1028, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(dap1_din_pj2, I2S1, RSVD1, RSVD2, RSVD3, 0x1030, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(dap1_dout_pj1, I2S1, RSVD1, RSVD2, RSVD3, 0x1038, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(dap1_sclk_pj0, I2S1, RSVD1, RSVD2, RSVD3, 0x1040, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(dmic1_clk_pm1, DMIC1, I2S3, RSVD2, RSVD3, 0x2000, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(dmic1_dat_pm0, DMIC1, I2S3, RSVD2, RSVD3, 0x2008, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(dmic2_dat_pm2, DMIC2, I2S3, RSVD2, RSVD3, 0x2010, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(dmic2_clk_pm3, DMIC2, I2S3, RSVD2, RSVD3, 0x2018, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(dmic4_dat_pm4, DMIC4, DSPK0, RSVD2, RSVD3, 0x2020, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(dmic4_clk_pm5, DMIC4, DSPK0, RSVD2, RSVD3, 0x2028, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(dap4_fs_pcc3, I2S4, RSVD1, RSVD2, RSVD3, 0x2030, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(dap4_din_pcc2, I2S4, RSVD1, RSVD2, RSVD3, 0x2038, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(dap4_dout_pcc1, I2S4, RSVD1, RSVD2, RSVD3, 0x2040, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(dap4_sclk_pcc0, I2S4, RSVD1, RSVD2, RSVD3, 0x2048, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(extperiph2_clk_po1, EXTPERIPH2, RSVD1, RSVD2, RSVD3, 0x0000, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(extperiph1_clk_po0, EXTPERIPH1, RSVD1, RSVD2, RSVD3, 0x0008, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(cam_i2c_sda_po3, I2C3, RSVD1, RSVD2, RSVD3, 0x0010, 0, Y, 5, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(cam_i2c_scl_po2, I2C3, RSVD1, RSVD2, RSVD3, 0x0018, 0, Y, 5, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_cam1_pn0, VGP1, RSVD1, RSVD2, RSVD3, 0x0020, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_cam2_pn1, VGP2, EXTPERIPH3, RSVD2, RSVD3, 0x0028, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_cam3_pn2, VGP3, EXTPERIPH4, RSVD2, RSVD3, 0x0030, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_cam4_pn3, VGP4, SPI4, RSVD2, RSVD3, 0x0038, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_cam5_pn4, VGP5, SPI4, RSVD2, RSVD3, 0x0040, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_cam6_pn5, VGP6, SPI4, RSVD2, RSVD3, 0x0048, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_cam7_pn6, RSVD0, SPI4, RSVD2, RSVD3, 0x0050, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(dap2_din_pc3, I2S2, RSVD1, RSVD2, RSVD3, 0x4000, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(dap2_dout_pc2, I2S2, RSVD1, RSVD2, RSVD3, 0x4008, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(dap2_fs_pc4, I2S2, RSVD1, RSVD2, RSVD3, 0x4010, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(dap2_sclk_pc1, I2S2, RSVD1, RSVD2, RSVD3, 0x4018, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(uart4_cts_pb3, UARTD, RSVD1, RSVD2, RSVD3, 0x4020, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(uart4_rts_pb2, UARTD, RSVD1, RSVD2, RSVD3, 0x4028, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(uart4_rx_pb1, UARTD, RSVD1, RSVD2, RSVD3, 0x4030, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(uart4_tx_pb0, UARTD, RSVD1, RSVD2, RSVD3, 0x4038, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_wan4_pc0, RSVD0, RSVD1, RSVD2, RSVD3, 0x4040, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_wan3_pb6, RSVD0, RSVD1, RSVD2, RSVD3, 0x4048, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_wan2_pb5, RSVD0, RSVD1, RSVD2, RSVD3, 0x4050, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_wan1_pb4, RSVD0, RSVD1, RSVD2, RSVD3, 0x4058, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gen1_i2c_scl_pc5, I2C1, RSVD1, RSVD2, RSVD3, 0x4060, 0, Y, 5, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gen1_i2c_sda_pc6, I2C1, RSVD1, RSVD2, RSVD3, 0x4068, 0, Y, 5, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(uart1_cts_pt3, UARTA, RSVD1, RSVD2, RSVD3, 0x5000, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(uart1_rts_pt2, UARTA, RSVD1, RSVD2, RSVD3, 0x5008, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(uart1_rx_pt1, UARTA, RSVD1, RSVD2, RSVD3, 0x5010, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(uart1_tx_pt0, UARTA, RSVD1, RSVD2, RSVD3, 0x5018, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(directdc1_out3_pq5, DIRECTDC1, RSVD1, RSVD2, RSVD3, 0x5028, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, 15, 17, Y), + PINGROUP(directdc1_out2_pq4, DIRECTDC1, RSVD1, RSVD2, RSVD3, 0x5030, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, 15, 17, Y), + PINGROUP(directdc1_out1_pq3, DIRECTDC1, RSVD1, RSVD2, RSVD3, 0x5038, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, 15, 17, Y), + PINGROUP(directdc1_out0_pq2, DIRECTDC1, RSVD1, RSVD2, RSVD3, 0x5040, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, 15, 17, Y), + PINGROUP(directdc1_in_pq1, DIRECTDC1, RSVD1, RSVD2, RSVD3, 0x5048, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, 15, 17, Y), + PINGROUP(directdc1_clk_pq0, DIRECTDC1, RSVD1, RSVD2, RSVD3, 0x5050, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, 15, 17, Y), + PINGROUP(directdc_comp, DIRECTDC, RSVD1, RSVD2, RSVD3, 0x5058, 0, Y, -1, -1, -1, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(gpio_pq0_pi0, RSVD0, IQC0, I2S6, RSVD3, 0x3000, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(gpio_pq1_pi1, RSVD0, IQC0, I2S6, RSVD3, 0x3008, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(gpio_pq2_pi2, RSVD0, IQC0, I2S6, RSVD3, 0x3010, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(gpio_pq3_pi3, RSVD0, IQC0, I2S6, RSVD3, 0x3018, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(gpio_pq4_pi4, RSVD0, IQC1, DTV, RSVD3, 0x3020, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(gpio_pq5_pi5, RSVD0, IQC1, DTV, RSVD3, 0x3028, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(gpio_pq6_pi6, RSVD0, IQC1, DTV, RSVD3, 0x3030, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(gpio_pq7_pi7, RSVD0, IQC1, DTV, RSVD3, 0x3038, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(gpio_edp2_pp5, RSVD0, UARTF, SDMMC3, RSVD3, 0x10000, 0, Y, 5, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_edp3_pp6, RSVD0, UARTF, SDMMC1, RSVD3, 0x10008, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_edp0_pp3, RSVD0, UARTF, SDMMC3, RSVD3, 0x10010, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_edp1_pp4, RSVD0, UARTF, SDMMC1, RSVD3, 0x10018, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(dp_aux_ch0_hpd_pp0, DP, RSVD1, RSVD2, RSVD3, 0x10020, 0, Y, 5, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(dp_aux_ch1_hpd_pp1, DP, RSVD1, RSVD2, RSVD3, 0x10028, 0, Y, 5, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(hdmi_cec_pp2, HDMI, RSVD1, RSVD2, RSVD3, 0x10030, 0, Y, 5, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(pex_l2_clkreq_n_pa6, PE2, GP, SATA, RSVD3, 0x7000, 0, Y, 5, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(pex_wake_n_pa2, PE, RSVD1, RSVD2, RSVD3, 0x7008, 0, Y, 5, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(pex_l1_clkreq_n_pa4, PE1, RSVD1, RSVD2, RSVD3, 0x7010, 0, Y, 5, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(pex_l1_rst_n_pa3, PE1, RSVD1, RSVD2, RSVD3, 0x7018, 0, Y, 5, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(pex_l0_clkreq_n_pa1, PE0, RSVD1, RSVD2, RSVD3, 0x7020, 0, Y, 5, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(pex_l0_rst_n_pa0, PE0, RSVD1, RSVD2, RSVD3, 0x7028, 0, Y, 5, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(pex_l2_rst_n_pa5, PE2, SOC, SATA, RSVD3, 0x7030, 0, Y, 5, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(sdmmc1_clk_pd0, SDMMC1, RSVD1, RSVD2, RSVD3, 0x8000, 0, Y, 5, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(sdmmc1_cmd_pd1, SDMMC1, RSVD1, RSVD2, RSVD3, 0x8008, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(sdmmc1_comp, SDMMC1, RSVD1, RSVD2, RSVD3, 0x8010, 0, Y, -1, -1, 6, -1, -1, -1, -1, -1, N, -1, -1, N), + PINGROUP(sdmmc1_dat3_pd5, SDMMC1, RSVD1, RSVD2, RSVD3, 0x8014, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(sdmmc1_dat2_pd4, SDMMC1, RSVD1, RSVD2, RSVD3, 0x801c, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(sdmmc1_dat1_pd3, SDMMC1, RSVD1, RSVD2, RSVD3, 0x8024, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(sdmmc1_dat0_pd2, SDMMC1, RSVD1, RSVD2, RSVD3, 0x802c, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(eqos_td3_pe4, EQOS, SDMMC2, RSVD2, RSVD3, 0x9000, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(eqos_td2_pe3, EQOS, SDMMC2, RSVD2, RSVD3, 0x9008, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(eqos_td1_pe2, EQOS, SDMMC2, RSVD2, RSVD3, 0x9010, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(eqos_td0_pe1, EQOS, SDMMC2, RSVD2, RSVD3, 0x9018, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(eqos_rd3_pf1, EQOS, SDMMC2, RSVD2, RSVD3, 0x9020, 0, Y, -1, 5, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(eqos_rd2_pf0, EQOS, SDMMC2, RSVD2, RSVD3, 0x9028, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(eqos_rd1_pe7, EQOS, SDMMC2, RSVD2, RSVD3, 0x9030, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(eqos_mdio_pf4, EQOS, SOC, RSVD2, RSVD3, 0x9038, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(eqos_rd0_pe6, EQOS, SDMMC2, RSVD2, RSVD3, 0x9040, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(eqos_mdc_pf5, EQOS, RSVD1, RSVD2, RSVD3, 0x9048, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(eqos_comp, EQOS, SDMMC2, RSVD2, RSVD3, 0x9050, 0, Y, -1, -1, -1, -1, -1, -1, -1, -1, N, -1, -1, N), + PINGROUP(eqos_txc_pe0, EQOS, SDMMC2, RSVD2, RSVD3, 0x9054, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(eqos_rxc_pf3, EQOS, SDMMC2, RSVD2, RSVD3, 0x905c, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(eqos_tx_ctl_pe5, EQOS, SDMMC2, RSVD2, RSVD3, 0x9064, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(eqos_rx_ctl_pf2, EQOS, SDMMC2, RSVD2, RSVD3, 0x906c, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(sdmmc3_dat3_pg5, SDMMC3, RSVD1, RSVD2, RSVD3, 0xa000, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(sdmmc3_dat2_pg4, SDMMC3, RSVD1, RSVD2, RSVD3, 0xa008, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(sdmmc3_dat1_pg3, SDMMC3, RSVD1, RSVD2, RSVD3, 0xa010, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(sdmmc3_dat0_pg2, SDMMC3, RSVD1, RSVD2, RSVD3, 0xa018, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(sdmmc3_comp, SDMMC3, RSVD1, RSVD2, RSVD3, 0xa020, 0, Y, -1, -1, -1, -1, -1, -1, -1, -1, N, -1, -1, N), + PINGROUP(sdmmc3_cmd_pg1, SDMMC3, RSVD1, RSVD2, RSVD3, 0xa024, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(sdmmc3_clk_pg0, SDMMC3, RSVD1, RSVD1, RSVD3, 0xa02c, 0, Y, -1, 5, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(sdmmc4_clk, SDMMC4, RSVD1, RSVD2, RSVD3, 0x6004, 0, Y, -1, 5, 6, -1, 9, -1, -1, 12, Y, -1, -1, Y), + PINGROUP(sdmmc4_cmd, SDMMC4, RSVD1, RSVD2, RSVD3, 0x6008, 0, Y, -1, -1, 6, -1, 9, -1, -1, 12, Y, -1, -1, Y), + PINGROUP(sdmmc4_dqs, SDMMC4, RSVD1, RSVD2, RSVD3, 0x600c, 0, Y, -1, -1, 6, -1, 9, -1, -1, 12, Y, -1, -1, Y), + PINGROUP(sdmmc4_dat7, SDMMC4, RSVD1, RSVD2, RSVD3, 0x6010, 0, Y, -1, -1, 6, -1, 9, -1, -1, 12, Y, -1, -1, Y), + PINGROUP(sdmmc4_dat6, SDMMC4, RSVD1, RSVD2, RSVD3, 0x6014, 0, Y, -1, -1, 6, -1, 9, -1, -1, 12, Y, -1, -1, Y), + PINGROUP(sdmmc4_dat5, SDMMC4, RSVD1, RSVD2, RSVD3, 0x6018, 0, Y, -1, -1, 6, -1, 9, -1, -1, 12, Y, -1, -1, Y), + PINGROUP(sdmmc4_dat4, SDMMC4, RSVD1, RSVD2, RSVD3, 0x601c, 0, Y, -1, -1, 6, -1, 9, -1, -1, 12, Y, -1, -1, Y), + PINGROUP(sdmmc4_dat3, SDMMC4, RSVD1, RSVD2, RSVD3, 0x6020, 0, Y, -1, -1, 6, -1, 9, -1, -1, 12, Y, -1, -1, Y), + PINGROUP(sdmmc4_dat2, SDMMC4, RSVD1, RSVD2, RSVD3, 0x6024, 0, Y, -1, -1, 6, -1, 9, -1, -1, 12, Y, -1, -1, Y), + PINGROUP(sdmmc4_dat1, SDMMC4, RSVD1, RSVD2, RSVD3, 0x6028, 0, Y, -1, -1, 6, -1, 9, -1, -1, 12, Y, -1, -1, Y), + PINGROUP(sdmmc4_dat0, SDMMC4, RSVD1, RSVD2, RSVD3, 0x602c, 0, Y, -1, -1, 6, -1, 9, -1, -1, 12, Y, -1, -1, Y), + PINGROUP(qspi_io3_pr4, QSPI, RSVD1, RSVD2, RSVD3, 0xB000, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, 15, 17, Y), + PINGROUP(qspi_io2_pr3, QSPI, RSVD1, RSVD2, RSVD3, 0xB008, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, 15, 17, Y), + PINGROUP(qspi_io1_pr2, QSPI, RSVD1, RSVD2, RSVD3, 0xB010, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, 15, 17, Y), + PINGROUP(qspi_io0_pr1, QSPI, RSVD1, RSVD2, RSVD3, 0xB018, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, 15, 17, Y), + PINGROUP(qspi_sck_pr0, QSPI, RSVD1, RSVD2, RSVD3, 0xB020, 0, Y, -1, 5, 6, -1, 9, 10, -1, 12, Y, 15, 17, Y), + PINGROUP(qspi_cs_n_pr5, QSPI, RSVD1, RSVD2, RSVD3, 0xB028, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, 15, 17, Y), + PINGROUP(qspi_comp, QSPI, RSVD1, RSVD2, RSVD3, 0xB030, 0, Y, -1, -1, -1, -1, -1, -1, -1, -1, Y, -1, -1, Y), + PINGROUP(gpio_wan8_ph3, RSVD0, RSVD1, SPI1, RSVD3, 0xd000, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_wan7_ph2, RSVD0, RSVD1, SPI1, RSVD3, 0xd008, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_wan6_ph1, RSVD0, RSVD1, SPI1, RSVD3, 0xd010, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_wan5_ph0, RSVD0, RSVD1, SPI1, RSVD3, 0xd018, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(uart2_tx_px0, UARTB, RSVD1, RSVD2, RSVD3, 0xd020, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(uart2_rx_px1, UARTB, RSVD1, RSVD2, RSVD3, 0xd028, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(uart2_rts_px2, UARTB, RSVD1, RSVD2, RSVD3, 0xd030, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(uart2_cts_px3, UARTB, RSVD1, RSVD2, RSVD3, 0xd038, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(uart5_rx_px5, UARTE, SPI3, GP, RSVD3, 0xd040, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(uart5_tx_px4, UARTE, SPI3, NV, RSVD3, 0xd048, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(uart5_rts_px6, UARTE, SPI3, RSVD2, RSVD3, 0xd050, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(uart5_cts_px7, UARTE, SPI3, RSVD2, RSVD3, 0xd058, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_mdm1_py0, RSVD0, RSVD1, RSVD2, RSVD3, 0xd060, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_mdm2_py1, RSVD0, RSVD1, RSVD2, RSVD3, 0xd068, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_mdm3_py2, RSVD0, RSVD1, RSVD2, RSVD3, 0xd070, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_mdm4_py3, RSVD0, SPI1, CCLA, RSVD3, 0xd078, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_mdm5_py4, RSVD0, SPI1, RSVD2, RSVD3, 0xd080, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_mdm6_py5, SOC, RSVD1, RSVD2, RSVD3, 0xd088, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_mdm7_py6, RSVD0, RSVD1, RSVD2, RSVD3, 0xd090, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(bcpu_pwr_req_ph4, RSVD0, RSVD1, RSVD2, RSVD3, 0xd098, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(mcpu_pwr_req_ph5, RSVD0, RSVD1, RSVD2, RSVD3, 0xd0a0, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpu_pwr_req_ph6, RSVD0, RSVD1, RSVD2, RSVD3, 0xd0a8, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gen7_i2c_scl_pl0, I2C7, I2S5, RSVD2, RSVD3, 0xd0b0, 0, Y, 5, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gen7_i2c_sda_pl1, I2C7, I2S5, RSVD2, RSVD3, 0xd0b8, 0, Y, 5, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gen9_i2c_sda_pl3, I2C9, I2S5, RSVD2, RSVD3, 0xd0c0, 0, Y, 5, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gen9_i2c_scl_pl2, I2C9, I2S5, RSVD2, RSVD3, 0xd0c8, 0, Y, 5, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(usb_vbus_en0_pl4, USB, RSVD1, RSVD2, RSVD3, 0xd0d0, 0, Y, 5, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(usb_vbus_en1_pl5, USB, RSVD1, RSVD2, RSVD3, 0xd0d8, 0, Y, 5, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gp_pwm7_pl7, GP, RSVD1, RSVD2, RSVD3, 0xd0e0, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gp_pwm6_pl6, GP, RSVD1, RSVD2, RSVD3, 0xd0e8, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(ufs0_rst_pbb1, UFS0, RSVD1, RSVD2, RSVD3, 0x11000, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, 15, 17, Y), + PINGROUP(ufs0_ref_clk_pbb0, UFS0, RSVD1, RSVD2, RSVD3, 0x11008, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, 15, 17, Y), +}; + +static const struct tegra_pinctrl_soc_data tegra186_pinctrl = { + .pins = tegra186_pins, + .npins = ARRAY_SIZE(tegra186_pins), + .functions = tegra186_functions, + .nfunctions = ARRAY_SIZE(tegra186_functions), + .groups = tegra186_groups, + .ngroups = ARRAY_SIZE(tegra186_groups), + .hsm_in_mux = false, + .schmitt_in_mux = true, + .drvtype_in_mux = true, + .sfsel_in_mux = true, +}; + +static const struct pinctrl_pin_desc tegra186_aon_pins[] = { + PINCTRL_PIN(TEGRA_PIN_PWR_I2C_SCL_PS0, "PWR_I2C_SCL_PS0"), + PINCTRL_PIN(TEGRA_PIN_PWR_I2C_SDA_PS1, "PWR_I2C_SDA_PS1"), + PINCTRL_PIN(TEGRA_PIN_BATT_OC_PS2, "BATT_OC_PS2"), + PINCTRL_PIN(TEGRA_PIN_SAFE_STATE_PS3, "SAFE_STATE_PS3"), + PINCTRL_PIN(TEGRA_PIN_VCOMP_ALERT_PS4, "VCOMP_ALERT_PS4"), + PINCTRL_PIN(TEGRA_PIN_GPIO_DIS0_PU0, "GPIO_DIS0_PU0"), + PINCTRL_PIN(TEGRA_PIN_GPIO_DIS1_PU1, "GPIO_DIS1_PU1"), + PINCTRL_PIN(TEGRA_PIN_GPIO_DIS2_PU2, "GPIO_DIS2_PU2"), + PINCTRL_PIN(TEGRA_PIN_GPIO_DIS3_PU3, "GPIO_DIS3_PU3"), + PINCTRL_PIN(TEGRA_PIN_GPIO_DIS4_PU4, "GPIO_DIS4_PU4"), + PINCTRL_PIN(TEGRA_PIN_GPIO_DIS5_PU5, "GPIO_DIS5_PU5"), + PINCTRL_PIN(TEGRA_PIN_GPIO_SEN0_PV0, "GPIO_SEN0_PV0"), + PINCTRL_PIN(TEGRA_PIN_GPIO_SEN1_PV1, "GPIO_SEN1_PV1"), + PINCTRL_PIN(TEGRA_PIN_GPIO_SEN2_PV2, "GPIO_SEN2_PV2"), + PINCTRL_PIN(TEGRA_PIN_GPIO_SEN3_PV3, "GPIO_SEN3_PV3"), + PINCTRL_PIN(TEGRA_PIN_GPIO_SEN4_PV4, "GPIO_SEN4_PV4"), + PINCTRL_PIN(TEGRA_PIN_GPIO_SEN5_PV5, "GPIO_SEN5_PV5"), + PINCTRL_PIN(TEGRA_PIN_GPIO_SEN6_PV6, "GPIO_SEN6_PV6"), + PINCTRL_PIN(TEGRA_PIN_GPIO_SEN7_PV7, "GPIO_SEN7_PV7"), + PINCTRL_PIN(TEGRA_PIN_GEN8_I2C_SCL_PW0, "GEN8_I2C_SCL_PW0"), + PINCTRL_PIN(TEGRA_PIN_GEN8_I2C_SDA_PW1, "GEN8_I2C_SDA_PW1"), + PINCTRL_PIN(TEGRA_PIN_UART3_TX_PW2, "UART3_TX_PW2"), + PINCTRL_PIN(TEGRA_PIN_UART3_RX_PW3, "UART3_RX_PW3"), + PINCTRL_PIN(TEGRA_PIN_UART3_RTS_PW4, "UART3_RTS_PW4"), + PINCTRL_PIN(TEGRA_PIN_UART3_CTS_PW5, "UART3_CTS_PW5"), + PINCTRL_PIN(TEGRA_PIN_UART7_TX_PW6, "UART7_TX_PW6"), + PINCTRL_PIN(TEGRA_PIN_UART7_RX_PW7, "UART7_RX_PW7"), + PINCTRL_PIN(TEGRA_PIN_CAN1_DOUT_PZ0, "CAN1_DOUT_PZ0"), + PINCTRL_PIN(TEGRA_PIN_CAN1_DIN_PZ1, "CAN1_DIN_PZ1"), + PINCTRL_PIN(TEGRA_PIN_CAN0_DOUT_PZ2, "CAN0_DOUT_PZ2"), + PINCTRL_PIN(TEGRA_PIN_CAN0_DIN_PZ3, "CAN0_DIN_PZ3"), + PINCTRL_PIN(TEGRA_PIN_CAN_GPIO0_PAA0, "CAN_GPIO0_PAA0"), + PINCTRL_PIN(TEGRA_PIN_CAN_GPIO1_PAA1, "CAN_GPIO1_PAA1"), + PINCTRL_PIN(TEGRA_PIN_CAN_GPIO2_PAA2, "CAN_GPIO2_PAA2"), + PINCTRL_PIN(TEGRA_PIN_CAN_GPIO3_PAA3, "CAN_GPIO3_PAA3"), + PINCTRL_PIN(TEGRA_PIN_CAN_GPIO4_PAA4, "CAN_GPIO4_PAA4"), + PINCTRL_PIN(TEGRA_PIN_CAN_GPIO5_PAA5, "CAN_GPIO5_PAA5"), + PINCTRL_PIN(TEGRA_PIN_CAN_GPIO6_PAA6, "CAN_GPIO6_PAA6"), + PINCTRL_PIN(TEGRA_PIN_CAN_GPIO7_PAA7, "CAN_GPIO7_PAA7"), + PINCTRL_PIN(TEGRA_PIN_GPIO_SEN8_PEE0, "GPIO_SEN8_PEE0"), + PINCTRL_PIN(TEGRA_PIN_GPIO_SEN9_PEE1, "GPIO_SEN9_PEE1"), + PINCTRL_PIN(TEGRA_PIN_TOUCH_CLK_PEE2, "TOUCH_CLK_PEE2"), + PINCTRL_PIN(TEGRA_PIN_POWER_ON_PFF0, "POWER_ON_PFF0"), + PINCTRL_PIN(TEGRA_PIN_GPIO_SW1_PFF1, "GPIO_SW1_PFF1"), + PINCTRL_PIN(TEGRA_PIN_GPIO_SW2_PFF2, "GPIO_SW2_PFF2"), + PINCTRL_PIN(TEGRA_PIN_GPIO_SW3_PFF3, "GPIO_SW3_PFF3"), + PINCTRL_PIN(TEGRA_PIN_GPIO_SW4_PFF4, "GPIO_SW4_PFF4"), + PINCTRL_PIN(TEGRA_PIN_SHUTDOWN, "SHUTDOWN"), + PINCTRL_PIN(TEGRA_PIN_PMU_INT, "PMU_INT"), + PINCTRL_PIN(TEGRA_PIN_SOC_PWR_REQ, "SOC_PWR_REQ"), + PINCTRL_PIN(TEGRA_PIN_CLK_32K_IN, "CLK_32K_IN"), +}; + +static const struct tegra_pingroup tegra186_aon_groups[] = { + PINGROUP(touch_clk_pee2, TOUCH, RSVD1, RSVD2, RSVD3, 0x2000, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(uart3_cts_pw5, UARTC, RSVD1, RSVD2, RSVD3, 0x2008, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(uart3_rts_pw4, UARTC, RSVD1, RSVD2, RSVD3, 0x2010, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(uart3_rx_pw3, UARTC, RSVD1, RSVD2, RSVD3, 0x2018, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(uart3_tx_pw2, UARTC, RSVD1, RSVD2, RSVD3, 0x2020, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gen8_i2c_sda_pw1, I2C8, RSVD1, RSVD2, RSVD3, 0x2028, 0, Y, 5, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gen8_i2c_scl_pw0, I2C8, RSVD1, RSVD2, RSVD3, 0x2030, 0, Y, 5, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(uart7_rx_pw7, UARTG, RSVD1, RSVD2, RSVD3, 0x2038, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(uart7_tx_pw6, UARTG, RSVD1, RSVD2, RSVD3, 0x2040, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_sen0_pv0, RSVD0, RSVD1, RSVD2, RSVD3, 0x2048, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_sen1_pv1, SPI2, RSVD1, RSVD2, RSVD3, 0x2050, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_sen2_pv2, SPI2, RSVD1, RSVD2, RSVD3, 0x2058, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_sen3_pv3, SPI2, RSVD1, RSVD2, RSVD3, 0x2060, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_sen4_pv4, SPI2, RSVD1, RSVD2, RSVD3, 0x2068, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_sen5_pv5, RSVD0, RSVD1, RSVD2, RSVD3, 0x2070, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_sen6_pv6, RSVD0, GP, RSVD2, RSVD3, 0x2078, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_sen7_pv7, RSVD0, WDT, RSVD2, RSVD3, 0x2080, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_sen8_pee0, RSVD0, I2C2, RSVD2, RSVD3, 0x2088, 0, Y, 5, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_sen9_pee1, RSVD0, I2C2, RSVD2, RSVD3, 0x2090, 0, Y, 5, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(can_gpio7_paa7, RSVD0, WDT, RSVD2, RSVD3, 0x3000, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(can1_dout_pz0, CAN1, RSVD1, RSVD2, RSVD3, 0x3008, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(can1_din_pz1, CAN1, RSVD1, RSVD2, RSVD3, 0x3010, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(can0_dout_pz2, CAN0, RSVD1, RSVD2, RSVD3, 0x3018, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(can0_din_pz3, CAN0, RSVD1, RSVD2, RSVD3, 0x3020, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(can_gpio0_paa0, RSVD0, DMIC3, DMIC5, RSVD3, 0x3028, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(can_gpio1_paa1, RSVD0, DMIC3, DMIC5, RSVD3, 0x3030, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(can_gpio2_paa2, GPIO, RSVD1, RSVD2, RSVD3, 0x3038, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(can_gpio3_paa3, RSVD0, RSVD1, RSVD2, RSVD3, 0x3040, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(can_gpio4_paa4, RSVD0, RSVD1, RSVD2, RSVD3, 0x3048, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(can_gpio5_paa5, RSVD0, RSVD1, RSVD2, RSVD3, 0x3050, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(can_gpio6_paa6, RSVD0, RSVD1, RSVD2, RSVD3, 0x3058, 0, Y, -1, -1, 6, -1, 9, 10, -1, 12, Y, -1, -1, Y), + PINGROUP(gpio_sw1_pff1, RSVD0, RSVD1, RSVD2, RSVD3, 0x1000, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_sw2_pff2, RSVD0, RSVD1, RSVD2, RSVD3, 0x1008, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_sw3_pff3, RSVD0, RSVD1, RSVD2, RSVD3, 0x1010, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_sw4_pff4, RSVD0, RSVD1, RSVD2, RSVD3, 0x1018, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(shutdown, RSVD0, RSVD1, RSVD2, RSVD3, 0x1020, 0, Y, -1, -1, 6, 8, -1, -1, -1, 12, N, -1, -1, N), + PINGROUP(pmu_int, RSVD0, RSVD1, RSVD2, RSVD3, 0x1028, 0, Y, -1, -1, 6, 8, -1, -1, -1, 12, N, -1, -1, N), + PINGROUP(safe_state_ps3, SCE, RSVD1, RSVD2, RSVD3, 0x1030, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(vcomp_alert_ps4, SOC, RSVD1, RSVD2, RSVD3, 0x1038, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(soc_pwr_req, RSVD0, RSVD1, RSVD2, RSVD3, 0x1040, 0, Y, -1, -1, 6, 8, -1, -1, -1, 12, N, -1, -1, N), + PINGROUP(batt_oc_ps2, SOC, RSVD1, RSVD2, RSVD3, 0x1048, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(clk_32k_in, RSVD0, RSVD1, RSVD2, RSVD3, 0x1050, 0, Y, -1, -1, 6, 8, -1, -1, -1, -1, N, -1, -1, N), + PINGROUP(power_on_pff0, RSVD0, RSVD1, RSVD2, RSVD3, 0x1058, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(pwr_i2c_scl_ps0, I2C5, RSVD1, RSVD2, RSVD3, 0x1060, 0, Y, 5, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(pwr_i2c_sda_ps1, I2C5, RSVD1, RSVD2, RSVD3, 0x1068, 0, Y, 5, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_dis0_pu0, RSVD0, GP, DCB, DCC, 0x1080, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_dis1_pu1, RSVD0, RSVD1, DISPLAYA, RSVD3, 0x1088, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_dis2_pu2, RSVD0, GP, DCA, RSVD3, 0x1090, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_dis3_pu3, RSVD0, RSVD1, DISPLAYB, DCC, 0x1098, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_dis4_pu4, RSVD0, SOC, DCA, RSVD3, 0x10a0, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), + PINGROUP(gpio_dis5_pu5, RSVD0, GP, DCC, DCB, 0x10a8, 0, Y, -1, -1, 6, 8, -1, 10, 11, 12, N, -1, -1, N), +}; + +static const struct tegra_pinctrl_soc_data tegra186_pinctrl_aon = { + .pins = tegra186_aon_pins, + .npins = ARRAY_SIZE(tegra186_aon_pins), + .functions = tegra186_functions, + .nfunctions = ARRAY_SIZE(tegra186_functions), + .groups = tegra186_aon_groups, + .ngroups = ARRAY_SIZE(tegra186_aon_groups), + .hsm_in_mux = false, + .schmitt_in_mux = true, + .drvtype_in_mux = true, + .sfsel_in_mux = true, +}; + +static int tegra186_pinctrl_probe(struct platform_device *pdev) +{ + const struct tegra_pinctrl_soc_data *soc = of_device_get_match_data(&pdev->dev); + + return tegra_pinctrl_probe(pdev, soc); +} + +static const struct of_device_id tegra186_pinctrl_of_match[] = { + { .compatible = "nvidia,tegra186-pinmux", .data = &tegra186_pinctrl }, + { .compatible = "nvidia,tegra186-pinmux-aon", .data = &tegra186_pinctrl_aon }, + { }, +}; + +static struct platform_driver tegra186_pinctrl_driver = { + .driver = { + .name = "tegra186-pinctrl", + .of_match_table = tegra186_pinctrl_of_match, + }, + .probe = tegra186_pinctrl_probe, +}; + +static int __init tegra186_pinctrl_init(void) +{ + return platform_driver_register(&tegra186_pinctrl_driver); +} +arch_initcall(tegra186_pinctrl_init); diff --git a/drivers/soc/tegra/Kconfig b/drivers/soc/tegra/Kconfig index 9392c2c43cc8..c0fc54c3cd35 100644 --- a/drivers/soc/tegra/Kconfig +++ b/drivers/soc/tegra/Kconfig @@ -96,6 +96,7 @@ config ARCH_TEGRA_210_SOC config ARCH_TEGRA_186_SOC bool "NVIDIA Tegra186 SoC" depends on !CPU_BIG_ENDIAN + select PINCTRL_TEGRA186 select MAILBOX select SOC_TEGRA_PMC help From 76196742f49ed5e6b12804c8777c4c11a173289e Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Mon, 14 Jul 2025 12:46:37 +0000 Subject: [PATCH 01373/11391] pid: add Rust files to MAINTAINERS This files is maintained by Christian Brauner, thus add it to the relevant MAINTAINERS entry. Signed-off-by: Alice Ryhl Link: https://lore.kernel.org/20250714124637.1905722-2-aliceryhl@google.com Acked-by: Miguel Ojeda Signed-off-by: Christian Brauner --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index fe168477caa4..5f423e080718 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -19834,6 +19834,7 @@ M: Christian Brauner L: linux-kernel@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux.git +F: rust/kernel/pid_namespace.rs F: samples/pidfd/ F: tools/testing/selftests/clone3/ F: tools/testing/selftests/pid_namespace/ From 73861970938ad1323eb02bbbc87f6fbd1e5bacca Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Wed, 13 Aug 2025 00:17:44 +0900 Subject: [PATCH 01374/11391] minixfs: Verify inode mode when loading from disk The inode mode loaded from corrupted disk can be invalid. Do like what commit 0a9e74051313 ("isofs: Verify inode mode when loading from disk") does. Reported-by: syzbot Closes: https://syzkaller.appspot.com/bug?extid=895c23f6917da440ed0d Signed-off-by: Tetsuo Handa Link: https://lore.kernel.org/ec982681-84b8-4624-94fa-8af15b77cbd2@I-love.SAKURA.ne.jp Signed-off-by: Christian Brauner --- fs/minix/inode.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fs/minix/inode.c b/fs/minix/inode.c index df9d11479caf..32db676127a9 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -492,8 +492,14 @@ void minix_set_inode(struct inode *inode, dev_t rdev) inode->i_op = &minix_symlink_inode_operations; inode_nohighmem(inode); inode->i_mapping->a_ops = &minix_aops; - } else + } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || + S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { init_special_inode(inode, inode->i_mode, rdev); + } else { + printk(KERN_DEBUG "MINIX-fs: Invalid file type 0%04o for inode %lu.\n", + inode->i_mode, inode->i_ino); + make_bad_inode(inode); + } } /* From 96d6bc84742f9e08b70bd1193da32cf0f09a0058 Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Tue, 12 Aug 2025 15:54:44 +0800 Subject: [PATCH 01375/11391] pinctrl: equilibrium: Remove redundant semicolons Remove unnecessary semicolons. Fixes: 1948d5c51dba4 ("pinctrl: Add pinmux & GPIO controller driver for a new SoC") Signed-off-by: Liao Yuanhong Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/20250812075444.8310-1-liaoyuanhong@vivo.com Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-equilibrium.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/pinctrl-equilibrium.c b/drivers/pinctrl/pinctrl-equilibrium.c index 210044185679..01731d51a7c4 100644 --- a/drivers/pinctrl/pinctrl-equilibrium.c +++ b/drivers/pinctrl/pinctrl-equilibrium.c @@ -445,7 +445,7 @@ static int eqbr_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, } raw_spin_unlock_irqrestore(&pctl->lock, flags); *config = pinconf_to_config_packed(param, val); -; + return 0; } From 006568ab4c5ca2309ceb36fa553e390b4aa9c0c7 Mon Sep 17 00:00:00 2001 From: gaoxiang17 Date: Sat, 2 Aug 2025 10:21:23 +0800 Subject: [PATCH 01376/11391] pid: Add a judgment for ns null in pid_nr_ns __task_pid_nr_ns ns = task_active_pid_ns(current); pid_nr_ns(rcu_dereference(*task_pid_ptr(task, type)), ns); if (pid && ns->level <= pid->level) { Sometimes null is returned for task_active_pid_ns. Then it will trigger kernel panic in pid_nr_ns. For example: Unable to handle kernel NULL pointer dereference at virtual address 0000000000000058 Mem abort info: ESR = 0x0000000096000007 EC = 0x25: DABT (current EL), IL = 32 bits SET = 0, FnV = 0 EA = 0, S1PTW = 0 FSC = 0x07: level 3 translation fault Data abort info: ISV = 0, ISS = 0x00000007, ISS2 = 0x00000000 CM = 0, WnR = 0, TnD = 0, TagAccess = 0 GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 user pgtable: 4k pages, 39-bit VAs, pgdp=00000002175aa000 [0000000000000058] pgd=08000002175ab003, p4d=08000002175ab003, pud=08000002175ab003, pmd=08000002175be003, pte=0000000000000000 pstate: 834000c5 (Nzcv daIF +PAN -UAO +TCO +DIT -SSBS BTYPE=--) pc : __task_pid_nr_ns+0x74/0xd0 lr : __task_pid_nr_ns+0x24/0xd0 sp : ffffffc08001bd10 x29: ffffffc08001bd10 x28: ffffffd4422b2000 x27: 0000000000000001 x26: ffffffd442821168 x25: ffffffd442821000 x24: 00000f89492eab31 x23: 00000000000000c0 x22: ffffff806f5693c0 x21: ffffff806f5693c0 x20: 0000000000000001 x19: 0000000000000000 x18: 0000000000000000 x17: 00000000529c6ef0 x16: 00000000529c6ef0 x15: 00000000023a1adc x14: 0000000000000003 x13: 00000000007ef6d8 x12: 001167c391c78800 x11: 00ffffffffffffff x10: 0000000000000000 x9 : 0000000000000001 x8 : ffffff80816fa3c0 x7 : 0000000000000000 x6 : 49534d702d535449 x5 : ffffffc080c4c2c0 x4 : ffffffd43ee128c8 x3 : ffffffd43ee124dc x2 : 0000000000000000 x1 : 0000000000000001 x0 : ffffff806f5693c0 Call trace: __task_pid_nr_ns+0x74/0xd0 ... __handle_irq_event_percpu+0xd4/0x284 handle_irq_event+0x48/0xb0 handle_fasteoi_irq+0x160/0x2d8 generic_handle_domain_irq+0x44/0x60 gic_handle_irq+0x4c/0x114 call_on_irq_stack+0x3c/0x74 do_interrupt_handler+0x4c/0x84 el1_interrupt+0x34/0x58 el1h_64_irq_handler+0x18/0x24 el1h_64_irq+0x68/0x6c account_kernel_stack+0x60/0x144 exit_task_stack_account+0x1c/0x80 do_exit+0x7e4/0xaf8 ... get_signal+0x7bc/0x8d8 do_notify_resume+0x128/0x828 el0_svc+0x6c/0x70 el0t_64_sync_handler+0x68/0xbc el0t_64_sync+0x1a8/0x1ac Code: 35fffe54 911a02a8 f9400108 b4000128 (b9405a69) ---[ end trace 0000000000000000 ]--- Kernel panic - not syncing: Oops: Fatal exception in interrupt Signed-off-by: gaoxiang17 Link: https://lore.kernel.org/20250802022123.3536934-1-gxxa03070307@gmail.com Reviewed-by: Baoquan He Signed-off-by: Christian Brauner --- kernel/pid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/pid.c b/kernel/pid.c index c45a28c16cd2..14e908f2f0cb 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -491,7 +491,7 @@ pid_t pid_nr_ns(struct pid *pid, struct pid_namespace *ns) struct upid *upid; pid_t nr = 0; - if (pid && ns->level <= pid->level) { + if (pid && ns && ns->level <= pid->level) { upid = &pid->numbers[ns->level]; if (upid->ns == ns) nr = upid->nr; From abdfd4948e45c51b19162cf8b3f5003f8f53c9b9 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sun, 10 Aug 2025 19:36:04 +0200 Subject: [PATCH 01377/11391] pid: make __task_pid_nr_ns(ns => NULL) safe for zombie callers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit task_pid_vnr(another_task) will crash if the caller was already reaped. The pid_alive(current) check can't really help, the parent/debugger can call release_task() right after this check. This also means that even task_ppid_nr_ns(current, NULL) is not safe, pid_alive() only ensures that it is safe to dereference ->real_parent. Change __task_pid_nr_ns() to ensure ns != NULL. Originally-by: 高翔 Link: https://lore.kernel.org/all/20250802022123.3536934-1-gxxa03070307@gmail.com/ Signed-off-by: Oleg Nesterov Link: https://lore.kernel.org/20250810173604.GA19991@redhat.com Signed-off-by: Christian Brauner --- kernel/pid.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/pid.c b/kernel/pid.c index 14e908f2f0cb..f62a7df2f04c 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -514,7 +514,8 @@ pid_t __task_pid_nr_ns(struct task_struct *task, enum pid_type type, rcu_read_lock(); if (!ns) ns = task_active_pid_ns(current); - nr = pid_nr_ns(rcu_dereference(*task_pid_ptr(task, type)), ns); + if (ns) + nr = pid_nr_ns(rcu_dereference(*task_pid_ptr(task, type)), ns); rcu_read_unlock(); return nr; From b1afcaddd6c8475ee346a60525f9504965673e0c Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sun, 10 Aug 2025 19:36:15 +0200 Subject: [PATCH 01378/11391] pid: change bacct_add_tsk() to use task_ppid_nr_ns() to simplify the code. Signed-off-by: Oleg Nesterov Link: https://lore.kernel.org/20250810173615.GA20000@redhat.com Signed-off-by: Christian Brauner --- kernel/tsacct.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kernel/tsacct.c b/kernel/tsacct.c index 16b283f9d831..6ea2f6363b90 100644 --- a/kernel/tsacct.c +++ b/kernel/tsacct.c @@ -57,12 +57,11 @@ void bacct_add_tsk(struct user_namespace *user_ns, stats->ac_sched = tsk->policy; stats->ac_pid = task_pid_nr_ns(tsk, pid_ns); stats->ac_tgid = task_tgid_nr_ns(tsk, pid_ns); + stats->ac_ppid = task_ppid_nr_ns(tsk, pid_ns); rcu_read_lock(); tcred = __task_cred(tsk); stats->ac_uid = from_kuid_munged(user_ns, tcred->uid); stats->ac_gid = from_kgid_munged(user_ns, tcred->gid); - stats->ac_ppid = pid_alive(tsk) ? - task_tgid_nr_ns(rcu_dereference(tsk->real_parent), pid_ns) : 0; rcu_read_unlock(); task_cputime(tsk, &utime, &stime); From d00f5232851c4895db8f0228881c31608feaab30 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sun, 10 Aug 2025 19:36:20 +0200 Subject: [PATCH 01379/11391] pid: change task_state() to use task_ppid_nr_ns() to simplify the code. Note that only tpid and max_fds really need rcu_read_lock(), we could move task_ppid_nr_ns/task_tgid_nr_ns/task_numa_group_id/get_task_cred outside of rcu read section. Signed-off-by: Oleg Nesterov Link: https://lore.kernel.org/20250810173620.GA20007@redhat.com Signed-off-by: Christian Brauner --- fs/proc/array.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/proc/array.c b/fs/proc/array.c index d6a0369caa93..69269745d73b 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -157,13 +157,11 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns, unsigned int max_fds = 0; rcu_read_lock(); - ppid = pid_alive(p) ? - task_tgid_nr_ns(rcu_dereference(p->real_parent), ns) : 0; - tracer = ptrace_parent(p); if (tracer) tpid = task_pid_nr_ns(tracer, ns); + ppid = task_ppid_nr_ns(p, ns); tgid = task_tgid_nr_ns(p, ns); ngid = task_numa_group_id(p); cred = get_task_cred(p); From 12cc0ff3cdd95f2bc0ffdc63bcd9da231eb33199 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 19 Aug 2025 11:01:46 +0100 Subject: [PATCH 01380/11391] ASoC: qcom: audioreach: deprecate AR_TKN_U32_MODULE_[IN/OUT]_PORTS Deprecate usage of AR_TKN_U32_MODULE_IN_PORTS and AR_TKN_U32_MODULE_OUT_PORTS as the connectivity of modules is taken care by AR_TKN_U32_MODULE_SRC_OP_PORT_ID* and AR_TKN_U32_MODULE_DST_IN_PORT_ID* Also this property is never used in the drivers. Signed-off-by: Srinivas Kandagatla Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250819100151.1294047-2-srinivas.kandagatla@oss.qualcomm.com Signed-off-by: Mark Brown --- include/uapi/sound/snd_ar_tokens.h | 4 ++-- sound/soc/qcom/qdsp6/audioreach.h | 3 --- sound/soc/qcom/qdsp6/topology.c | 10 +--------- 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/include/uapi/sound/snd_ar_tokens.h b/include/uapi/sound/snd_ar_tokens.h index b9b9093b4396..bc0b1bede00c 100644 --- a/include/uapi/sound/snd_ar_tokens.h +++ b/include/uapi/sound/snd_ar_tokens.h @@ -184,8 +184,8 @@ enum ar_event_types { #define AR_TKN_U32_MODULE_INSTANCE_ID 201 #define AR_TKN_U32_MODULE_MAX_IP_PORTS 202 #define AR_TKN_U32_MODULE_MAX_OP_PORTS 203 -#define AR_TKN_U32_MODULE_IN_PORTS 204 -#define AR_TKN_U32_MODULE_OUT_PORTS 205 +#define AR_TKN_U32_MODULE_IN_PORTS 204 /* deprecated */ +#define AR_TKN_U32_MODULE_OUT_PORTS 205 /* deprecated */ #define AR_TKN_U32_MODULE_SRC_OP_PORT_ID 206 #define AR_TKN_U32_MODULE_DST_IN_PORT_ID 207 #define AR_TKN_U32_MODULE_SRC_INSTANCE_ID 208 diff --git a/sound/soc/qcom/qdsp6/audioreach.h b/sound/soc/qcom/qdsp6/audioreach.h index 61a69df4f50f..9b30177463e6 100644 --- a/sound/soc/qcom/qdsp6/audioreach.h +++ b/sound/soc/qcom/qdsp6/audioreach.h @@ -707,9 +707,6 @@ struct audioreach_module { uint32_t max_ip_port; uint32_t max_op_port; - uint32_t in_port; - uint32_t out_port; - uint32_t num_connections; /* Connections */ uint32_t src_mod_inst_id; diff --git a/sound/soc/qcom/qdsp6/topology.c b/sound/soc/qcom/qdsp6/topology.c index 83319a928f29..a3b0f558260c 100644 --- a/sound/soc/qcom/qdsp6/topology.c +++ b/sound/soc/qcom/qdsp6/topology.c @@ -412,7 +412,7 @@ static struct audioreach_module *audioreach_parse_common_tokens(struct q6apm *ap struct snd_soc_tplg_private *private, struct snd_soc_dapm_widget *w) { - uint32_t max_ip_port = 0, max_op_port = 0, in_port = 0, out_port = 0; + uint32_t max_ip_port = 0, max_op_port = 0; uint32_t src_mod_op_port_id[AR_MAX_MOD_LINKS] = { 0, }; uint32_t dst_mod_inst_id[AR_MAX_MOD_LINKS] = { 0, }; uint32_t dst_mod_ip_port_id[AR_MAX_MOD_LINKS] = { 0, }; @@ -455,12 +455,6 @@ static struct audioreach_module *audioreach_parse_common_tokens(struct q6apm *ap case AR_TKN_U32_MODULE_MAX_OP_PORTS: max_op_port = le32_to_cpu(mod_elem->value); break; - case AR_TKN_U32_MODULE_IN_PORTS: - in_port = le32_to_cpu(mod_elem->value); - break; - case AR_TKN_U32_MODULE_OUT_PORTS: - out_port = le32_to_cpu(mod_elem->value); - break; case AR_TKN_U32_MODULE_SRC_INSTANCE_ID: src_mod_inst_id = le32_to_cpu(mod_elem->value); break; @@ -550,8 +544,6 @@ static struct audioreach_module *audioreach_parse_common_tokens(struct q6apm *ap mod->module_id = module_id; mod->max_ip_port = max_ip_port; mod->max_op_port = max_op_port; - mod->in_port = in_port; - mod->out_port = out_port; mod->src_mod_inst_id = src_mod_inst_id; for (pn = 0; pn < mod->max_op_port; pn++) { if (src_mod_op_port_id[pn] && dst_mod_inst_id[pn] && From f07b81b573b28e5cae5c1482001ad0d6c0b7c051 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 19 Aug 2025 11:01:47 +0100 Subject: [PATCH 01381/11391] ASoC: qcom: audioreach: add documentation for i2s interface type Add documentation of possible values for I2S interface types, currently this is only documented for DMA module. Signed-off-by: Srinivas Kandagatla Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250819100151.1294047-3-srinivas.kandagatla@oss.qualcomm.com Signed-off-by: Mark Brown --- include/uapi/sound/snd_ar_tokens.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/uapi/sound/snd_ar_tokens.h b/include/uapi/sound/snd_ar_tokens.h index bc0b1bede00c..92cf72a6fdd4 100644 --- a/include/uapi/sound/snd_ar_tokens.h +++ b/include/uapi/sound/snd_ar_tokens.h @@ -118,6 +118,12 @@ enum ar_event_types { * LPAIF_WSA = 2, * LPAIF_VA = 3, * LPAIF_AXI = 4 + * Possible values for MI2S + * I2S_INTF_TYPE_PRIMARY = 0, + * I2S_INTF_TYPE_SECONDARY = 1, + * I2S_INTF_TYPE_TERTIARY = 2, + * I2S_INTF_TYPE_QUATERNARY = 3, + * I2S_INTF_TYPE_QUINARY = 4, * * %AR_TKN_U32_MODULE_FMT_INTERLEAVE: PCM Interleaving * PCM_INTERLEAVED = 1, From c7ed4c2debfd192f6071f4ab33c092d419abb941 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 19 Aug 2025 11:01:48 +0100 Subject: [PATCH 01382/11391] ASoC: qcom: audioreach: add support for static calibration This change adds support for static calibration data via ASoC topology file. This static calibration data could include binary blob of data that is required by specific module and is not part of topology tokens. Reason for adding this support is to allow loading module specific data that can not be part of the tplg tokens, example, Echo and Noise cancelling module needs a blob of calibration data to function correctly. This support is also one of the building block for adding speaker protection support. Tested this with Single Mic ECNS(Echo and Noise Cancellation). tplg can now contain this calibration data like: SectionWidget."stream2.SMECNS_V224" { ... data [ ... "stream2.SMECNS_V224_cfg_data" ] } SectionData."stream2.SMECNS_V224_cfg_data" { words "0x00000330, 0x01001006,0x00000000,0x00000000, 0x00004145,0x08001026,0x00000004,0x00000000, ..." } } Signed-off-by: Srinivas Kandagatla Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250819100151.1294047-4-srinivas.kandagatla@oss.qualcomm.com Signed-off-by: Mark Brown --- include/uapi/sound/snd_ar_tokens.h | 10 ++++++++++ sound/soc/qcom/qdsp6/audioreach.h | 2 ++ sound/soc/qcom/qdsp6/topology.c | 31 ++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/include/uapi/sound/snd_ar_tokens.h b/include/uapi/sound/snd_ar_tokens.h index 92cf72a6fdd4..6b8102eaa121 100644 --- a/include/uapi/sound/snd_ar_tokens.h +++ b/include/uapi/sound/snd_ar_tokens.h @@ -3,6 +3,8 @@ #ifndef __SND_AR_TOKENS_H__ #define __SND_AR_TOKENS_H__ +#include + #define APM_SUB_GRAPH_PERF_MODE_LOW_POWER 0x1 #define APM_SUB_GRAPH_PERF_MODE_LOW_LATENCY 0x2 @@ -238,4 +240,12 @@ enum ar_event_types { #define AR_TKN_U32_MODULE_LOG_TAP_POINT_ID 260 #define AR_TKN_U32_MODULE_LOG_MODE 261 +#define SND_SOC_AR_TPLG_MODULE_CFG_TYPE 0x01001006 +struct audioreach_module_priv_data { + __le32 size; /* size in bytes of the array, including all elements */ + __le32 type; /* SND_SOC_AR_TPLG_MODULE_CFG_TYPE */ + __le32 priv[2]; /* Private data for future expansion */ + __le32 data[0]; /* config data */ +}; + #endif /* __SND_AR_TOKENS_H__ */ diff --git a/sound/soc/qcom/qdsp6/audioreach.h b/sound/soc/qcom/qdsp6/audioreach.h index 9b30177463e6..617bda051cf8 100644 --- a/sound/soc/qcom/qdsp6/audioreach.h +++ b/sound/soc/qcom/qdsp6/audioreach.h @@ -4,6 +4,7 @@ #define __AUDIOREACH_H__ #include #include +#include #include struct q6apm; struct q6apm_graph; @@ -742,6 +743,7 @@ struct audioreach_module { struct list_head node; struct audioreach_container *container; struct snd_soc_dapm_widget *widget; + struct audioreach_module_priv_data *data; }; struct audioreach_module_config { diff --git a/sound/soc/qcom/qdsp6/topology.c b/sound/soc/qcom/qdsp6/topology.c index a3b0f558260c..ec51fabd98cb 100644 --- a/sound/soc/qcom/qdsp6/topology.c +++ b/sound/soc/qcom/qdsp6/topology.c @@ -305,6 +305,34 @@ static struct snd_soc_tplg_vendor_array *audioreach_get_module_array( return NULL; } +static struct audioreach_module_priv_data *audioreach_get_module_priv_data( + struct snd_soc_tplg_private *private) +{ + int sz; + + for (sz = 0; sz < le32_to_cpu(private->size); ) { + struct snd_soc_tplg_vendor_array *mod_array; + + mod_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz); + if (mod_array->type == SND_SOC_AR_TPLG_MODULE_CFG_TYPE) { + struct audioreach_module_priv_data *pdata; + + pdata = kzalloc(struct_size(pdata, data, le32_to_cpu(mod_array->size)), + GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + memcpy(pdata, ((u8 *)private->data + sz), struct_size(pdata, data, + le32_to_cpu(mod_array->size))); + return pdata; + } + + sz = sz + le32_to_cpu(mod_array->size); + } + + return NULL; +} + static struct audioreach_sub_graph *audioreach_parse_sg_tokens(struct q6apm *apm, struct snd_soc_tplg_private *private) { @@ -582,6 +610,8 @@ static int audioreach_widget_load_module_common(struct snd_soc_component *compon if (IS_ERR(mod)) return PTR_ERR(mod); + mod->data = audioreach_get_module_priv_data(&tplg_w->priv); + dobj = &w->dobj; dobj->private = mod; @@ -939,6 +969,7 @@ static int audioreach_widget_unload(struct snd_soc_component *scomp, cont->num_modules--; list_del(&mod->node); + kfree(mod->data); kfree(mod); /* Graph Info has N sub-graphs, sub-graph has N containers, Container has N Modules */ if (list_empty(&cont->modules_list)) { /* if no modules in the container then remove it */ From 0f5787df78799c7c8a7dbd2de5ff15250d8d3a4e Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 19 Aug 2025 11:01:49 +0100 Subject: [PATCH 01383/11391] ASoC: qcom: audioreach: fix typos in I2S_INTF_TYPE Fix spelling mistakes in I2S_INTF_TYPE defines. Reported-by: Krzysztof Kozlowski Signed-off-by: Srinivas Kandagatla Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250819100151.1294047-5-srinivas.kandagatla@oss.qualcomm.com Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/audioreach.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/qcom/qdsp6/audioreach.h b/sound/soc/qcom/qdsp6/audioreach.h index 617bda051cf8..efc918452e2a 100644 --- a/sound/soc/qcom/qdsp6/audioreach.h +++ b/sound/soc/qcom/qdsp6/audioreach.h @@ -462,8 +462,8 @@ struct param_id_i2s_intf_cfg { } __packed; #define I2S_INTF_TYPE_PRIMARY 0 -#define I2S_INTF_TYPE_SECOINDARY 1 -#define I2S_INTF_TYPE_TERTINARY 2 +#define I2S_INTF_TYPE_SECONDARY 1 +#define I2S_INTF_TYPE_TERTIARY 2 #define I2S_INTF_TYPE_QUATERNARY 3 #define I2S_INTF_TYPE_QUINARY 4 #define I2S_SD0 1 From 97a719fe7d7001d361490b44985f8b4c7ea6ef98 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 19 Aug 2025 11:01:50 +0100 Subject: [PATCH 01384/11391] ASoC: qcom: audioreach: sort modules based on hex ids Sort the module defines based on its hex ids. Signed-off-by: Srinivas Kandagatla Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250819100151.1294047-6-srinivas.kandagatla@oss.qualcomm.com Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/audioreach.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/qcom/qdsp6/audioreach.h b/sound/soc/qcom/qdsp6/audioreach.h index efc918452e2a..e4babf9a44ff 100644 --- a/sound/soc/qcom/qdsp6/audioreach.h +++ b/sound/soc/qcom/qdsp6/audioreach.h @@ -18,14 +18,14 @@ struct q6apm_graph; #define MODULE_ID_PCM_DEC 0x07001005 #define MODULE_ID_PLACEHOLDER_ENCODER 0x07001008 #define MODULE_ID_PLACEHOLDER_DECODER 0x07001009 -#define MODULE_ID_SAL 0x07001010 -#define MODULE_ID_MFC 0x07001015 -#define MODULE_ID_CODEC_DMA_SINK 0x07001023 -#define MODULE_ID_CODEC_DMA_SOURCE 0x07001024 #define MODULE_ID_I2S_SINK 0x0700100A #define MODULE_ID_I2S_SOURCE 0x0700100B +#define MODULE_ID_SAL 0x07001010 +#define MODULE_ID_MFC 0x07001015 #define MODULE_ID_DATA_LOGGING 0x0700101A #define MODULE_ID_AAC_DEC 0x0700101F +#define MODULE_ID_CODEC_DMA_SINK 0x07001023 +#define MODULE_ID_CODEC_DMA_SOURCE 0x07001024 #define MODULE_ID_FLAC_DEC 0x0700102F #define MODULE_ID_MP3_DECODE 0x0700103B #define MODULE_ID_GAPLESS 0x0700104D From da9881d00153cc6d3917f6b74144b1d41b58338c Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 19 Aug 2025 11:01:51 +0100 Subject: [PATCH 01385/11391] ASoC: qcom: audioreach: add support for SMECNS module This patch adds support for Single Mic ECNS module, used for echo cancellation. It also makes use of audioreach_set_module_config to load the calibration data for this module from ASoC tplg file. Signed-off-by: Srinivas Kandagatla Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250819100151.1294047-7-srinivas.kandagatla@oss.qualcomm.com Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/audioreach.c | 27 +++++++++++++++++++++++++++ sound/soc/qcom/qdsp6/audioreach.h | 1 + 2 files changed, 28 insertions(+) diff --git a/sound/soc/qcom/qdsp6/audioreach.c b/sound/soc/qcom/qdsp6/audioreach.c index 4ebaaf736fb9..f4c53e84b4dc 100644 --- a/sound/soc/qcom/qdsp6/audioreach.c +++ b/sound/soc/qcom/qdsp6/audioreach.c @@ -811,6 +811,30 @@ static int audioreach_gapless_set_media_format(struct q6apm_graph *graph, EARLY_EOS_DELAY_MS); } +static int audioreach_set_module_config(struct q6apm_graph *graph, + struct audioreach_module *module, + struct audioreach_module_config *cfg) +{ + int payload_size = module->data->size; + struct gpr_pkt *pkt; + int rc; + void *p; + + pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0); + if (IS_ERR(pkt)) + return PTR_ERR(pkt); + + p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE; + + memcpy(p, module->data->data, payload_size); + + rc = q6apm_send_cmd_sync(graph->apm, pkt, 0); + + kfree(pkt); + + return rc; +} + static int audioreach_mfc_set_media_format(struct q6apm_graph *graph, struct audioreach_module *module, struct audioreach_module_config *cfg) @@ -1247,6 +1271,9 @@ int audioreach_set_media_format(struct q6apm_graph *graph, struct audioreach_mod case MODULE_ID_DISPLAY_PORT_SINK: rc = audioreach_display_port_set_media_format(graph, module, cfg); break; + case MODULE_ID_SMECNS_V2: + rc = audioreach_set_module_config(graph, module, cfg); + break; case MODULE_ID_I2S_SOURCE: case MODULE_ID_I2S_SINK: rc = audioreach_i2s_set_media_format(graph, module, cfg); diff --git a/sound/soc/qcom/qdsp6/audioreach.h b/sound/soc/qcom/qdsp6/audioreach.h index e4babf9a44ff..790fba96e34d 100644 --- a/sound/soc/qcom/qdsp6/audioreach.h +++ b/sound/soc/qcom/qdsp6/audioreach.h @@ -27,6 +27,7 @@ struct q6apm_graph; #define MODULE_ID_CODEC_DMA_SINK 0x07001023 #define MODULE_ID_CODEC_DMA_SOURCE 0x07001024 #define MODULE_ID_FLAC_DEC 0x0700102F +#define MODULE_ID_SMECNS_V2 0x07001031 #define MODULE_ID_MP3_DECODE 0x0700103B #define MODULE_ID_GAPLESS 0x0700104D #define MODULE_ID_DISPLAY_PORT_SINK 0x07001069 From c1dd310f1d76b4b13f1854618087af2513140897 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Tue, 19 Aug 2025 12:02:38 +0800 Subject: [PATCH 01386/11391] spi: SPISG: Use devm_kcalloc() in aml_spisg_clk_init() Replace calls of devm_kzalloc() with devm_kcalloc() in aml_spisg_clk_init() for safer memory allocation with built-in overflow protection, and replace sizeof(struct clk_div_table) with sizeof(*tbl) to shorten the line. Signed-off-by: Qianfeng Rong Link: https://patch.msgid.link/20250819040239.434863-1-rongqianfeng@vivo.com Signed-off-by: Mark Brown --- drivers/spi/spi-amlogic-spisg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-amlogic-spisg.c b/drivers/spi/spi-amlogic-spisg.c index 2ab8bdf2a676..64244a0bd408 100644 --- a/drivers/spi/spi-amlogic-spisg.c +++ b/drivers/spi/spi-amlogic-spisg.c @@ -662,7 +662,7 @@ static int aml_spisg_clk_init(struct spisg_device *spisg, void __iomem *base) clk_disable_unprepare(spisg->pclk); - tbl = devm_kzalloc(dev, sizeof(struct clk_div_table) * (DIV_NUM + 1), GFP_KERNEL); + tbl = devm_kcalloc(dev, (DIV_NUM + 1), sizeof(*tbl), GFP_KERNEL); if (!tbl) return -ENOMEM; From 2a5d410916d3a8dcac06f72494f252314e933cfb Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Tue, 19 Aug 2025 17:20:38 +0800 Subject: [PATCH 01387/11391] spi: spi_amd: 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 Link: https://patch.msgid.link/20250819092044.549464-2-zhao.xichao@vivo.com Signed-off-by: Mark Brown --- drivers/spi/spi-amd-pci.c | 5 ++--- drivers/spi/spi-amd.c | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-amd-pci.c b/drivers/spi/spi-amd-pci.c index e5faab414c17..d48c3a5da303 100644 --- a/drivers/spi/spi-amd-pci.c +++ b/drivers/spi/spi-amd-pci.c @@ -38,7 +38,7 @@ static int amd_spi_pci_probe(struct pci_dev *pdev, /* Allocate storage for host and driver private data */ host = devm_spi_alloc_host(dev, sizeof(struct amd_spi)); if (!host) - return dev_err_probe(dev, -ENOMEM, "Error allocating SPI host\n"); + return -ENOMEM; amd_spi = spi_controller_get_devdata(host); @@ -47,8 +47,7 @@ static int amd_spi_pci_probe(struct pci_dev *pdev, amd_spi->io_remap_addr = devm_ioremap(dev, io_base_addr, AMD_HID2_MEM_SIZE); if (!amd_spi->io_remap_addr) - return dev_err_probe(dev, -ENOMEM, - "ioremap of SPI registers failed\n"); + return -ENOMEM; dev_dbg(dev, "io_remap_address: %p\n", amd_spi->io_remap_addr); diff --git a/drivers/spi/spi-amd.c b/drivers/spi/spi-amd.c index 02e7fe095a0b..4d1dce4f4974 100644 --- a/drivers/spi/spi-amd.c +++ b/drivers/spi/spi-amd.c @@ -857,7 +857,7 @@ static int amd_spi_probe(struct platform_device *pdev) /* Allocate storage for host and driver private data */ host = devm_spi_alloc_host(dev, sizeof(struct amd_spi)); if (!host) - return dev_err_probe(dev, -ENOMEM, "Error allocating SPI host\n"); + return -ENOMEM; amd_spi = spi_controller_get_devdata(host); amd_spi->io_remap_addr = devm_platform_ioremap_resource(pdev, 0); From 0d00ebc6b869f4df67c05522bc1e8d01d1c7daa7 Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Tue, 19 Aug 2025 17:20:39 +0800 Subject: [PATCH 01388/11391] spi: SPISG: 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 Link: https://patch.msgid.link/20250819092044.549464-3-zhao.xichao@vivo.com Signed-off-by: Mark Brown --- drivers/spi/spi-amlogic-spisg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-amlogic-spisg.c b/drivers/spi/spi-amlogic-spisg.c index 2ab8bdf2a676..d1d5f3114fa8 100644 --- a/drivers/spi/spi-amlogic-spisg.c +++ b/drivers/spi/spi-amlogic-spisg.c @@ -733,7 +733,7 @@ static int aml_spisg_probe(struct platform_device *pdev) else ctlr = spi_alloc_host(dev, sizeof(*spisg)); if (!ctlr) - return dev_err_probe(dev, -ENOMEM, "controller allocation failed\n"); + return -ENOMEM; spisg = spi_controller_get_devdata(ctlr); spisg->controller = ctlr; From 2aade32d1ffc5f91cc447ed6387c0f619fb980c3 Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Tue, 19 Aug 2025 17:20:40 +0800 Subject: [PATCH 01389/11391] spi: 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 Link: https://patch.msgid.link/20250819092044.549464-4-zhao.xichao@vivo.com Signed-off-by: Mark Brown --- drivers/spi/spi-microchip-core-qspi.c | 3 +-- drivers/spi/spi-microchip-core.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-microchip-core-qspi.c b/drivers/spi/spi-microchip-core-qspi.c index d13a9b755c7f..0a6f65c77eac 100644 --- a/drivers/spi/spi-microchip-core-qspi.c +++ b/drivers/spi/spi-microchip-core-qspi.c @@ -701,8 +701,7 @@ static int mchp_coreqspi_probe(struct platform_device *pdev) ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*qspi)); if (!ctlr) - return dev_err_probe(&pdev->dev, -ENOMEM, - "unable to allocate host for QSPI controller\n"); + return -ENOMEM; qspi = spi_controller_get_devdata(ctlr); platform_set_drvdata(pdev, qspi); diff --git a/drivers/spi/spi-microchip-core.c b/drivers/spi/spi-microchip-core.c index 62ba0bd9cbb7..9128b86c5366 100644 --- a/drivers/spi/spi-microchip-core.c +++ b/drivers/spi/spi-microchip-core.c @@ -534,8 +534,7 @@ static int mchp_corespi_probe(struct platform_device *pdev) host = devm_spi_alloc_host(&pdev->dev, sizeof(*spi)); if (!host) - return dev_err_probe(&pdev->dev, -ENOMEM, - "unable to allocate host for SPI controller\n"); + return -ENOMEM; platform_set_drvdata(pdev, host); From 2bee48c9d1cd1749922d0e2df54330c924e14a0e Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Tue, 19 Aug 2025 17:20:41 +0800 Subject: [PATCH 01390/11391] spi: mt65xx: 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 Link: https://patch.msgid.link/20250819092044.549464-5-zhao.xichao@vivo.com Signed-off-by: Mark Brown --- drivers/spi/spi-mt65xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index a6032d44771b..8a3c00c3af42 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c @@ -1159,7 +1159,7 @@ static int mtk_spi_probe(struct platform_device *pdev) host = devm_spi_alloc_host(dev, sizeof(*mdata)); if (!host) - return dev_err_probe(dev, -ENOMEM, "failed to alloc spi host\n"); + return -ENOMEM; host->auto_runtime_pm = true; host->dev.of_node = dev->of_node; From 67259af78219bdbdea00491f32b1c0971a33401e Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Tue, 19 Aug 2025 17:20:42 +0800 Subject: [PATCH 01391/11391] spi: pxa2xx: 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 Link: https://patch.msgid.link/20250819092044.549464-6-zhao.xichao@vivo.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 06711a62fa3d..ec7117a94d5f 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1283,7 +1283,7 @@ int pxa2xx_spi_probe(struct device *dev, struct ssp_device *ssp, else controller = devm_spi_alloc_host(dev, sizeof(*drv_data)); if (!controller) - return dev_err_probe(dev, -ENOMEM, "cannot alloc spi_controller\n"); + return -ENOMEM; drv_data = spi_controller_get_devdata(controller); drv_data->controller = controller; From 27848c082ba0b22850fd9fb7b185c015423dcdc7 Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Tue, 19 Aug 2025 17:20:43 +0800 Subject: [PATCH 01392/11391] spi: s3c64xx: 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: Tudor Ambarus Link: https://patch.msgid.link/20250819092044.549464-7-zhao.xichao@vivo.com Signed-off-by: Mark Brown --- drivers/spi/spi-s3c64xx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index b1567243ae19..3a00f9e480c5 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -1268,8 +1268,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) host = devm_spi_alloc_host(&pdev->dev, sizeof(*sdd)); if (!host) - return dev_err_probe(&pdev->dev, -ENOMEM, - "Unable to allocate SPI Host\n"); + return -ENOMEM; platform_set_drvdata(pdev, host); From 9a96082f99453a3c0f5ea7a70d19a66dbfbd55bc Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 13 Aug 2025 18:14:59 +0200 Subject: [PATCH 01393/11391] pinctrl: 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/20250813161517.4746-14-wsa+renesas@sang-engineering.com Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-rp1.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/pinctrl/pinctrl-rp1.c b/drivers/pinctrl/pinctrl-rp1.c index b231efc62ff3..605105aa0cbc 100644 --- a/drivers/pinctrl/pinctrl-rp1.c +++ b/drivers/pinctrl/pinctrl-rp1.c @@ -1690,7 +1690,6 @@ static const struct regmap_config rp1_pinctrl_gpio_regmap_cfg = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, - .fast_io = true, .rd_table = &rp1_gpio_reg_table, .name = "rp1-gpio", .max_register = 0xb11c, @@ -1700,7 +1699,6 @@ static const struct regmap_config rp1_pinctrl_rio_regmap_cfg = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, - .fast_io = true, .rd_table = &rp1_rio_reg_table, .name = "rp1-rio", .max_register = 0xb004, @@ -1710,7 +1708,6 @@ static const struct regmap_config rp1_pinctrl_pads_regmap_cfg = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, - .fast_io = true, .rd_table = &rp1_pads_reg_table, .name = "rp1-pads", .max_register = 0x8050, From 29a799917947d24c55e8902ef29f5cb52195682c Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Tue, 5 Aug 2025 09:47:39 +0200 Subject: [PATCH 01394/11391] dt-bindings: power: mediatek: Document access-controllers property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow specifying access-controllers in the main power controller node and deprecate the old mediatek,infracfg, mediatek,infracfg-nao and mediatek,smi properties located in the children. This is done in order to both simplify the power controller nodes and in preparation for adding support for new generation SoCs like MT8196/MT6991 and other variants, which will need to set protection on new busses. Reviewed-by: Nícolas F. R. A. Prado Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250805074746.29457-4-angelogioacchino.delregno@collabora.com Signed-off-by: Ulf Hansson --- .../power/mediatek,power-controller.yaml | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml b/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml index 9c7cc632abee..500d98921581 100644 --- a/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml +++ b/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml @@ -44,6 +44,15 @@ properties: '#size-cells': const: 0 + access-controllers: + description: + A number of phandles to external blocks to set and clear the required + bits to enable or disable bus protection, necessary to avoid any bus + faults while enabling or disabling a power domain. + For example, this may hold phandles to INFRACFG and SMI. + minItems: 1 + maxItems: 3 + patternProperties: "^power-domain@[0-9a-f]+$": $ref: "#/$defs/power-domain-node" @@ -123,14 +132,17 @@ $defs: mediatek,infracfg: $ref: /schemas/types.yaml#/definitions/phandle description: phandle to the device containing the INFRACFG register range. + deprecated: true mediatek,infracfg-nao: $ref: /schemas/types.yaml#/definitions/phandle description: phandle to the device containing the INFRACFG-NAO register range. + deprecated: true mediatek,smi: $ref: /schemas/types.yaml#/definitions/phandle description: phandle to the device containing the SMI register range. + deprecated: true required: - reg @@ -138,6 +150,31 @@ $defs: required: - compatible +allOf: + - if: + properties: + compatible: + contains: + enum: + - mediatek,mt8183-power-controller + then: + properties: + access-controllers: + minItems: 2 + maxItems: 2 + + - if: + properties: + compatible: + contains: + enum: + - mediatek,mt8365-power-controller + then: + properties: + access-controllers: + minItems: 3 + maxItems: 3 + additionalProperties: false examples: From c29345fa5f66bea0790cf2219f57b974d4fc177b Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Tue, 5 Aug 2025 09:47:40 +0200 Subject: [PATCH 01395/11391] pmdomain: mediatek: Refactor bus protection regmaps retrieval MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation to add support for new generation SoCs like MT8196, MT6991 and other variants, which require to set bus protection on different busses than the ones found on legacy chips, and to also simplify and reduce memory footprint of this driver, refactor the mechanism to retrieve and use the bus protection regmaps. This is done by removing the three pointers to struct regmap from struct scpsys_domain (allocated for each power domain) and moving them to the main struct scpsys (allocated per driver instance) as an array of pointers to regmap named **bus_prot. That deprecates the old devicetree properties to grab phandles to the three predefined busses (infracfg, infracfg-nao and smi) and replaces it with the base property "access-controllers" that is meant to be an array of phandles holding the same busses where required (for now - for legacy SoCs). The new bus protection phandles are indexed by the bus_prot_index member of struct scpsys, used to map "bus type" (ex.: infra, smi, etc) to the specific *bus_prot[x] element. While the old per-power-domain regmap pointers were removed, the support for old devicetree was retained by still checking if the new property (in DT) and new-style declaration (in SoC specific platform data) are both present at probe time. If those are not present, a lookup for the old properties will be done in all of the children of the power controller, and pointers to regmaps will be retrieved with the old properties, but then will be internally remapped to follow the new style regmap anyway as to let this driver benefit of the memory footprint reduction. Finally, it was necessary to change macros in mtk-pm-domains.h and in mt8365-pm-domains.h to make use of the new style bus protection declaration, as the actual HW block is now recognized not by flags but by its own scpsys_bus_prot_block enumeration. The BUS_PROT_(STA)_COMPONENT_{INFRA,INFRA_NAO,SMI} flags were also removed since they are now unused, and because that enumeration was initially meant to vary the logic of bus protection and not the bus where work is performed, anyway! Reviewed-by: Nícolas F. R. A. Prado Signed-off-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20250805074746.29457-5-angelogioacchino.delregno@collabora.com Signed-off-by: Ulf Hansson --- drivers/pmdomain/mediatek/mt8365-pm-domains.h | 8 +- drivers/pmdomain/mediatek/mtk-pm-domains.c | 188 ++++++++++++++---- drivers/pmdomain/mediatek/mtk-pm-domains.h | 53 +++-- 3 files changed, 187 insertions(+), 62 deletions(-) diff --git a/drivers/pmdomain/mediatek/mt8365-pm-domains.h b/drivers/pmdomain/mediatek/mt8365-pm-domains.h index 3d83d49eaa7c..6fbd5ef8d672 100644 --- a/drivers/pmdomain/mediatek/mt8365-pm-domains.h +++ b/drivers/pmdomain/mediatek/mt8365-pm-domains.h @@ -29,11 +29,9 @@ MT8365_SMI_COMMON_CLAMP_EN) #define MT8365_BUS_PROT_WAY_EN(_set_mask, _set, _sta_mask, _sta) \ - _BUS_PROT(_set_mask, _set, _set, _sta_mask, _sta, \ - BUS_PROT_COMPONENT_INFRA | \ - BUS_PROT_STA_COMPONENT_INFRA_NAO | \ - BUS_PROT_INVERTED | \ - BUS_PROT_REG_UPDATE) + _BUS_PROT_STA(INFRA, INFRA_NAO, _set_mask, _set, _set, \ + _sta_mask, _sta, \ + BUS_PROT_INVERTED | BUS_PROT_REG_UPDATE) static const struct scpsys_domain_data scpsys_domain_data_mt8365[] = { [MT8365_POWER_DOMAIN_MM] = { diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.c b/drivers/pmdomain/mediatek/mtk-pm-domains.c index a58ed7e2d9a4..48dc5f188438 100644 --- a/drivers/pmdomain/mediatek/mtk-pm-domains.c +++ b/drivers/pmdomain/mediatek/mtk-pm-domains.c @@ -47,9 +47,6 @@ struct scpsys_domain { struct clk_bulk_data *clks; int num_subsys_clks; struct clk_bulk_data *subsys_clks; - struct regmap *infracfg_nao; - struct regmap *infracfg; - struct regmap *smi; struct regulator *supply; }; @@ -57,6 +54,8 @@ struct scpsys { struct device *dev; struct regmap *base; const struct scpsys_soc_data *soc_data; + u8 bus_prot_index[BUS_PROT_BLOCK_COUNT]; + struct regmap **bus_prot; struct genpd_onecell_data pd_data; struct generic_pm_domain *domains[]; }; @@ -125,19 +124,19 @@ static int scpsys_sram_disable(struct scpsys_domain *pd) static struct regmap *scpsys_bus_protect_get_regmap(struct scpsys_domain *pd, const struct scpsys_bus_prot_data *bpd) { - if (bpd->flags & BUS_PROT_COMPONENT_SMI) - return pd->smi; - else - return pd->infracfg; + struct scpsys *scpsys = pd->scpsys; + unsigned short block_idx = scpsys->bus_prot_index[bpd->bus_prot_block]; + + return scpsys->bus_prot[block_idx]; } static struct regmap *scpsys_bus_protect_get_sta_regmap(struct scpsys_domain *pd, const struct scpsys_bus_prot_data *bpd) { - if (bpd->flags & BUS_PROT_STA_COMPONENT_INFRA_NAO) - return pd->infracfg_nao; - else - return scpsys_bus_protect_get_regmap(pd, bpd); + struct scpsys *scpsys = pd->scpsys; + int block_idx = scpsys->bus_prot_index[bpd->bus_prot_sta_block]; + + return scpsys->bus_prot[block_idx]; } static int scpsys_bus_protect_clear(struct scpsys_domain *pd, @@ -149,7 +148,7 @@ static int scpsys_bus_protect_clear(struct scpsys_domain *pd, u32 expected_ack; u32 val; - expected_ack = (bpd->flags & BUS_PROT_STA_COMPONENT_INFRA_NAO ? sta_mask : 0); + expected_ack = (bpd->bus_prot_sta_block == BUS_PROT_BLOCK_INFRA_NAO ? sta_mask : 0); if (bpd->flags & BUS_PROT_REG_UPDATE) regmap_clear_bits(regmap, bpd->bus_prot_clr, bpd->bus_prot_set_clr_mask); @@ -355,7 +354,6 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no { const struct scpsys_domain_data *domain_data; struct scpsys_domain *pd; - struct device_node *smi_node; struct property *prop; const char *clk_name; int i, ret, num_clks; @@ -396,32 +394,6 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no node); } - pd->infracfg = syscon_regmap_lookup_by_phandle_optional(node, "mediatek,infracfg"); - if (IS_ERR(pd->infracfg)) - return dev_err_cast_probe(scpsys->dev, pd->infracfg, - "%pOF: failed to get infracfg regmap\n", - node); - - smi_node = of_parse_phandle(node, "mediatek,smi", 0); - if (smi_node) { - pd->smi = device_node_to_regmap(smi_node); - of_node_put(smi_node); - if (IS_ERR(pd->smi)) - return dev_err_cast_probe(scpsys->dev, pd->smi, - "%pOF: failed to get SMI regmap\n", - node); - } - - if (MTK_SCPD_CAPS(pd, MTK_SCPD_HAS_INFRA_NAO)) { - pd->infracfg_nao = syscon_regmap_lookup_by_phandle(node, "mediatek,infracfg-nao"); - if (IS_ERR(pd->infracfg_nao)) - return dev_err_cast_probe(scpsys->dev, pd->infracfg_nao, - "%pOF: failed to get infracfg-nao regmap\n", - node); - } else { - pd->infracfg_nao = NULL; - } - num_clks = of_clk_get_parent_count(node); if (num_clks > 0) { /* Calculate number of subsys_clks */ @@ -615,6 +587,136 @@ static void scpsys_domain_cleanup(struct scpsys *scpsys) } } +static int scpsys_get_bus_protection_legacy(struct device *dev, struct scpsys *scpsys) +{ + const u8 bp_blocks[3] = { + BUS_PROT_BLOCK_INFRA, BUS_PROT_BLOCK_SMI, BUS_PROT_BLOCK_INFRA_NAO + }; + struct device_node *np = dev->of_node; + struct device_node *node, *smi_np; + int num_regmaps = 0, i, j; + struct regmap *regmap[3]; + + /* + * Legacy code retrieves a maximum of three bus protection handles: + * some may be optional, or may not be, so the array of bp blocks + * that is normally passed in as platform data must be dynamically + * built in this case. + * + * Here, try to retrieve all of the regmaps that the legacy code + * supported and then count the number of the ones that are present, + * this makes it then possible to allocate the array of bus_prot + * regmaps and convert all to the new style handling. + */ + node = of_find_node_with_property(np, "mediatek,infracfg"); + if (node) { + regmap[0] = syscon_regmap_lookup_by_phandle(node, "mediatek,infracfg"); + of_node_put(node); + num_regmaps++; + if (IS_ERR(regmap[0])) + return dev_err_probe(dev, PTR_ERR(regmap[0]), + "%pOF: failed to get infracfg regmap\n", + node); + } else { + regmap[0] = NULL; + } + + node = of_find_node_with_property(np, "mediatek,smi"); + if (node) { + smi_np = of_parse_phandle(node, "mediatek,smi", 0); + of_node_put(node); + if (!smi_np) + return -ENODEV; + + regmap[1] = device_node_to_regmap(smi_np); + num_regmaps++; + of_node_put(smi_np); + if (IS_ERR(regmap[1])) + return dev_err_probe(dev, PTR_ERR(regmap[1]), + "%pOF: failed to get SMI regmap\n", + node); + } else { + regmap[1] = NULL; + } + + node = of_find_node_with_property(np, "mediatek,infracfg-nao"); + if (node) { + regmap[2] = syscon_regmap_lookup_by_phandle(node, "mediatek,infracfg-nao"); + num_regmaps++; + of_node_put(node); + if (IS_ERR(regmap[2])) + return dev_err_probe(dev, PTR_ERR(regmap[2]), + "%pOF: failed to get infracfg regmap\n", + node); + } else { + regmap[2] = NULL; + } + + scpsys->bus_prot = devm_kmalloc_array(dev, num_regmaps, + sizeof(*scpsys->bus_prot), GFP_KERNEL); + if (!scpsys->bus_prot) + return -ENOMEM; + + for (i = 0, j = 0; i < ARRAY_SIZE(bp_blocks); i++) { + enum scpsys_bus_prot_block bp_type; + + if (!regmap[i]) + continue; + + bp_type = bp_blocks[i]; + scpsys->bus_prot_index[bp_type] = j; + scpsys->bus_prot[j] = regmap[i]; + + j++; + } + + return 0; +} + +static int scpsys_get_bus_protection(struct device *dev, struct scpsys *scpsys) +{ + const struct scpsys_soc_data *soc = scpsys->soc_data; + struct device_node *np = dev->of_node; + int i, num_handles; + + num_handles = of_count_phandle_with_args(np, "access-controllers", NULL); + if (num_handles < 0 || num_handles != soc->num_bus_prot_blocks) + return dev_err_probe(dev, -EINVAL, + "Cannot get access controllers: expected %u, got %d\n", + soc->num_bus_prot_blocks, num_handles); + + scpsys->bus_prot = devm_kmalloc_array(dev, soc->num_bus_prot_blocks, + sizeof(*scpsys->bus_prot), GFP_KERNEL); + if (!scpsys->bus_prot) + return -ENOMEM; + + for (i = 0; i < soc->num_bus_prot_blocks; i++) { + enum scpsys_bus_prot_block bp_type; + struct device_node *node; + + node = of_parse_phandle(np, "access-controllers", i); + if (!node) + return -EINVAL; + + /* + * Index the bus protection regmaps so that we don't have to + * find the right one by type with a loop at every execution + * of power sequence(s). + */ + bp_type = soc->bus_prot_blocks[i]; + scpsys->bus_prot_index[bp_type] = i; + + scpsys->bus_prot[i] = device_node_to_regmap(node); + of_node_put(node); + if (IS_ERR_OR_NULL(scpsys->bus_prot[i])) + return dev_err_probe(dev, scpsys->bus_prot[i] ? + PTR_ERR(scpsys->bus_prot[i]) : -ENXIO, + "Cannot get regmap for access controller %d\n", i); + } + + return 0; +} + static const struct of_device_id scpsys_of_match[] = { { .compatible = "mediatek,mt6735-power-controller", @@ -701,6 +803,14 @@ static int scpsys_probe(struct platform_device *pdev) return PTR_ERR(scpsys->base); } + if (of_find_property(np, "access-controllers", NULL)) + ret = scpsys_get_bus_protection(dev, scpsys); + else + ret = scpsys_get_bus_protection_legacy(dev, scpsys); + + if (ret) + return ret; + ret = -ENODEV; for_each_available_child_of_node(np, node) { struct generic_pm_domain *domain; diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.h b/drivers/pmdomain/mediatek/mtk-pm-domains.h index 7085fa2976e9..4f2d331a866a 100644 --- a/drivers/pmdomain/mediatek/mtk-pm-domains.h +++ b/drivers/pmdomain/mediatek/mtk-pm-domains.h @@ -50,30 +50,43 @@ enum scpsys_bus_prot_flags { BUS_PROT_REG_UPDATE = BIT(1), BUS_PROT_IGNORE_CLR_ACK = BIT(2), BUS_PROT_INVERTED = BIT(3), - BUS_PROT_COMPONENT_INFRA = BIT(4), - BUS_PROT_COMPONENT_SMI = BIT(5), - BUS_PROT_STA_COMPONENT_INFRA_NAO = BIT(6), }; -#define _BUS_PROT(_set_clr_mask, _set, _clr, _sta_mask, _sta, _flags) { \ - .bus_prot_set_clr_mask = (_set_clr_mask), \ - .bus_prot_set = _set, \ - .bus_prot_clr = _clr, \ - .bus_prot_sta_mask = (_sta_mask), \ - .bus_prot_sta = _sta, \ - .flags = _flags \ +enum scpsys_bus_prot_block { + BUS_PROT_BLOCK_INFRA, + BUS_PROT_BLOCK_INFRA_NAO, + BUS_PROT_BLOCK_SMI, + BUS_PROT_BLOCK_COUNT, +}; + +#define _BUS_PROT_STA(_hwip, _sta_hwip, _set_clr_mask, _set, _clr, \ + _sta_mask, _sta, _flags) \ + { \ + .bus_prot_block = BUS_PROT_BLOCK_##_hwip, \ + .bus_prot_sta_block = BUS_PROT_BLOCK_##_sta_hwip, \ + .bus_prot_set_clr_mask = (_set_clr_mask), \ + .bus_prot_set = _set, \ + .bus_prot_clr = _clr, \ + .bus_prot_sta_mask = (_sta_mask), \ + .bus_prot_sta = _sta, \ + .flags = _flags \ } -#define BUS_PROT_WR(_hwip, _mask, _set, _clr, _sta) \ - _BUS_PROT(_mask, _set, _clr, _mask, _sta, BUS_PROT_COMPONENT_##_hwip) +#define _BUS_PROT(_hwip, _set_clr_mask, _set, _clr, _sta_mask, \ + _sta, _flags) \ + _BUS_PROT_STA(_hwip, _hwip, _set_clr_mask, _set, _clr, \ + _sta_mask, _sta, _flags) -#define BUS_PROT_WR_IGN(_hwip, _mask, _set, _clr, _sta) \ - _BUS_PROT(_mask, _set, _clr, _mask, _sta, \ - BUS_PROT_COMPONENT_##_hwip | BUS_PROT_IGNORE_CLR_ACK) +#define BUS_PROT_WR(_hwip, _mask, _set, _clr, _sta) \ + _BUS_PROT(_hwip, _mask, _set, _clr, _mask, _sta, 0) -#define BUS_PROT_UPDATE(_hwip, _mask, _set, _clr, _sta) \ - _BUS_PROT(_mask, _set, _clr, _mask, _sta, \ - BUS_PROT_COMPONENT_##_hwip | BUS_PROT_REG_UPDATE) +#define BUS_PROT_WR_IGN(_hwip, _mask, _set, _clr, _sta) \ + _BUS_PROT(_hwip, _mask, _set, _clr, _mask, _sta, \ + BUS_PROT_IGNORE_CLR_ACK) + +#define BUS_PROT_UPDATE(_hwip, _mask, _set, _clr, _sta) \ + _BUS_PROT(_hwip, _mask, _set, _clr, _mask, _sta, \ + BUS_PROT_REG_UPDATE) #define BUS_PROT_INFRA_UPDATE_TOPAXI(_mask) \ BUS_PROT_UPDATE(INFRA, _mask, \ @@ -82,6 +95,8 @@ enum scpsys_bus_prot_flags { INFRA_TOPAXI_PROTECTSTA1) struct scpsys_bus_prot_data { + u8 bus_prot_block; + u8 bus_prot_sta_block; u32 bus_prot_set_clr_mask; u32 bus_prot_set; u32 bus_prot_clr; @@ -119,6 +134,8 @@ struct scpsys_domain_data { struct scpsys_soc_data { const struct scpsys_domain_data *domains_data; int num_domains; + enum scpsys_bus_prot_block *bus_prot_blocks; + int num_bus_prot_blocks; }; #endif /* __SOC_MEDIATEK_MTK_PM_DOMAINS_H */ From ad4bbdc59b75edf7f3bda836136a1f2bace427b8 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Tue, 5 Aug 2025 09:47:41 +0200 Subject: [PATCH 01396/11391] pmdomain: mediatek: Handle SoCs with inverted SRAM power-down bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some SoCs, and even some subsystems in the same SoC, may have the logic for SRAM power-down inverted, as in, setting the bit means "power down" and unsetting means "power up": this is because some hardware subsystems use this as a power-lock indication and some use this as a power down one (for example, usually, the modem ss has it inverted!). In preparation for adding support for power domains with inverted SRAM_PDN bits, add a new MTK_SCPD_SRAM_PDN_INVERTED flag and check for it in scpsys_sram_enable() and scpsys_sram_disable(). Reviewed-by: Nícolas F. R. A. Prado Signed-off-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20250805074746.29457-6-angelogioacchino.delregno@collabora.com Signed-off-by: Ulf Hansson --- drivers/pmdomain/mediatek/mtk-pm-domains.c | 27 ++++++++++++++++------ drivers/pmdomain/mediatek/mtk-pm-domains.h | 1 + 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.c b/drivers/pmdomain/mediatek/mtk-pm-domains.c index 48dc5f188438..6118a389244a 100644 --- a/drivers/pmdomain/mediatek/mtk-pm-domains.c +++ b/drivers/pmdomain/mediatek/mtk-pm-domains.c @@ -79,16 +79,23 @@ static bool scpsys_domain_is_on(struct scpsys_domain *pd) static int scpsys_sram_enable(struct scpsys_domain *pd) { - u32 pdn_ack = pd->data->sram_pdn_ack_bits; + u32 expected_ack, pdn_ack = pd->data->sram_pdn_ack_bits; struct scpsys *scpsys = pd->scpsys; unsigned int tmp; int ret; - regmap_clear_bits(scpsys->base, pd->data->ctl_offs, pd->data->sram_pdn_bits); + if (MTK_SCPD_CAPS(pd, MTK_SCPD_SRAM_PDN_INVERTED)) { + regmap_set_bits(scpsys->base, pd->data->ctl_offs, pd->data->sram_pdn_bits); + expected_ack = pdn_ack; + } else { + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, pd->data->sram_pdn_bits); + expected_ack = 0; + } /* Either wait until SRAM_PDN_ACK all 1 or 0 */ ret = regmap_read_poll_timeout(scpsys->base, pd->data->ctl_offs, tmp, - (tmp & pdn_ack) == 0, MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); + (tmp & pdn_ack) == expected_ack, + MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); if (ret < 0) return ret; @@ -103,7 +110,7 @@ static int scpsys_sram_enable(struct scpsys_domain *pd) static int scpsys_sram_disable(struct scpsys_domain *pd) { - u32 pdn_ack = pd->data->sram_pdn_ack_bits; + u32 expected_ack, pdn_ack = pd->data->sram_pdn_ack_bits; struct scpsys *scpsys = pd->scpsys; unsigned int tmp; @@ -113,12 +120,18 @@ static int scpsys_sram_disable(struct scpsys_domain *pd) regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_SRAM_ISOINT_B_BIT); } - regmap_set_bits(scpsys->base, pd->data->ctl_offs, pd->data->sram_pdn_bits); + if (MTK_SCPD_CAPS(pd, MTK_SCPD_SRAM_PDN_INVERTED)) { + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, pd->data->sram_pdn_bits); + expected_ack = 0; + } else { + regmap_set_bits(scpsys->base, pd->data->ctl_offs, pd->data->sram_pdn_bits); + expected_ack = pdn_ack; + } /* Either wait until SRAM_PDN_ACK all 1 or 0 */ return regmap_read_poll_timeout(scpsys->base, pd->data->ctl_offs, tmp, - (tmp & pdn_ack) == pdn_ack, MTK_POLL_DELAY_US, - MTK_POLL_TIMEOUT); + (tmp & pdn_ack) == expected_ack, + MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); } static struct regmap *scpsys_bus_protect_get_regmap(struct scpsys_domain *pd, diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.h b/drivers/pmdomain/mediatek/mtk-pm-domains.h index 4f2d331a866a..fbbfb23a8739 100644 --- a/drivers/pmdomain/mediatek/mtk-pm-domains.h +++ b/drivers/pmdomain/mediatek/mtk-pm-domains.h @@ -13,6 +13,7 @@ #define MTK_SCPD_EXT_BUCK_ISO BIT(6) #define MTK_SCPD_HAS_INFRA_NAO BIT(7) #define MTK_SCPD_STRICT_BUS_PROTECTION BIT(8) +#define MTK_SCPD_SRAM_PDN_INVERTED BIT(9) #define MTK_SCPD_CAPS(_scpd, _x) ((_scpd)->data->caps & (_x)) #define SPM_VDE_PWR_CON 0x0210 From 0e8e6b5f6a31a3d001ab83f7af9394fccd4bb569 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Tue, 5 Aug 2025 09:47:42 +0200 Subject: [PATCH 01397/11391] pmdomain: mediatek: Move ctl sequences out of power_on/off functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation to support power domains of new SoCs and the modem power domains for both new and already supported chips, move the generic control power sequences out of the scpsys_power_on() and scpsys_power_off() and put them in new scpsys_ctl_pwrseq_on(), scpsys_ctl_pewseq_off() functions. Reviewed-by: Nícolas F. R. A. Prado Signed-off-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20250805074746.29457-7-angelogioacchino.delregno@collabora.com Signed-off-by: Ulf Hansson --- drivers/pmdomain/mediatek/mtk-pm-domains.c | 57 ++++++++++++++-------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.c b/drivers/pmdomain/mediatek/mtk-pm-domains.c index 6118a389244a..d84f0e7cde12 100644 --- a/drivers/pmdomain/mediatek/mtk-pm-domains.c +++ b/drivers/pmdomain/mediatek/mtk-pm-domains.c @@ -244,11 +244,45 @@ static int scpsys_regulator_disable(struct regulator *supply) return supply ? regulator_disable(supply) : 0; } +static int scpsys_ctl_pwrseq_on(struct scpsys_domain *pd) +{ + struct scpsys *scpsys = pd->scpsys; + bool tmp; + int ret; + + /* subsys power on */ + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_BIT); + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_2ND_BIT); + + /* wait until PWR_ACK = 1 */ + ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, tmp, MTK_POLL_DELAY_US, + MTK_POLL_TIMEOUT); + if (ret < 0) + return ret; + + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_CLK_DIS_BIT); + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_BIT); + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT); + + return 0; +} + +static void scpsys_ctl_pwrseq_off(struct scpsys_domain *pd) +{ + struct scpsys *scpsys = pd->scpsys; + + /* subsys power off */ + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_BIT); + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_CLK_DIS_BIT); + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT); + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_2ND_BIT); + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_BIT); +} + static int scpsys_power_on(struct generic_pm_domain *genpd) { struct scpsys_domain *pd = container_of(genpd, struct scpsys_domain, genpd); struct scpsys *scpsys = pd->scpsys; - bool tmp; int ret; ret = scpsys_regulator_enable(pd->supply); @@ -263,20 +297,10 @@ static int scpsys_power_on(struct generic_pm_domain *genpd) regmap_clear_bits(scpsys->base, pd->data->ext_buck_iso_offs, pd->data->ext_buck_iso_mask); - /* subsys power on */ - regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_BIT); - regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_2ND_BIT); - - /* wait until PWR_ACK = 1 */ - ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, tmp, MTK_POLL_DELAY_US, - MTK_POLL_TIMEOUT); - if (ret < 0) + ret = scpsys_ctl_pwrseq_on(pd); + if (ret) goto err_pwr_ack; - regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_CLK_DIS_BIT); - regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_BIT); - regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT); - /* * In few Mediatek platforms(e.g. MT6779), the bus protect policy is * stricter, which leads to bus protect release must be prior to bus @@ -342,12 +366,7 @@ static int scpsys_power_off(struct generic_pm_domain *genpd) clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks); - /* subsys power off */ - regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_BIT); - regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_CLK_DIS_BIT); - regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT); - regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_2ND_BIT); - regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_BIT); + scpsys_ctl_pwrseq_off(pd); /* wait until PWR_ACK = 0 */ ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, !tmp, MTK_POLL_DELAY_US, From 16d861d2bce8b1d28b6d94ffbfcdaa9cf833542b Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Tue, 5 Aug 2025 09:47:43 +0200 Subject: [PATCH 01398/11391] pmdomain: mediatek: Add support for modem power sequences MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the modem power domains by adding its specific power sequence in functions scpsys_modem_pwrseq_{on,off}() and call them if the flag MTK_SCPD_MODEM_PWRSEQ is present. While at it, since some SoC models need to skip setting/clearing the PWR_RST_B_BIT, also add a MTK_SCPD_SKIP_RESET_B flag for that. Reviewed-by: Nícolas F. R. A. Prado Signed-off-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20250805074746.29457-8-angelogioacchino.delregno@collabora.com Signed-off-by: Ulf Hansson --- drivers/pmdomain/mediatek/mtk-pm-domains.c | 41 ++++++++++++++++++++-- drivers/pmdomain/mediatek/mtk-pm-domains.h | 2 ++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.c b/drivers/pmdomain/mediatek/mtk-pm-domains.c index d84f0e7cde12..cf749ba5c3c7 100644 --- a/drivers/pmdomain/mediatek/mtk-pm-domains.c +++ b/drivers/pmdomain/mediatek/mtk-pm-domains.c @@ -279,6 +279,36 @@ static void scpsys_ctl_pwrseq_off(struct scpsys_domain *pd) regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_BIT); } +static int scpsys_modem_pwrseq_on(struct scpsys_domain *pd) +{ + struct scpsys *scpsys = pd->scpsys; + bool tmp; + int ret; + + if (!MTK_SCPD_CAPS(pd, MTK_SCPD_SKIP_RESET_B)) + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT); + + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_BIT); + + /* wait until PWR_ACK = 1 */ + ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, tmp, MTK_POLL_DELAY_US, + MTK_POLL_TIMEOUT); + if (ret < 0) + return ret; + + return 0; +} + +static void scpsys_modem_pwrseq_off(struct scpsys_domain *pd) +{ + struct scpsys *scpsys = pd->scpsys; + + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_BIT); + + if (!MTK_SCPD_CAPS(pd, MTK_SCPD_SKIP_RESET_B)) + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT); +} + static int scpsys_power_on(struct generic_pm_domain *genpd) { struct scpsys_domain *pd = container_of(genpd, struct scpsys_domain, genpd); @@ -297,7 +327,11 @@ static int scpsys_power_on(struct generic_pm_domain *genpd) regmap_clear_bits(scpsys->base, pd->data->ext_buck_iso_offs, pd->data->ext_buck_iso_mask); - ret = scpsys_ctl_pwrseq_on(pd); + if (MTK_SCPD_CAPS(pd, MTK_SCPD_MODEM_PWRSEQ)) + ret = scpsys_modem_pwrseq_on(pd); + else + ret = scpsys_ctl_pwrseq_on(pd); + if (ret) goto err_pwr_ack; @@ -366,7 +400,10 @@ static int scpsys_power_off(struct generic_pm_domain *genpd) clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks); - scpsys_ctl_pwrseq_off(pd); + if (MTK_SCPD_CAPS(pd, MTK_SCPD_MODEM_PWRSEQ)) + scpsys_modem_pwrseq_off(pd); + else + scpsys_ctl_pwrseq_off(pd); /* wait until PWR_ACK = 0 */ ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, !tmp, MTK_POLL_DELAY_US, diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.h b/drivers/pmdomain/mediatek/mtk-pm-domains.h index fbbfb23a8739..931a54f1c5ca 100644 --- a/drivers/pmdomain/mediatek/mtk-pm-domains.h +++ b/drivers/pmdomain/mediatek/mtk-pm-domains.h @@ -14,6 +14,8 @@ #define MTK_SCPD_HAS_INFRA_NAO BIT(7) #define MTK_SCPD_STRICT_BUS_PROTECTION BIT(8) #define MTK_SCPD_SRAM_PDN_INVERTED BIT(9) +#define MTK_SCPD_MODEM_PWRSEQ BIT(10) +#define MTK_SCPD_SKIP_RESET_B BIT(11) #define MTK_SCPD_CAPS(_scpd, _x) ((_scpd)->data->caps & (_x)) #define SPM_VDE_PWR_CON 0x0210 From 9d02c94342b35a94c4f1feecf94aa68e1565e6af Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Tue, 5 Aug 2025 09:47:44 +0200 Subject: [PATCH 01399/11391] pmdomain: mediatek: Add support for RTFF Hardware in MT8196/MT6991 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New generation SoCs use a new RTFF Hardware to save power during operation of various IPs, other than managing isolation of the internal buck converters during powerup/down of power domains. Since some of the power domains need different RTFF handling, add a new scpys_rtff_type enumeration and hold the value for each power domain in struct scpsys_domain_data. If RTFF HW is available, the RTFF additional power sequences are handled in scpsys_ctl_pwrseq_{on,off}(). Reviewed-by: Nícolas F. R. A. Prado Signed-off-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20250805074746.29457-9-angelogioacchino.delregno@collabora.com Signed-off-by: Ulf Hansson --- drivers/pmdomain/mediatek/mtk-pm-domains.c | 94 +++++++++++++++++++++- drivers/pmdomain/mediatek/mtk-pm-domains.h | 18 +++++ 2 files changed, 111 insertions(+), 1 deletion(-) diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.c b/drivers/pmdomain/mediatek/mtk-pm-domains.c index cf749ba5c3c7..0ebe7379b94e 100644 --- a/drivers/pmdomain/mediatek/mtk-pm-domains.c +++ b/drivers/pmdomain/mediatek/mtk-pm-domains.c @@ -39,6 +39,12 @@ #define PWR_SRAM_CLKISO_BIT BIT(5) #define PWR_SRAM_ISOINT_B_BIT BIT(6) +#define PWR_RTFF_SAVE BIT(24) +#define PWR_RTFF_NRESTORE BIT(25) +#define PWR_RTFF_CLK_DIS BIT(26) +#define PWR_RTFF_SAVE_FLAG BIT(27) +#define PWR_RTFF_UFS_CLK_DIS BIT(28) + struct scpsys_domain { struct generic_pm_domain genpd; const struct scpsys_domain_data *data; @@ -247,7 +253,7 @@ static int scpsys_regulator_disable(struct regulator *supply) static int scpsys_ctl_pwrseq_on(struct scpsys_domain *pd) { struct scpsys *scpsys = pd->scpsys; - bool tmp; + bool do_rtff_nrestore, tmp; int ret; /* subsys power on */ @@ -260,10 +266,72 @@ static int scpsys_ctl_pwrseq_on(struct scpsys_domain *pd) if (ret < 0) return ret; + if (pd->data->rtff_type == SCPSYS_RTFF_TYPE_PCIE_PHY) + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_CLK_DIS); + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_CLK_DIS_BIT); regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_BIT); + + /* Wait for RTFF HW to sync buck isolation state if this is PCIe PHY RTFF */ + if (pd->data->rtff_type == SCPSYS_RTFF_TYPE_PCIE_PHY) + udelay(5); + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT); + /* + * RTFF HW state may be modified by secure world or remote processors. + * + * With the only exception of STOR_UFS, which always needs save/restore, + * check if this power domain's RTFF is already on before trying to do + * the NRESTORE procedure, otherwise the system will lock up. + */ + switch (pd->data->rtff_type) { + case SCPSYS_RTFF_TYPE_GENERIC: + case SCPSYS_RTFF_TYPE_PCIE_PHY: + { + u32 ctl_status; + + regmap_read(scpsys->base, pd->data->ctl_offs, &ctl_status); + do_rtff_nrestore = ctl_status & PWR_RTFF_SAVE_FLAG; + break; + } + case SCPSYS_RTFF_TYPE_STOR_UFS: + /* STOR_UFS always needs NRESTORE */ + do_rtff_nrestore = true; + break; + default: + do_rtff_nrestore = false; + break; + } + + /* Return early if RTFF NRESTORE shall not be done */ + if (!do_rtff_nrestore) + return 0; + + switch (pd->data->rtff_type) { + case SCPSYS_RTFF_TYPE_GENERIC: + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_SAVE_FLAG); + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_CLK_DIS); + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_NRESTORE); + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_NRESTORE); + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_CLK_DIS); + break; + case SCPSYS_RTFF_TYPE_PCIE_PHY: + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_SAVE_FLAG); + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_NRESTORE); + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_NRESTORE); + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_CLK_DIS); + break; + case SCPSYS_RTFF_TYPE_STOR_UFS: + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_UFS_CLK_DIS); + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_NRESTORE); + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_NRESTORE); + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_UFS_CLK_DIS); + break; + default: + break; + } + return 0; } @@ -271,8 +339,32 @@ static void scpsys_ctl_pwrseq_off(struct scpsys_domain *pd) { struct scpsys *scpsys = pd->scpsys; + switch (pd->data->rtff_type) { + case SCPSYS_RTFF_TYPE_GENERIC: + case SCPSYS_RTFF_TYPE_PCIE_PHY: + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_CLK_DIS); + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_SAVE); + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_SAVE); + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_CLK_DIS); + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_SAVE_FLAG); + break; + case SCPSYS_RTFF_TYPE_STOR_UFS: + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_UFS_CLK_DIS); + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_SAVE); + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_SAVE); + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_UFS_CLK_DIS); + break; + default: + break; + } + /* subsys power off */ regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_BIT); + + /* Wait for RTFF HW to sync buck isolation state if this is PCIe PHY RTFF */ + if (pd->data->rtff_type == SCPSYS_RTFF_TYPE_PCIE_PHY) + udelay(1); + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_CLK_DIS_BIT); regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT); regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_2ND_BIT); diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.h b/drivers/pmdomain/mediatek/mtk-pm-domains.h index 931a54f1c5ca..b2e3dee03831 100644 --- a/drivers/pmdomain/mediatek/mtk-pm-domains.h +++ b/drivers/pmdomain/mediatek/mtk-pm-domains.h @@ -108,6 +108,22 @@ struct scpsys_bus_prot_data { u8 flags; }; +/** + * enum scpsys_rtff_type - Type of RTFF Hardware for power domain + * @SCPSYS_RTFF_NONE: RTFF HW not present or domain not RTFF managed + * @SCPSYS_RTFF_TYPE_GENERIC: Non-CPU, peripheral-generic RTFF HW + * @SCPSYS_RTFF_TYPE_PCIE_PHY: PCI-Express PHY specific RTFF HW + * @SCPSYS_RTFF_TYPE_STOR_UFS: Storage (UFS) specific RTFF HW + * @SCPSYS_RTFF_TYPE_MAX: Number of supported RTFF HW Types + */ +enum scpsys_rtff_type { + SCPSYS_RTFF_NONE = 0, + SCPSYS_RTFF_TYPE_GENERIC, + SCPSYS_RTFF_TYPE_PCIE_PHY, + SCPSYS_RTFF_TYPE_STOR_UFS, + SCPSYS_RTFF_TYPE_MAX +}; + /** * struct scpsys_domain_data - scp domain data for power on/off flow * @name: The name of the power domain. @@ -118,6 +134,7 @@ struct scpsys_bus_prot_data { * @ext_buck_iso_offs: The offset for external buck isolation * @ext_buck_iso_mask: The mask for external buck isolation * @caps: The flag for active wake-up action. + * @rtff_type: The power domain RTFF HW type * @bp_cfg: bus protection configuration for any subsystem */ struct scpsys_domain_data { @@ -129,6 +146,7 @@ struct scpsys_domain_data { int ext_buck_iso_offs; u32 ext_buck_iso_mask; u16 caps; + enum scpsys_rtff_type rtff_type; const struct scpsys_bus_prot_data bp_cfg[SPM_MAX_BUS_PROT_DATA]; int pwr_sta_offs; int pwr_sta2nd_offs; From ffeebf7587f518a3717fad308cf735adbbcaba97 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Tue, 5 Aug 2025 09:47:45 +0200 Subject: [PATCH 01400/11391] pmdomain: mediatek: Convert all SoCs to new style regmap retrieval MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the bus_prot_blocks handle and declare num_bus_prot_blocks to allow all of the currently supported AArch64 MediaTek SoCs to use the new style regmap retrieval in the driver when a new style devicetree declaring the mediatek,bus-protection phandle(s) in the main power controller node is found. Reviewed-by: Nícolas F. R. A. Prado Signed-off-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20250805074746.29457-10-angelogioacchino.delregno@collabora.com Signed-off-by: Ulf Hansson --- drivers/pmdomain/mediatek/mt6795-pm-domains.h | 5 +++++ drivers/pmdomain/mediatek/mt8167-pm-domains.h | 5 +++++ drivers/pmdomain/mediatek/mt8173-pm-domains.h | 5 +++++ drivers/pmdomain/mediatek/mt8183-pm-domains.h | 5 +++++ drivers/pmdomain/mediatek/mt8186-pm-domains.h | 5 +++++ drivers/pmdomain/mediatek/mt8188-pm-domains.h | 6 ++++++ drivers/pmdomain/mediatek/mt8192-pm-domains.h | 5 +++++ drivers/pmdomain/mediatek/mt8195-pm-domains.h | 5 +++++ drivers/pmdomain/mediatek/mt8365-pm-domains.h | 6 ++++++ 9 files changed, 47 insertions(+) diff --git a/drivers/pmdomain/mediatek/mt6795-pm-domains.h b/drivers/pmdomain/mediatek/mt6795-pm-domains.h index a3f7785b04bd..dc8e9f8877ad 100644 --- a/drivers/pmdomain/mediatek/mt6795-pm-domains.h +++ b/drivers/pmdomain/mediatek/mt6795-pm-domains.h @@ -9,6 +9,9 @@ /* * MT6795 power domain support */ +static enum scpsys_bus_prot_block scpsys_bus_prot_blocks_mt6795[] = { + BUS_PROT_BLOCK_INFRA +}; static const struct scpsys_domain_data scpsys_domain_data_mt6795[] = { [MT6795_POWER_DOMAIN_VDEC] = { @@ -107,6 +110,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt6795[] = { static const struct scpsys_soc_data mt6795_scpsys_data = { .domains_data = scpsys_domain_data_mt6795, .num_domains = ARRAY_SIZE(scpsys_domain_data_mt6795), + .bus_prot_blocks = scpsys_bus_prot_blocks_mt6795, + .num_bus_prot_blocks = ARRAY_SIZE(scpsys_bus_prot_blocks_mt6795), }; #endif /* __SOC_MEDIATEK_MT6795_PM_DOMAINS_H */ diff --git a/drivers/pmdomain/mediatek/mt8167-pm-domains.h b/drivers/pmdomain/mediatek/mt8167-pm-domains.h index 8a0e898b79ab..f6ee48a711a1 100644 --- a/drivers/pmdomain/mediatek/mt8167-pm-domains.h +++ b/drivers/pmdomain/mediatek/mt8167-pm-domains.h @@ -12,6 +12,9 @@ /* * MT8167 power domain support */ +static enum scpsys_bus_prot_block scpsys_bus_prot_blocks_mt8167[] = { + BUS_PROT_BLOCK_INFRA +}; static const struct scpsys_domain_data scpsys_domain_data_mt8167[] = { [MT8167_POWER_DOMAIN_MM] = { @@ -99,6 +102,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8167[] = { static const struct scpsys_soc_data mt8167_scpsys_data = { .domains_data = scpsys_domain_data_mt8167, .num_domains = ARRAY_SIZE(scpsys_domain_data_mt8167), + .bus_prot_blocks = scpsys_bus_prot_blocks_mt8167, + .num_bus_prot_blocks = ARRAY_SIZE(scpsys_bus_prot_blocks_mt8167), }; #endif /* __SOC_MEDIATEK_MT8167_PM_DOMAINS_H */ diff --git a/drivers/pmdomain/mediatek/mt8173-pm-domains.h b/drivers/pmdomain/mediatek/mt8173-pm-domains.h index 7be0f47f5214..561a644b5d1c 100644 --- a/drivers/pmdomain/mediatek/mt8173-pm-domains.h +++ b/drivers/pmdomain/mediatek/mt8173-pm-domains.h @@ -9,6 +9,9 @@ /* * MT8173 power domain support */ +static enum scpsys_bus_prot_block scpsys_bus_prot_blocks_mt8173[] = { + BUS_PROT_BLOCK_INFRA +}; static const struct scpsys_domain_data scpsys_domain_data_mt8173[] = { [MT8173_POWER_DOMAIN_VDEC] = { @@ -118,6 +121,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8173[] = { static const struct scpsys_soc_data mt8173_scpsys_data = { .domains_data = scpsys_domain_data_mt8173, .num_domains = ARRAY_SIZE(scpsys_domain_data_mt8173), + .bus_prot_blocks = scpsys_bus_prot_blocks_mt8173, + .num_bus_prot_blocks = ARRAY_SIZE(scpsys_bus_prot_blocks_mt8173), }; #endif /* __SOC_MEDIATEK_MT8173_PM_DOMAINS_H */ diff --git a/drivers/pmdomain/mediatek/mt8183-pm-domains.h b/drivers/pmdomain/mediatek/mt8183-pm-domains.h index c4c1b63d85b1..3742782a2702 100644 --- a/drivers/pmdomain/mediatek/mt8183-pm-domains.h +++ b/drivers/pmdomain/mediatek/mt8183-pm-domains.h @@ -9,6 +9,9 @@ /* * MT8183 power domain support */ +static enum scpsys_bus_prot_block scpsys_bus_prot_blocks_mt8183[] = { + BUS_PROT_BLOCK_INFRA, BUS_PROT_BLOCK_SMI +}; static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = { [MT8183_POWER_DOMAIN_AUDIO] = { @@ -290,6 +293,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = { static const struct scpsys_soc_data mt8183_scpsys_data = { .domains_data = scpsys_domain_data_mt8183, .num_domains = ARRAY_SIZE(scpsys_domain_data_mt8183), + .bus_prot_blocks = scpsys_bus_prot_blocks_mt8183, + .num_bus_prot_blocks = ARRAY_SIZE(scpsys_bus_prot_blocks_mt8183), }; #endif /* __SOC_MEDIATEK_MT8183_PM_DOMAINS_H */ diff --git a/drivers/pmdomain/mediatek/mt8186-pm-domains.h b/drivers/pmdomain/mediatek/mt8186-pm-domains.h index cbac715c38fa..00b9861af7c9 100644 --- a/drivers/pmdomain/mediatek/mt8186-pm-domains.h +++ b/drivers/pmdomain/mediatek/mt8186-pm-domains.h @@ -13,6 +13,9 @@ /* * MT8186 power domain support */ +static enum scpsys_bus_prot_block scpsys_bus_prot_blocks_mt8186[] = { + BUS_PROT_BLOCK_INFRA +}; static const struct scpsys_domain_data scpsys_domain_data_mt8186[] = { [MT8186_POWER_DOMAIN_MFG0] = { @@ -361,6 +364,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8186[] = { static const struct scpsys_soc_data mt8186_scpsys_data = { .domains_data = scpsys_domain_data_mt8186, .num_domains = ARRAY_SIZE(scpsys_domain_data_mt8186), + .bus_prot_blocks = scpsys_bus_prot_blocks_mt8186, + .num_bus_prot_blocks = ARRAY_SIZE(scpsys_bus_prot_blocks_mt8186), }; #endif /* __SOC_MEDIATEK_MT8186_PM_DOMAINS_H */ diff --git a/drivers/pmdomain/mediatek/mt8188-pm-domains.h b/drivers/pmdomain/mediatek/mt8188-pm-domains.h index 007235be9efe..3a989e83e9b7 100644 --- a/drivers/pmdomain/mediatek/mt8188-pm-domains.h +++ b/drivers/pmdomain/mediatek/mt8188-pm-domains.h @@ -14,6 +14,10 @@ * MT8188 power domain support */ +static enum scpsys_bus_prot_block scpsys_bus_prot_blocks_mt8188[] = { + BUS_PROT_BLOCK_INFRA +}; + static const struct scpsys_domain_data scpsys_domain_data_mt8188[] = { [MT8188_POWER_DOMAIN_MFG0] = { .name = "mfg0", @@ -685,6 +689,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8188[] = { static const struct scpsys_soc_data mt8188_scpsys_data = { .domains_data = scpsys_domain_data_mt8188, .num_domains = ARRAY_SIZE(scpsys_domain_data_mt8188), + .bus_prot_blocks = scpsys_bus_prot_blocks_mt8188, + .num_bus_prot_blocks = ARRAY_SIZE(scpsys_bus_prot_blocks_mt8188), }; #endif /* __SOC_MEDIATEK_MT8188_PM_DOMAINS_H */ diff --git a/drivers/pmdomain/mediatek/mt8192-pm-domains.h b/drivers/pmdomain/mediatek/mt8192-pm-domains.h index 6f139eed3769..5d62fac5f682 100644 --- a/drivers/pmdomain/mediatek/mt8192-pm-domains.h +++ b/drivers/pmdomain/mediatek/mt8192-pm-domains.h @@ -9,6 +9,9 @@ /* * MT8192 power domain support */ +static enum scpsys_bus_prot_block scpsys_bus_prot_blocks_mt8192[] = { + BUS_PROT_BLOCK_INFRA +}; static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = { [MT8192_POWER_DOMAIN_AUDIO] = { @@ -380,6 +383,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = { static const struct scpsys_soc_data mt8192_scpsys_data = { .domains_data = scpsys_domain_data_mt8192, .num_domains = ARRAY_SIZE(scpsys_domain_data_mt8192), + .bus_prot_blocks = scpsys_bus_prot_blocks_mt8192, + .num_bus_prot_blocks = ARRAY_SIZE(scpsys_bus_prot_blocks_mt8192), }; #endif /* __SOC_MEDIATEK_MT8192_PM_DOMAINS_H */ diff --git a/drivers/pmdomain/mediatek/mt8195-pm-domains.h b/drivers/pmdomain/mediatek/mt8195-pm-domains.h index 59aa031ae632..9405e8f62eaf 100644 --- a/drivers/pmdomain/mediatek/mt8195-pm-domains.h +++ b/drivers/pmdomain/mediatek/mt8195-pm-domains.h @@ -13,6 +13,9 @@ /* * MT8195 power domain support */ +static enum scpsys_bus_prot_block scpsys_bus_prot_blocks_mt8195[] = { + BUS_PROT_BLOCK_INFRA +}; static const struct scpsys_domain_data scpsys_domain_data_mt8195[] = { [MT8195_POWER_DOMAIN_PCIE_MAC_P0] = { @@ -661,6 +664,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8195[] = { static const struct scpsys_soc_data mt8195_scpsys_data = { .domains_data = scpsys_domain_data_mt8195, .num_domains = ARRAY_SIZE(scpsys_domain_data_mt8195), + .bus_prot_blocks = scpsys_bus_prot_blocks_mt8195, + .num_bus_prot_blocks = ARRAY_SIZE(scpsys_bus_prot_blocks_mt8195), }; #endif /* __SOC_MEDIATEK_MT8195_PM_DOMAINS_H */ diff --git a/drivers/pmdomain/mediatek/mt8365-pm-domains.h b/drivers/pmdomain/mediatek/mt8365-pm-domains.h index 6fbd5ef8d672..33265ab8ce76 100644 --- a/drivers/pmdomain/mediatek/mt8365-pm-domains.h +++ b/drivers/pmdomain/mediatek/mt8365-pm-domains.h @@ -33,6 +33,10 @@ _sta_mask, _sta, \ BUS_PROT_INVERTED | BUS_PROT_REG_UPDATE) +static enum scpsys_bus_prot_block scpsys_bus_prot_blocks_mt8365[] = { + BUS_PROT_BLOCK_INFRA, BUS_PROT_BLOCK_INFRA_NAO, BUS_PROT_BLOCK_SMI +}; + static const struct scpsys_domain_data scpsys_domain_data_mt8365[] = { [MT8365_POWER_DOMAIN_MM] = { .name = "mm", @@ -190,6 +194,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8365[] = { static const struct scpsys_soc_data mt8365_scpsys_data = { .domains_data = scpsys_domain_data_mt8365, .num_domains = ARRAY_SIZE(scpsys_domain_data_mt8365), + .bus_prot_blocks = scpsys_bus_prot_blocks_mt8365, + .num_bus_prot_blocks = ARRAY_SIZE(scpsys_bus_prot_blocks_mt8365), }; #endif /* __SOC_MEDIATEK_MT8365_PM_DOMAINS_H */ From ec205a929257e766117bc541b8b27b7797b2a19a Mon Sep 17 00:00:00 2001 From: Da Xue Date: Thu, 14 Aug 2025 14:12:36 -0400 Subject: [PATCH 01401/11391] pinctrl: meson-g12a: add GPIOC_7 pcie_clkreqn pinmux Amlogic G12 exposes PCIe clock request signal on GPIOC_7 pinmux func 1 Add the relevant pinmux and pin groups Signed-off-by: Da Xue Reviewed-by: Martin Blumenstingl Link: https://lore.kernel.org/20250814181236.1956731-1-da@libre.computer Signed-off-by: Linus Walleij --- drivers/pinctrl/meson/pinctrl-meson-g12a.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/pinctrl/meson/pinctrl-meson-g12a.c b/drivers/pinctrl/meson/pinctrl-meson-g12a.c index 8b9130c6e170..117e72b4ffcb 100644 --- a/drivers/pinctrl/meson/pinctrl-meson-g12a.c +++ b/drivers/pinctrl/meson/pinctrl-meson-g12a.c @@ -442,6 +442,8 @@ static const unsigned int tdm_c_dout1_z_pins[] = { GPIOZ_3 }; static const unsigned int tdm_c_dout2_z_pins[] = { GPIOZ_4 }; static const unsigned int tdm_c_dout3_z_pins[] = { GPIOZ_5 }; +static const unsigned int pcie_clkreqn_pins[] = { GPIOC_7 }; + static const struct meson_pmx_group meson_g12a_periphs_groups[] = { GPIO_GROUP(GPIOZ_0), GPIO_GROUP(GPIOZ_1), @@ -721,6 +723,7 @@ static const struct meson_pmx_group meson_g12a_periphs_groups[] = { GROUP(pdm_din2_c, 4), GROUP(pdm_din3_c, 4), GROUP(pdm_dclk_c, 4), + GROUP(pcie_clkreqn, 1), /* bank GPIOH */ GROUP(spi1_mosi, 3), @@ -1183,6 +1186,10 @@ static const char * const tdm_c_groups[] = { "tdm_c_dout2_z", "tdm_c_dout3_z", }; +static const char * const pcie_clkreqn_groups[] = { + "pcie_clkreqn" +}; + static const char * const gpio_aobus_groups[] = { "GPIOAO_0", "GPIOAO_1", "GPIOAO_2", "GPIOAO_3", "GPIOAO_4", "GPIOAO_5", "GPIOAO_6", "GPIOAO_7", "GPIOAO_8", "GPIOAO_9", @@ -1309,6 +1316,7 @@ static const struct meson_pmx_func meson_g12a_periphs_functions[] = { FUNCTION(tdm_a), FUNCTION(tdm_b), FUNCTION(tdm_c), + FUNCTION(pcie_clkreqn), }; static const struct meson_pmx_func meson_g12a_aobus_functions[] = { From fec40f44afdabcbc4a7748e4278f30737b54bb1a Mon Sep 17 00:00:00 2001 From: Rex Chen Date: Mon, 28 Jul 2025 17:22:29 +0900 Subject: [PATCH 01402/11391] mmc: core: SPI mode remove cmd7 SPI mode doesn't support cmd7, so remove it in mmc_sdio_alive() and confirm if sdio is active by checking CCCR register value is available or not. Signed-off-by: Rex Chen Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20250728082230.1037917-2-rex.chen_1@nxp.com Signed-off-by: Ulf Hansson --- drivers/mmc/core/sdio.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 0f753367aec1..83085e76486a 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -945,7 +945,11 @@ static void mmc_sdio_remove(struct mmc_host *host) */ static int mmc_sdio_alive(struct mmc_host *host) { - return mmc_select_card(host->card); + if (!mmc_host_is_spi(host)) + return mmc_select_card(host->card); + else + return mmc_io_rw_direct(host->card, 0, 0, SDIO_CCCR_CCCR, 0, + NULL); } /* From fef12d9f5bcf7e2b19a7cf1295c6abd5642dd241 Mon Sep 17 00:00:00 2001 From: Rex Chen Date: Mon, 28 Jul 2025 17:22:30 +0900 Subject: [PATCH 01403/11391] mmc: mmc_spi: multiple block read remove read crc ack For multiple block read, the current implementation, transfer packet includes cmd53 + cmd53 response + block nums*(1byte token + block length bytes payload + 2bytes CRC + 1byte transfer), the last 1byte transfer of every block is not needed, so remove it. Why doesn't multiple block read need CRC ack? For read operation, host side get the payload and CRC value, then will only check the CRC value to confirm if the data is correct or not, but not send CRC ack to card. If the data is correct, save it, or discard it and retransmit if data is error, so the last 1byte transfer of every block make no sense. What's the side effect of this 1byte transfer? As the SPI is full duplex, if add this redundant 1byte transfer, SDIO card side take it as the token of next block, then all the next sub blocks sequence distort. Signed-off-by: Rex Chen Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20250728082230.1037917-3-rex.chen_1@nxp.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/mmc_spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 35b0ad273b4f..95a32ff29ee1 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -563,7 +563,7 @@ mmc_spi_setup_data_message(struct mmc_spi_host *host, bool multiple, bool write) * the next token (next data block, or STOP_TRAN). We can try to * minimize I/O ops by using a single read to collect end-of-busy. */ - if (multiple || write) { + if (write) { t = &host->early_status; memset(t, 0, sizeof(*t)); t->len = write ? sizeof(scratch->status) : 1; From 9c174e4dacee9fb2014a4ffc953d79a5707b77e4 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sun, 29 Jun 2025 21:38:56 +0100 Subject: [PATCH 01404/11391] mmc: host: renesas_sdhi: Fix the actual clock Wrong actual clock reported, if the SD clock division ratio is other than 1:1(bits DIV[7:0] in SD_CLK_CTRL are set to 11111111). On high speed mode, cat /sys/kernel/debug/mmc1/ios Without the patch: clock: 50000000 Hz actual clock: 200000000 Hz After the fix: clock: 50000000 Hz actual clock: 50000000 Hz Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20250629203859.170850-1-biju.das.jz@bp.renesas.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/renesas_sdhi_core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index fb8ca03f661d..a41291a28e9b 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -222,7 +222,11 @@ static void renesas_sdhi_set_clock(struct tmio_mmc_host *host, clk &= ~0xff; } - sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & CLK_CTL_DIV_MASK); + clock = clk & CLK_CTL_DIV_MASK; + if (clock != 0xff) + host->mmc->actual_clock /= (1 << (ffs(clock) + 1)); + + sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clock); if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2)) usleep_range(10000, 11000); From 74f44ad07d1063933c237a7db16f6a4036643d60 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Wed, 30 Jul 2025 17:46:14 +0100 Subject: [PATCH 01405/11391] mmc: tmio: Add 64-bit read/write support for SD_BUF0 in polling mode As per the RZ/{G2L,G3E} HW manual SD_BUF0 can be accessed by 16/32/64 bits. Most of the data transfer in SD/SDIO/eMMC mode is more than 8 bytes. During testing it is found that, if the DMA buffer is not aligned to 128 bit it fallback to PIO mode. In such cases, 64-bit access is much more efficient than the current 16-bit. Tested-by: Wolfram Sang Reviewed-by: Wolfram Sang Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20250730164618.233117-2-biju.das.jz@bp.renesas.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/tmio_mmc.h | 15 ++++++++++++++ drivers/mmc/host/tmio_mmc_core.c | 33 ++++++++++++++++++++++++++++++ include/linux/platform_data/tmio.h | 3 +++ 3 files changed, 51 insertions(+) diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index d730b7633ae1..c8cdb1c0722e 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -242,6 +243,20 @@ static inline void sd_ctrl_read32_rep(struct tmio_mmc_host *host, int addr, ioread32_rep(host->ctl + (addr << host->bus_shift), buf, count); } +#ifdef CONFIG_64BIT +static inline void sd_ctrl_read64_rep(struct tmio_mmc_host *host, int addr, + u64 *buf, int count) +{ + readsq(host->ctl + (addr << host->bus_shift), buf, count); +} + +static inline void sd_ctrl_write64_rep(struct tmio_mmc_host *host, int addr, + const u64 *buf, int count) +{ + writesq(host->ctl + (addr << host->bus_shift), buf, count); +} +#endif + static inline void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, u16 val) { diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index 21c2f9095bac..775e0d9353d5 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -349,6 +349,39 @@ static void tmio_mmc_transfer_data(struct tmio_mmc_host *host, /* * Transfer the data */ +#ifdef CONFIG_64BIT + if (host->pdata->flags & TMIO_MMC_64BIT_DATA_PORT) { + u64 *buf64 = (u64 *)buf; + u64 data = 0; + + if (count >= 8) { + if (is_read) + sd_ctrl_read64_rep(host, CTL_SD_DATA_PORT, + buf64, count >> 3); + else + sd_ctrl_write64_rep(host, CTL_SD_DATA_PORT, + buf64, count >> 3); + } + + /* if count was multiple of 8 */ + if (!(count & 0x7)) + return; + + buf64 += count >> 3; + count %= 8; + + if (is_read) { + sd_ctrl_read64_rep(host, CTL_SD_DATA_PORT, &data, 1); + memcpy(buf64, &data, count); + } else { + memcpy(&data, buf64, count); + sd_ctrl_write64_rep(host, CTL_SD_DATA_PORT, &data, 1); + } + + return; + } +#endif + if (host->pdata->flags & TMIO_MMC_32BIT_DATA_PORT) { u32 data = 0; u32 *buf32 = (u32 *)buf; diff --git a/include/linux/platform_data/tmio.h b/include/linux/platform_data/tmio.h index b060124ba1ae..426291713b83 100644 --- a/include/linux/platform_data/tmio.h +++ b/include/linux/platform_data/tmio.h @@ -47,6 +47,9 @@ /* Some controllers have a CBSY bit */ #define TMIO_MMC_HAVE_CBSY BIT(11) +/* Some controllers have a 64-bit wide data port register */ +#define TMIO_MMC_64BIT_DATA_PORT BIT(12) + struct tmio_mmc_data { void *chan_priv_tx; void *chan_priv_rx; From 709fe7aa5aaf8047b528561a0082db8a3a29010c Mon Sep 17 00:00:00 2001 From: Biju Das Date: Wed, 30 Jul 2025 17:46:15 +0100 Subject: [PATCH 01406/11391] mmc: renesas_sdhi: Enable 64-bit polling mode Enable 64-bit polling mode for R-Car gen3 and RZ/G2L SoCs. Reviewed-by: Wolfram Sang Tested-by: Wolfram Sang Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20250730164618.233117-3-biju.das.jz@bp.renesas.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/renesas_sdhi_internal_dmac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index 4b389e92399e..9e3ed0bcddd6 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -107,7 +107,8 @@ static const struct renesas_sdhi_of_data of_data_rza2 = { static const struct renesas_sdhi_of_data of_data_rcar_gen3 = { .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL | - TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2, + TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2 | + TMIO_MMC_64BIT_DATA_PORT, .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | MMC_CAP_CMD23 | MMC_CAP_WAIT_WHILE_BUSY, .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT | MMC_CAP2_MERGE_CAPABLE, From b65e630a55a490a0269ab1e4a282af975848064c Mon Sep 17 00:00:00 2001 From: Jiayi Li Date: Mon, 4 Aug 2025 10:48:25 +0800 Subject: [PATCH 01407/11391] memstick: Add timeout to prevent indefinite waiting Add timeout handling to wait_for_completion calls in memstick_set_rw_addr() and memstick_alloc_card() to prevent indefinite blocking in case of hardware or communication failures. Signed-off-by: Jiayi Li Link: https://lore.kernel.org/r/20250804024825.1565078-1-lijiayi@kylinos.cn Signed-off-by: Ulf Hansson --- drivers/memstick/core/memstick.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c index 7f3f47db4c98..ee7a5c7ba1c5 100644 --- a/drivers/memstick/core/memstick.c +++ b/drivers/memstick/core/memstick.c @@ -370,7 +370,9 @@ int memstick_set_rw_addr(struct memstick_dev *card) { card->next_request = h_memstick_set_rw_addr; memstick_new_req(card->host); - wait_for_completion(&card->mrq_complete); + if (!wait_for_completion_timeout(&card->mrq_complete, + msecs_to_jiffies(500))) + card->current_mrq.error = -ETIMEDOUT; return card->current_mrq.error; } @@ -404,7 +406,9 @@ static struct memstick_dev *memstick_alloc_card(struct memstick_host *host) card->next_request = h_memstick_read_dev_id; memstick_new_req(host); - wait_for_completion(&card->mrq_complete); + if (!wait_for_completion_timeout(&card->mrq_complete, + msecs_to_jiffies(500))) + card->current_mrq.error = -ETIMEDOUT; if (card->current_mrq.error) goto err_out; From d2e6fb2c31a07f34e5e7533df11431cb0d2ecf9f Mon Sep 17 00:00:00 2001 From: Ricky Wu Date: Tue, 12 Aug 2025 11:08:11 +0800 Subject: [PATCH 01408/11391] misc: rtsx: usb card reader: add OCP support This patch adds support for Over Current Protection (OCP) to the Realtek USB card reader driver. The OCP mechanism protects the hardware by detecting and handling current overload conditions. This implementation includes: - Register configurations to enable OCP monitoring. - Handling of OCP interrupt events and associated error reporting. - Card power management changes in response to OCP triggers. This enhancement improves the robustness of the driver when operating in environments where electrical anomalies may occur, particularly with SD and MS card interfaces. Signed-off-by: Ricky Wu Link: https://lore.kernel.org/r/20250812030811.2426112-1-ricky_wu@realtek.com Signed-off-by: Ulf Hansson --- drivers/memstick/host/rtsx_usb_ms.c | 5 ++++- drivers/misc/cardreader/rtsx_usb.c | 7 ++++++ drivers/mmc/host/rtsx_usb_sdmmc.c | 33 ++++++++++++++++++++++++++--- include/linux/rtsx_usb.h | 11 ++++++++++ 4 files changed, 52 insertions(+), 4 deletions(-) diff --git a/drivers/memstick/host/rtsx_usb_ms.c b/drivers/memstick/host/rtsx_usb_ms.c index 3878136227e4..9389e9643c24 100644 --- a/drivers/memstick/host/rtsx_usb_ms.c +++ b/drivers/memstick/host/rtsx_usb_ms.c @@ -216,7 +216,10 @@ static int ms_power_off(struct rtsx_usb_ms *host) rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_EN, MS_CLK_EN, 0); rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_OE, MS_OUTPUT_EN, 0); - + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL, + POWER_MASK, POWER_OFF); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL, + POWER_MASK | LDO3318_PWR_MASK, POWER_OFF | LDO_SUSPEND); err = rtsx_usb_send_cmd(ucr, MODE_C, 100); if (err < 0) return err; diff --git a/drivers/misc/cardreader/rtsx_usb.c b/drivers/misc/cardreader/rtsx_usb.c index d007a4455ce5..1830e9ed2521 100644 --- a/drivers/misc/cardreader/rtsx_usb.c +++ b/drivers/misc/cardreader/rtsx_usb.c @@ -552,6 +552,10 @@ static int rtsx_usb_reset_chip(struct rtsx_ucr *ucr) ret = rtsx_usb_send_cmd(ucr, MODE_C, 100); if (ret) return ret; + /* config OCP */ + rtsx_usb_write_register(ucr, OCPCTL, MS_OCP_DETECT_EN, MS_OCP_DETECT_EN); + rtsx_usb_write_register(ucr, OCPPARA1, 0xF0, 0x50); + rtsx_usb_write_register(ucr, OCPPARA2, 0x7, 0x3); /* config non-crystal mode */ rtsx_usb_read_register(ucr, CFG_MODE, &val); @@ -722,6 +726,9 @@ static int rtsx_usb_suspend(struct usb_interface *intf, pm_message_t message) if (val & (SD_CD | MS_CD)) { device_for_each_child(&intf->dev, NULL, rtsx_usb_resume_child); return -EAGAIN; + } else { + /* if the card does not exists, clear OCP status */ + rtsx_usb_write_register(ucr, OCPCTL, MS_OCP_CLEAR, MS_OCP_CLEAR); } } else { /* There is an ongoing operation*/ diff --git a/drivers/mmc/host/rtsx_usb_sdmmc.c b/drivers/mmc/host/rtsx_usb_sdmmc.c index c5f6b9df066b..e1ed39c657c3 100644 --- a/drivers/mmc/host/rtsx_usb_sdmmc.c +++ b/drivers/mmc/host/rtsx_usb_sdmmc.c @@ -48,7 +48,7 @@ struct rtsx_usb_sdmmc { bool ddr_mode; unsigned char power_mode; - + u16 ocp_stat; #ifdef RTSX_USB_USE_LEDS_CLASS struct led_classdev led; char led_name[32]; @@ -785,6 +785,9 @@ static int sdmmc_get_cd(struct mmc_host *mmc) mutex_unlock(&ucr->dev_mutex); + /* get OCP status */ + host->ocp_stat = (val >> 4) & 0x03; + /* Treat failed detection as non-exist */ if (err) goto no_card; @@ -795,6 +798,11 @@ static int sdmmc_get_cd(struct mmc_host *mmc) } no_card: + /* clear OCP status */ + if (host->ocp_stat & (MS_OCP_NOW | MS_OCP_EVER)) { + rtsx_usb_write_register(ucr, OCPCTL, MS_OCP_CLEAR, MS_OCP_CLEAR); + host->ocp_stat = 0; + } host->card_exist = false; return 0; } @@ -818,7 +826,11 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq) cmd->error = -ENOMEDIUM; goto finish_detect_card; } - + /* check OCP stat */ + if (host->ocp_stat & (MS_OCP_NOW | MS_OCP_EVER)) { + cmd->error = -ENOMEDIUM; + goto finish_detect_card; + } mutex_lock(&ucr->dev_mutex); mutex_lock(&host->host_mutex); @@ -952,6 +964,10 @@ static int sd_power_on(struct rtsx_usb_sdmmc *host) struct rtsx_ucr *ucr = host->ucr; int err; + if (host->ocp_stat & (MS_OCP_NOW | MS_OCP_EVER)) { + dev_dbg(sdmmc_dev(host), "over current\n"); + return -EIO; + } dev_dbg(sdmmc_dev(host), "%s\n", __func__); rtsx_usb_init_cmd(ucr); rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_SELECT, 0x07, SD_MOD_SEL); @@ -977,9 +993,19 @@ static int sd_power_on(struct rtsx_usb_sdmmc *host) usleep_range(800, 1000); + rtsx_usb_init_cmd(ucr); + /* WA OCP issue: after OCP, there were problems with reopen card power */ + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL, POWER_MASK, POWER_ON); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, FPDCTL, SSC_POWER_MASK, SSC_POWER_DOWN); + err = rtsx_usb_send_cmd(ucr, MODE_C, 100); + if (err) + return err; + msleep(20); + rtsx_usb_write_register(ucr, FPDCTL, SSC_POWER_MASK, SSC_POWER_ON); + usleep_range(180, 200); rtsx_usb_init_cmd(ucr); rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL, - POWER_MASK|LDO3318_PWR_MASK, POWER_ON|LDO_ON); + LDO3318_PWR_MASK, LDO_ON); rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_OE, SD_OUTPUT_EN, SD_OUTPUT_EN); @@ -1332,6 +1358,7 @@ static void rtsx_usb_init_host(struct rtsx_usb_sdmmc *host) mmc->max_req_size = 524288; host->power_mode = MMC_POWER_OFF; + host->ocp_stat = 0; } static int rtsx_usb_sdmmc_drv_probe(struct platform_device *pdev) diff --git a/include/linux/rtsx_usb.h b/include/linux/rtsx_usb.h index f267a06c6b1e..276b509c03e3 100644 --- a/include/linux/rtsx_usb.h +++ b/include/linux/rtsx_usb.h @@ -99,6 +99,17 @@ extern int rtsx_usb_card_exclusive_check(struct rtsx_ucr *ucr, int card); #define CD_MASK (SD_CD | MS_CD | XD_CD) #define SD_WP 0x08 +/* OCPCTL */ +#define MS_OCP_DETECT_EN 0x08 +#define MS_OCP_INT_EN 0x04 +#define MS_OCP_INT_CLR 0x02 +#define MS_OCP_CLEAR 0x01 + +/* OCPSTAT */ +#define MS_OCP_DETECT 0x80 +#define MS_OCP_NOW 0x02 +#define MS_OCP_EVER 0x01 + /* reader command field offset & parameters */ #define READ_REG_CMD 0 #define WRITE_REG_CMD 1 From 40c3c7dec7cca43af1dd5d0b72499dac87d1c07b Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Tue, 12 Aug 2025 17:29:08 +0800 Subject: [PATCH 01409/11391] mmc: meson-mx-sdhc: use PTR_ERR_OR_ZERO() to simplify code Use the standard error pointer macro to shorten the code and simplify. Signed-off-by: Xichao Zhao Reviewed-by: Martin Blumenstingl Link: https://lore.kernel.org/r/20250812092908.101867-1-zhao.xichao@vivo.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/meson-mx-sdhc-clkc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mmc/host/meson-mx-sdhc-clkc.c b/drivers/mmc/host/meson-mx-sdhc-clkc.c index cbd17a596cd2..6d619bd0a8dc 100644 --- a/drivers/mmc/host/meson-mx-sdhc-clkc.c +++ b/drivers/mmc/host/meson-mx-sdhc-clkc.c @@ -84,10 +84,8 @@ static int meson_mx_sdhc_gate_clk_hw_register(struct device *dev, return ret; clk_bulk_data[bulk_index].clk = devm_clk_hw_get_clk(dev, hw, name_suffix); - if (IS_ERR(clk_bulk_data[bulk_index].clk)) - return PTR_ERR(clk_bulk_data[bulk_index].clk); - return 0; + return PTR_ERR_OR_ZERO(clk_bulk_data[bulk_index].clk); } int meson_mx_sdhc_register_clkc(struct device *dev, void __iomem *base, From ff1bd1190e746a0ba2c6db7b84c3f677fdf1dad1 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 13 Aug 2025 18:14:56 +0200 Subject: [PATCH 01410/11391] mmc: 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-11-wsa+renesas@sang-engineering.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci_am654.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c index e4fc345be7e5..8a099508b939 100644 --- a/drivers/mmc/host/sdhci_am654.c +++ b/drivers/mmc/host/sdhci_am654.c @@ -95,7 +95,6 @@ static const struct regmap_config sdhci_am654_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, - .fast_io = true, }; struct timing_data { From 18f7439fa171f798f2ff8aa69611db41f658242a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Monin?= Date: Mon, 18 Aug 2025 16:02:46 +0200 Subject: [PATCH 01411/11391] mmc: core: add mmc_card_can_cmd23 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a dedicated helper to check for CMD23 support for MMC card, similar to mmc_host_can_cmd23 for the host, as it is easy to get the check wrong. Signed-off-by: Benoît Monin Link: https://lore.kernel.org/r/20250818-mobileye-emmc-for-upstream-4-v4-1-34ecb3995e96@bootlin.com Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 9 +++++++++ drivers/mmc/core/core.h | 1 + 2 files changed, 10 insertions(+) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 874c6fe92855..88fd231fee1d 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1875,6 +1875,15 @@ bool mmc_card_can_secure_erase_trim(struct mmc_card *card) } EXPORT_SYMBOL(mmc_card_can_secure_erase_trim); +bool mmc_card_can_cmd23(struct mmc_card *card) +{ + return ((mmc_card_mmc(card) && + card->csd.mmca_vsn >= CSD_SPEC_VER_3) || + (mmc_card_sd(card) && !mmc_card_ult_capacity(card) && + card->scr.cmds & SD_SCR_CMD23_SUPPORT)); +} +EXPORT_SYMBOL(mmc_card_can_cmd23); + int mmc_erase_group_aligned(struct mmc_card *card, sector_t from, unsigned int nr) { diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 622085cd766f..73f5d3d8c77d 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -123,6 +123,7 @@ bool mmc_card_can_trim(struct mmc_card *card); bool mmc_card_can_discard(struct mmc_card *card); bool mmc_card_can_sanitize(struct mmc_card *card); bool mmc_card_can_secure_erase_trim(struct mmc_card *card); +bool mmc_card_can_cmd23(struct mmc_card *card); int mmc_erase_group_aligned(struct mmc_card *card, sector_t from, unsigned int nr); unsigned int mmc_calc_max_discard(struct mmc_card *card); From 05849fc5d842ece65a537c7492cf8dc038d15d57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Monin?= Date: Mon, 18 Aug 2025 16:02:47 +0200 Subject: [PATCH 01412/11391] mmc: card: add mmc_card_blk_no_cmd23 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a helper to check for the missing CMD23 quirk, similar to other quirk helpers. Also reorder the helpers to match the order of the quirk bits defined in include/linux/mmc/card.h. Signed-off-by: Benoît Monin Link: https://lore.kernel.org/r/20250818-mobileye-emmc-for-upstream-4-v4-2-34ecb3995e96@bootlin.com Signed-off-by: Ulf Hansson --- drivers/mmc/core/card.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/core/card.h b/drivers/mmc/core/card.h index 9cbdd240c3a7..1200951bab08 100644 --- a/drivers/mmc/core/card.h +++ b/drivers/mmc/core/card.h @@ -245,14 +245,19 @@ static inline int mmc_blksz_for_byte_mode(const struct mmc_card *c) return c->quirks & MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; } +static inline int mmc_card_nonstd_func_interface(const struct mmc_card *c) +{ + return c->quirks & MMC_QUIRK_NONSTD_FUNC_IF; +} + static inline int mmc_card_disable_cd(const struct mmc_card *c) { return c->quirks & MMC_QUIRK_DISABLE_CD; } -static inline int mmc_card_nonstd_func_interface(const struct mmc_card *c) +static inline int mmc_card_blk_no_cmd23(const struct mmc_card *c) { - return c->quirks & MMC_QUIRK_NONSTD_FUNC_IF; + return c->quirks & MMC_QUIRK_BLK_NO_CMD23; } static inline int mmc_card_broken_byte_mode_512(const struct mmc_card *c) From e5af5f5478d2e8ad6edc5bccd43b7d581177fe41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Monin?= Date: Mon, 18 Aug 2025 16:02:48 +0200 Subject: [PATCH 01413/11391] mmc: mmc_test: use mmc_card cmd23 helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use mmc_card_can_cmd23 instead of using a local and partial implementation, and check for the CMD23 quirk with mmc_card_blk_no_cmd23. Signed-off-by: Benoît Monin Link: https://lore.kernel.org/r/20250818-mobileye-emmc-for-upstream-4-v4-3-34ecb3995e96@bootlin.com Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc_test.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c index 80e5d87a5e50..67d4a301895c 100644 --- a/drivers/mmc/core/mmc_test.c +++ b/drivers/mmc/core/mmc_test.c @@ -180,20 +180,14 @@ static int mmc_test_set_blksize(struct mmc_test_card *test, unsigned size) return mmc_set_blocklen(test->card, size); } -static bool mmc_test_card_cmd23(struct mmc_card *card) -{ - return mmc_card_mmc(card) || - (mmc_card_sd(card) && card->scr.cmds & SD_SCR_CMD23_SUPPORT); -} - static void mmc_test_prepare_sbc(struct mmc_test_card *test, struct mmc_request *mrq, unsigned int blocks) { struct mmc_card *card = test->card; if (!mrq->sbc || !mmc_host_can_cmd23(card->host) || - !mmc_test_card_cmd23(card) || !mmc_op_multi(mrq->cmd->opcode) || - (card->quirks & MMC_QUIRK_BLK_NO_CMD23)) { + !mmc_card_can_cmd23(card) || !mmc_op_multi(mrq->cmd->opcode) || + mmc_card_blk_no_cmd23(card)) { mrq->sbc = NULL; return; } From f33bba9b6442fdc092ecc3b1555bc4cdbb9962bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Monin?= Date: Mon, 18 Aug 2025 16:02:49 +0200 Subject: [PATCH 01414/11391] mmc: block: use mmc_card cmd23 helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the dedicated helpers for CMD23 card support. Signed-off-by: Benoît Monin Link: https://lore.kernel.org/r/20250818-mobileye-emmc-for-upstream-4-v4-4-34ecb3995e96@bootlin.com Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 9cc47bf94804..8fd989146205 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -1768,8 +1768,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, * these, while retaining features like reliable writes. */ if ((md->flags & MMC_BLK_CMD23) && mmc_op_multi(brq->cmd.opcode) && - (do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23) || - do_data_tag)) { + (do_rel_wr || !mmc_card_blk_no_cmd23(card) || do_data_tag)) { brq->sbc.opcode = MMC_SET_BLOCK_COUNT; brq->sbc.arg = brq->data.blocks | (do_rel_wr ? (1 << 31) : 0) | @@ -2618,13 +2617,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, */ md->read_only = mmc_blk_readonly(card); - if (mmc_host_can_cmd23(card->host)) { - if ((mmc_card_mmc(card) && - card->csd.mmca_vsn >= CSD_SPEC_VER_3) || - (mmc_card_sd(card) && !mmc_card_ult_capacity(card) && - card->scr.cmds & SD_SCR_CMD23_SUPPORT)) - md->flags |= MMC_BLK_CMD23; - } + if (mmc_host_can_cmd23(card->host) && mmc_card_can_cmd23(card)) + md->flags |= MMC_BLK_CMD23; if (md->flags & MMC_BLK_CMD23 && ((card->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN) || From 99e6cc80d5ce5af5781f84d20e4f3478d66ee8ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Monin?= Date: Mon, 18 Aug 2025 16:02:50 +0200 Subject: [PATCH 01415/11391] mmc: core: add mmc_read_tuning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provide a function to the MMC hosts to read some blocks of data as part of their tuning. This function only returns the status of the read operation, not the data read. Signed-off-by: Benoît Monin Link: https://lore.kernel.org/r/20250818-mobileye-emmc-for-upstream-4-v4-5-34ecb3995e96@bootlin.com Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc_ops.c | 72 ++++++++++++++++++++++++++++++++++++++ include/linux/mmc/host.h | 1 + 2 files changed, 73 insertions(+) diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 66283825513c..a952cc8265af 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -1077,3 +1077,75 @@ int mmc_sanitize(struct mmc_card *card, unsigned int timeout_ms) return err; } EXPORT_SYMBOL_GPL(mmc_sanitize); + +/** + * mmc_read_tuning() - read data blocks from the mmc + * @host: mmc host doing the read + * @blksz: data block size + * @blocks: number of blocks to read + * + * Read one or more blocks of data from the beginning of the mmc. This is a + * low-level helper for tuning operation. It is assumed that CMD23 can be used + * for multi-block read if the host supports it. + * + * Note: Allocate and free a temporary buffer to store the data read. The data + * is not available outside of the function, only the status of the read + * operation. + * + * Return: 0 in case of success, otherwise -EIO / -ENOMEM / -E2BIG + */ +int mmc_read_tuning(struct mmc_host *host, unsigned int blksz, unsigned int blocks) +{ + struct mmc_request mrq = {}; + struct mmc_command sbc = {}; + struct mmc_command cmd = {}; + struct mmc_command stop = {}; + struct mmc_data data = {}; + struct scatterlist sg; + void *buf; + unsigned int len; + + if (blocks > 1) { + if (mmc_host_can_cmd23(host)) { + mrq.sbc = &sbc; + sbc.opcode = MMC_SET_BLOCK_COUNT; + sbc.arg = blocks; + sbc.flags = MMC_RSP_R1 | MMC_CMD_AC; + } + cmd.opcode = MMC_READ_MULTIPLE_BLOCK; + mrq.stop = &stop; + stop.opcode = MMC_STOP_TRANSMISSION; + stop.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; + } else { + cmd.opcode = MMC_READ_SINGLE_BLOCK; + } + + mrq.cmd = &cmd; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; + + mrq.data = &data; + data.flags = MMC_DATA_READ; + data.blksz = blksz; + data.blocks = blocks; + data.blk_addr = 0; + data.sg = &sg; + data.sg_len = 1; + data.timeout_ns = 1000000000; + + if (check_mul_overflow(blksz, blocks, &len)) + return -E2BIG; + buf = kmalloc(len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + sg_init_one(&sg, buf, len); + + mmc_wait_for_req(host, &mrq); + kfree(buf); + + if (sbc.error || cmd.error || data.error) + return -EIO; + + return 0; +} +EXPORT_SYMBOL_GPL(mmc_read_tuning); diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 68f09a955a90..5ed5d203de23 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -743,5 +743,6 @@ int mmc_send_status(struct mmc_card *card, u32 *status); int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error); int mmc_send_abort_tuning(struct mmc_host *host, u32 opcode); int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd); +int mmc_read_tuning(struct mmc_host *host, unsigned int blksz, unsigned int blocks); #endif /* LINUX_MMC_HOST_H */ From 60613a8b9b8187d789750423132ad7664ca448c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Monin?= Date: Mon, 18 Aug 2025 16:02:51 +0200 Subject: [PATCH 01416/11391] mmc: sdhci-cadence: implement multi-block read gap tuning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The controller suspends the clock between blocks when reading from the MMC as part of its flow-control, called read block gap. At higher clock speed and with IO delay between the controller and the MMC, this clock pause can happen too late, during the read of the next block and trigger a read error. To prevent this, the delay can be programmed for each mode via the pair of registers HRS37/38. This delay is obtained during tuning, by trying a multi-block read and increasing the delay until the read succeeds. For now, the tuning is only done in HS200, as the read error has only been observed at that speed. Acked-by: Adrian Hunter Signed-off-by: Benoît Monin Link: https://lore.kernel.org/r/20250818-mobileye-emmc-for-upstream-4-v4-6-34ecb3995e96@bootlin.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-cadence.c | 63 +++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c index 2d823e158c59..a2a4a5b0ab96 100644 --- a/drivers/mmc/host/sdhci-cadence.c +++ b/drivers/mmc/host/sdhci-cadence.c @@ -36,6 +36,24 @@ #define SDHCI_CDNS_HRS06_MODE_MMC_HS400 0x5 #define SDHCI_CDNS_HRS06_MODE_MMC_HS400ES 0x6 +/* Read block gap */ +#define SDHCI_CDNS_HRS37 0x94 /* interface mode select */ +#define SDHCI_CDNS_HRS37_MODE_DS 0x0 +#define SDHCI_CDNS_HRS37_MODE_HS 0x1 +#define SDHCI_CDNS_HRS37_MODE_UDS_SDR12 0x8 +#define SDHCI_CDNS_HRS37_MODE_UDS_SDR25 0x9 +#define SDHCI_CDNS_HRS37_MODE_UDS_SDR50 0xa +#define SDHCI_CDNS_HRS37_MODE_UDS_SDR104 0xb +#define SDHCI_CDNS_HRS37_MODE_UDS_DDR50 0xc +#define SDHCI_CDNS_HRS37_MODE_MMC_LEGACY 0x20 +#define SDHCI_CDNS_HRS37_MODE_MMC_SDR 0x21 +#define SDHCI_CDNS_HRS37_MODE_MMC_DDR 0x22 +#define SDHCI_CDNS_HRS37_MODE_MMC_HS200 0x23 +#define SDHCI_CDNS_HRS37_MODE_MMC_HS400 0x24 +#define SDHCI_CDNS_HRS37_MODE_MMC_HS400ES 0x25 +#define SDHCI_CDNS_HRS38 0x98 /* Read block gap coefficient */ +#define SDHCI_CDNS_HRS38_BLKGAP_MAX 0xf + /* SRS - Slot Register Set (SDHCI-compatible) */ #define SDHCI_CDNS_SRS_BASE 0x200 @@ -251,6 +269,44 @@ static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val) return 0; } +/** + * sdhci_cdns_tune_blkgap() - tune multi-block read gap + * @mmc: MMC host + * + * Tune delay used in multi block read. To do so, + * try sending multi-block read command with incremented gap, unless + * it succeeds. + * + * Return: error code + */ +static int sdhci_cdns_tune_blkgap(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_cdns_priv *priv = sdhci_pltfm_priv(pltfm_host); + void __iomem *hrs37_reg = priv->hrs_addr + SDHCI_CDNS_HRS37; + void __iomem *hrs38_reg = priv->hrs_addr + SDHCI_CDNS_HRS38; + int ret; + u32 gap; + u32 hrs37_mode; + + /* Currently only needed in HS200 mode */ + if (host->timing != MMC_TIMING_MMC_HS200) + return 0; + + writel(hrs37_mode, hrs37_reg); + + for (gap = 0; gap <= SDHCI_CDNS_HRS38_BLKGAP_MAX; gap++) { + writel(gap, hrs38_reg); + ret = mmc_read_tuning(mmc, 512, 32); + if (!ret) + break; + } + + dev_dbg(mmc_dev(mmc), "read block gap tune %s, gap %d\n", ret ? "failed" : "OK", gap); + return ret; +} + /* * In SD mode, software must not use the hardware tuning and instead perform * an almost identical procedure to eMMC. @@ -261,6 +317,7 @@ static int sdhci_cdns_execute_tuning(struct sdhci_host *host, u32 opcode) int max_streak = 0; int end_of_streak = 0; int i; + int ret; /* * Do not execute tuning for UHS_SDR50 or UHS_DDR50. @@ -288,7 +345,11 @@ static int sdhci_cdns_execute_tuning(struct sdhci_host *host, u32 opcode) return -EIO; } - return sdhci_cdns_set_tune_val(host, end_of_streak - max_streak / 2); + ret = sdhci_cdns_set_tune_val(host, end_of_streak - max_streak / 2); + if (ret) + return ret; + + return sdhci_cdns_tune_blkgap(host->mmc); } static void sdhci_cdns_set_uhs_signaling(struct sdhci_host *host, From 730ff06d3f5cc2ce0348414b78c10528b767d4a3 Mon Sep 17 00:00:00 2001 From: Dipayaan Roy Date: Thu, 14 Aug 2025 07:04:10 -0700 Subject: [PATCH 01417/11391] net: mana: Use page pool fragments for RX buffers instead of full pages to improve memory efficiency. This patch enhances RX buffer handling in the mana driver by allocating pages from a page pool and slicing them into MTU-sized fragments, rather than dedicating a full page per packet. This approach is especially beneficial on systems with large base page sizes like 64KB. Key improvements: - Proper integration of page pool for RX buffer allocations. - MTU-sized buffer slicing to improve memory utilization. - Reduce overall per Rx queue memory footprint. - Automatic fallback to full-page buffers when: * Jumbo frames are enabled (MTU > PAGE_SIZE / 2). * The XDP path is active, to avoid complexities with fragment reuse. Testing on VMs with 64KB pages shows around 200% throughput improvement. Memory efficiency is significantly improved due to reduced wastage in page allocations. Example: We are now able to fit 35 rx buffers in a single 64kb page for MTU size of 1500, instead of 1 rx buffer per page previously. Tested: - iperf3, iperf2, and nttcp benchmarks. - Jumbo frames with MTU 9000. - Native XDP programs (XDP_PASS, XDP_DROP, XDP_TX, XDP_REDIRECT) for testing the XDP path in driver. - Memory leak detection (kmemleak). - Driver load/unload, reboot, and stress scenarios. Reviewed-by: Jacob Keller Reviewed-by: Saurabh Sengar Reviewed-by: Haiyang Zhang Signed-off-by: Dipayaan Roy Link: https://patch.msgid.link/20250814140410.GA22089@linuxonhyperv3.guj3yctzbm1etfxqx2vob5hsef.xx.internal.cloudapp.net Signed-off-by: Paolo Abeni --- .../net/ethernet/microsoft/mana/mana_bpf.c | 46 +++++- drivers/net/ethernet/microsoft/mana/mana_en.c | 153 ++++++++++++------ include/net/mana/mana.h | 4 + 3 files changed, 151 insertions(+), 52 deletions(-) diff --git a/drivers/net/ethernet/microsoft/mana/mana_bpf.c b/drivers/net/ethernet/microsoft/mana/mana_bpf.c index d30721d4516f..7697c9b52ed3 100644 --- a/drivers/net/ethernet/microsoft/mana/mana_bpf.c +++ b/drivers/net/ethernet/microsoft/mana/mana_bpf.c @@ -174,6 +174,7 @@ static int mana_xdp_set(struct net_device *ndev, struct bpf_prog *prog, struct mana_port_context *apc = netdev_priv(ndev); struct bpf_prog *old_prog; struct gdma_context *gc; + int err; gc = apc->ac->gdma_dev->gdma_context; @@ -195,18 +196,57 @@ static int mana_xdp_set(struct net_device *ndev, struct bpf_prog *prog, */ apc->bpf_prog = prog; + if (apc->port_is_up) { + /* Re-create rxq's after xdp prog was loaded or unloaded. + * Ex: re create rxq's to switch from full pages to smaller + * size page fragments when xdp prog is unloaded and + * vice-versa. + */ + + /* Pre-allocate buffers to prevent failure in mana_attach */ + err = mana_pre_alloc_rxbufs(apc, ndev->mtu, apc->num_queues); + if (err) { + NL_SET_ERR_MSG_MOD(extack, + "XDP: Insufficient memory for tx/rx re-config"); + return err; + } + + err = mana_detach(ndev, false); + if (err) { + netdev_err(ndev, + "mana_detach failed at xdp set: %d\n", err); + NL_SET_ERR_MSG_MOD(extack, + "XDP: Re-config failed at detach"); + goto err_dealloc_rxbuffs; + } + + err = mana_attach(ndev); + if (err) { + netdev_err(ndev, + "mana_attach failed at xdp set: %d\n", err); + NL_SET_ERR_MSG_MOD(extack, + "XDP: Re-config failed at attach"); + goto err_dealloc_rxbuffs; + } + + mana_chn_setxdp(apc, prog); + mana_pre_dealloc_rxbufs(apc); + } + if (old_prog) bpf_prog_put(old_prog); - if (apc->port_is_up) - mana_chn_setxdp(apc, prog); - if (prog) ndev->max_mtu = MANA_XDP_MTU_MAX; else ndev->max_mtu = gc->adapter_mtu - ETH_HLEN; return 0; + +err_dealloc_rxbuffs: + apc->bpf_prog = old_prog; + mana_pre_dealloc_rxbufs(apc); + return err; } int mana_bpf(struct net_device *ndev, struct netdev_bpf *bpf) diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c index 550843e2164b..f4fc86f20213 100644 --- a/drivers/net/ethernet/microsoft/mana/mana_en.c +++ b/drivers/net/ethernet/microsoft/mana/mana_en.c @@ -57,6 +57,15 @@ static bool mana_en_need_log(struct mana_port_context *apc, int err) return true; } +static void mana_put_rx_page(struct mana_rxq *rxq, struct page *page, + bool from_pool) +{ + if (from_pool) + page_pool_put_full_page(rxq->page_pool, page, false); + else + put_page(page); +} + /* Microsoft Azure Network Adapter (MANA) functions */ static int mana_open(struct net_device *ndev) @@ -630,21 +639,40 @@ static void *mana_get_rxbuf_pre(struct mana_rxq *rxq, dma_addr_t *da) } /* Get RX buffer's data size, alloc size, XDP headroom based on MTU */ -static void mana_get_rxbuf_cfg(int mtu, u32 *datasize, u32 *alloc_size, - u32 *headroom) +static void mana_get_rxbuf_cfg(struct mana_port_context *apc, + int mtu, u32 *datasize, u32 *alloc_size, + u32 *headroom, u32 *frag_count) { - if (mtu > MANA_XDP_MTU_MAX) - *headroom = 0; /* no support for XDP */ - else - *headroom = XDP_PACKET_HEADROOM; - - *alloc_size = SKB_DATA_ALIGN(mtu + MANA_RXBUF_PAD + *headroom); - - /* Using page pool in this case, so alloc_size is PAGE_SIZE */ - if (*alloc_size < PAGE_SIZE) - *alloc_size = PAGE_SIZE; + u32 len, buf_size; + /* Calculate datasize first (consistent across all cases) */ *datasize = mtu + ETH_HLEN; + + /* For xdp and jumbo frames make sure only one packet fits per page */ + if (mtu + MANA_RXBUF_PAD > PAGE_SIZE / 2 || mana_xdp_get(apc)) { + if (mana_xdp_get(apc)) { + *headroom = XDP_PACKET_HEADROOM; + *alloc_size = PAGE_SIZE; + } else { + *headroom = 0; /* no support for XDP */ + *alloc_size = SKB_DATA_ALIGN(mtu + MANA_RXBUF_PAD + + *headroom); + } + + *frag_count = 1; + return; + } + + /* Standard MTU case - optimize for multiple packets per page */ + *headroom = 0; + + /* Calculate base buffer size needed */ + len = SKB_DATA_ALIGN(mtu + MANA_RXBUF_PAD + *headroom); + buf_size = ALIGN(len, MANA_RX_FRAG_ALIGNMENT); + + /* Calculate how many packets can fit in a page */ + *frag_count = PAGE_SIZE / buf_size; + *alloc_size = buf_size; } int mana_pre_alloc_rxbufs(struct mana_port_context *mpc, int new_mtu, int num_queues) @@ -656,8 +684,9 @@ int mana_pre_alloc_rxbufs(struct mana_port_context *mpc, int new_mtu, int num_qu void *va; int i; - mana_get_rxbuf_cfg(new_mtu, &mpc->rxbpre_datasize, - &mpc->rxbpre_alloc_size, &mpc->rxbpre_headroom); + mana_get_rxbuf_cfg(mpc, new_mtu, &mpc->rxbpre_datasize, + &mpc->rxbpre_alloc_size, &mpc->rxbpre_headroom, + &mpc->rxbpre_frag_count); dev = mpc->ac->gdma_dev->gdma_context->dev; @@ -1842,8 +1871,11 @@ static void mana_rx_skb(void *buf_va, bool from_pool, drop: if (from_pool) { - page_pool_recycle_direct(rxq->page_pool, - virt_to_head_page(buf_va)); + if (rxq->frag_count == 1) + page_pool_recycle_direct(rxq->page_pool, + virt_to_head_page(buf_va)); + else + page_pool_free_va(rxq->page_pool, buf_va, true); } else { WARN_ON_ONCE(rxq->xdp_save_va); /* Save for reuse */ @@ -1859,33 +1891,46 @@ static void *mana_get_rxfrag(struct mana_rxq *rxq, struct device *dev, dma_addr_t *da, bool *from_pool) { struct page *page; + u32 offset; void *va; - *from_pool = false; - /* Reuse XDP dropped page if available */ - if (rxq->xdp_save_va) { - va = rxq->xdp_save_va; - rxq->xdp_save_va = NULL; - } else { - page = page_pool_dev_alloc_pages(rxq->page_pool); - if (!page) + /* Don't use fragments for jumbo frames or XDP where it's 1 fragment + * per page. + */ + if (rxq->frag_count == 1) { + /* Reuse XDP dropped page if available */ + if (rxq->xdp_save_va) { + va = rxq->xdp_save_va; + page = virt_to_head_page(va); + rxq->xdp_save_va = NULL; + } else { + page = page_pool_dev_alloc_pages(rxq->page_pool); + if (!page) + return NULL; + + *from_pool = true; + va = page_to_virt(page); + } + + *da = dma_map_single(dev, va + rxq->headroom, rxq->datasize, + DMA_FROM_DEVICE); + if (dma_mapping_error(dev, *da)) { + mana_put_rx_page(rxq, page, *from_pool); return NULL; + } - *from_pool = true; - va = page_to_virt(page); + return va; } - *da = dma_map_single(dev, va + rxq->headroom, rxq->datasize, - DMA_FROM_DEVICE); - if (dma_mapping_error(dev, *da)) { - if (*from_pool) - page_pool_put_full_page(rxq->page_pool, page, false); - else - put_page(virt_to_head_page(va)); - + page = page_pool_dev_alloc_frag(rxq->page_pool, &offset, + rxq->alloc_size); + if (!page) return NULL; - } + + va = page_to_virt(page) + offset; + *da = page_pool_get_dma_addr(page) + offset + rxq->headroom; + *from_pool = true; return va; } @@ -1902,9 +1947,9 @@ static void mana_refill_rx_oob(struct device *dev, struct mana_rxq *rxq, va = mana_get_rxfrag(rxq, dev, &da, &from_pool); if (!va) return; - - dma_unmap_single(dev, rxoob->sgl[0].address, rxq->datasize, - DMA_FROM_DEVICE); + if (!rxoob->from_pool || rxq->frag_count == 1) + dma_unmap_single(dev, rxoob->sgl[0].address, rxq->datasize, + DMA_FROM_DEVICE); *old_buf = rxoob->buf_va; *old_fp = rxoob->from_pool; @@ -2315,15 +2360,15 @@ static void mana_destroy_rxq(struct mana_port_context *apc, if (!rx_oob->buf_va) continue; - dma_unmap_single(dev, rx_oob->sgl[0].address, - rx_oob->sgl[0].size, DMA_FROM_DEVICE); - page = virt_to_head_page(rx_oob->buf_va); - if (rx_oob->from_pool) - page_pool_put_full_page(rxq->page_pool, page, false); - else - put_page(page); + if (rxq->frag_count == 1 || !rx_oob->from_pool) { + dma_unmap_single(dev, rx_oob->sgl[0].address, + rx_oob->sgl[0].size, DMA_FROM_DEVICE); + mana_put_rx_page(rxq, page, rx_oob->from_pool); + } else { + page_pool_free_va(rxq->page_pool, rx_oob->buf_va, true); + } rx_oob->buf_va = NULL; } @@ -2429,11 +2474,22 @@ static int mana_create_page_pool(struct mana_rxq *rxq, struct gdma_context *gc) struct page_pool_params pprm = {}; int ret; - pprm.pool_size = mpc->rx_queue_size; + pprm.pool_size = mpc->rx_queue_size / rxq->frag_count + 1; pprm.nid = gc->numa_node; pprm.napi = &rxq->rx_cq.napi; pprm.netdev = rxq->ndev; pprm.order = get_order(rxq->alloc_size); + pprm.queue_idx = rxq->rxq_idx; + pprm.dev = gc->dev; + + /* Let the page pool do the dma map when page sharing with multiple + * fragments enabled for rx buffers. + */ + if (rxq->frag_count > 1) { + pprm.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV; + pprm.max_len = PAGE_SIZE; + pprm.dma_dir = DMA_FROM_DEVICE; + } rxq->page_pool = page_pool_create(&pprm); @@ -2472,9 +2528,8 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc, rxq->rxq_idx = rxq_idx; rxq->rxobj = INVALID_MANA_HANDLE; - mana_get_rxbuf_cfg(ndev->mtu, &rxq->datasize, &rxq->alloc_size, - &rxq->headroom); - + mana_get_rxbuf_cfg(apc, ndev->mtu, &rxq->datasize, &rxq->alloc_size, + &rxq->headroom, &rxq->frag_count); /* Create page pool for RX queue */ err = mana_create_page_pool(rxq, gc); if (err) { diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h index e1030a7d2daa..0921485565c0 100644 --- a/include/net/mana/mana.h +++ b/include/net/mana/mana.h @@ -65,6 +65,8 @@ enum TRI_STATE { #define MANA_STATS_RX_COUNT 5 #define MANA_STATS_TX_COUNT 11 +#define MANA_RX_FRAG_ALIGNMENT 64 + struct mana_stats_rx { u64 packets; u64 bytes; @@ -328,6 +330,7 @@ struct mana_rxq { u32 datasize; u32 alloc_size; u32 headroom; + u32 frag_count; mana_handle_t rxobj; @@ -510,6 +513,7 @@ struct mana_port_context { u32 rxbpre_datasize; u32 rxbpre_alloc_size; u32 rxbpre_headroom; + u32 rxbpre_frag_count; struct bpf_prog *bpf_prog; From fe2e8f17a56fe14915cd6b709e9f56a16029f104 Mon Sep 17 00:00:00 2001 From: Fange Zhang Date: Mon, 18 Aug 2025 12:41:23 +0800 Subject: [PATCH 01418/11391] pinctrl: sx150x: Make the driver tristate Set PINCTRL_SX150X config option as a tristate and add MODULE_DEVICE_TABLE()/MODULE_LICENSE() to export appropriate information. Signed-off-by: Fange Zhang Link: https://lore.kernel.org/20250818-modularize-sx150x-gpio-expander-v1-1-c2a027200fed@oss.qualcomm.com Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 2 +- drivers/pinctrl/pinctrl-sx150x.c | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 463cf252c275..6714aecce325 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -550,7 +550,7 @@ config PINCTRL_STMFX interrupt-controller. config PINCTRL_SX150X - bool "Semtech SX150x I2C GPIO expander pinctrl driver" + tristate "Semtech SX150x I2C GPIO expander pinctrl driver" depends on I2C=y select PINMUX select PINCONF diff --git a/drivers/pinctrl/pinctrl-sx150x.c b/drivers/pinctrl/pinctrl-sx150x.c index 53cf8168b274..b613568b42b7 100644 --- a/drivers/pinctrl/pinctrl-sx150x.c +++ b/drivers/pinctrl/pinctrl-sx150x.c @@ -863,6 +863,7 @@ static const struct of_device_id sx150x_of_match[] = { { .compatible = "semtech,sx1509q", .data = &sx1509q_device_data }, {}, }; +MODULE_DEVICE_TABLE(of, sx150x_of_match); static int sx150x_reset(struct sx150x_pinctrl *pctl) { @@ -1266,3 +1267,6 @@ static int __init sx150x_init(void) return i2c_add_driver(&sx150x_driver); } subsys_initcall(sx150x_init); + +MODULE_DESCRIPTION("Semtech SX150x I2C GPIO expander pinctrl driver"); +MODULE_LICENSE("GPL"); From 0283b8f134e499a51bb972403eb47cda6b960f7c Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 14 Aug 2025 18:33:14 -0700 Subject: [PATCH 01419/11391] selftests: drv-net: test the napi init state Test that threaded state (in the persistent NAPI config) gets updated even when NAPI with given ID is not allocated at the time. This test is validating commit ccba9f6baa90 ("net: update NAPI threaded config even for disabled NAPIs"). Signed-off-by: Jakub Kicinski Reviewed-by: Joe Damato Link: https://patch.msgid.link/20250815013314.2237512-1-kuba@kernel.org Signed-off-by: Paolo Abeni --- .../selftests/drivers/net/napi_threaded.py | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/drivers/net/napi_threaded.py b/tools/testing/selftests/drivers/net/napi_threaded.py index 9699a100a87d..ed66efa481b0 100755 --- a/tools/testing/selftests/drivers/net/napi_threaded.py +++ b/tools/testing/selftests/drivers/net/napi_threaded.py @@ -38,6 +38,34 @@ def _setup_deferred_cleanup(cfg) -> None: return combined +def napi_init(cfg, nl) -> None: + """ + Test that threaded state (in the persistent NAPI config) gets updated + even when NAPI with given ID is not allocated at the time. + """ + + qcnt = _setup_deferred_cleanup(cfg) + + _set_threaded_state(cfg, 1) + cmd(f"ethtool -L {cfg.ifname} combined 1") + _set_threaded_state(cfg, 0) + cmd(f"ethtool -L {cfg.ifname} combined {qcnt}") + + napis = nl.napi_get({'ifindex': cfg.ifindex}, dump=True) + for napi in napis: + ksft_eq(napi['threaded'], 'disabled') + ksft_eq(napi.get('pid'), None) + + cmd(f"ethtool -L {cfg.ifname} combined 1") + _set_threaded_state(cfg, 1) + cmd(f"ethtool -L {cfg.ifname} combined {qcnt}") + + napis = nl.napi_get({'ifindex': cfg.ifindex}, dump=True) + for napi in napis: + ksft_eq(napi['threaded'], 'enabled') + ksft_ne(napi.get('pid'), None) + + def enable_dev_threaded_disable_napi_threaded(cfg, nl) -> None: """ Test that when napi threaded is enabled at device level and @@ -103,7 +131,8 @@ def main() -> None: """ Ksft boiler plate main """ with NetDrvEnv(__file__, queue_count=2) as cfg: - ksft_run([change_num_queues, + ksft_run([napi_init, + change_num_queues, enable_dev_threaded_disable_napi_threaded], args=(cfg, NetdevFamily())) ksft_exit() From da114122b83149d1f1db0586b1d67947b651aa20 Mon Sep 17 00:00:00 2001 From: Chaoyi Chen Date: Fri, 15 Aug 2025 10:35:15 +0800 Subject: [PATCH 01420/11391] net: ethernet: stmmac: dwmac-rk: Make the clk_phy could be used for external phy For external phy, clk_phy should be optional, and some external phy need the clock input from clk_phy. This patch adds support for setting clk_phy for external phy. Signed-off-by: David Wu Signed-off-by: Chaoyi Chen Link: https://patch.msgid.link/20250815023515.114-1-kernel@airkyi.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c index 7c898768d544..9fc41207cc45 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c @@ -1412,12 +1412,15 @@ static int rk_gmac_clk_init(struct plat_stmmacenet_data *plat) clk_set_rate(plat->stmmac_clk, 50000000); } - if (plat->phy_node && bsp_priv->integrated_phy) { + if (plat->phy_node) { bsp_priv->clk_phy = of_clk_get(plat->phy_node, 0); ret = PTR_ERR_OR_ZERO(bsp_priv->clk_phy); - if (ret) - return dev_err_probe(dev, ret, "Cannot get PHY clock\n"); - clk_set_rate(bsp_priv->clk_phy, 50000000); + /* If it is not integrated_phy, clk_phy is optional */ + if (bsp_priv->integrated_phy) { + if (ret) + return dev_err_probe(dev, ret, "Cannot get PHY clock\n"); + clk_set_rate(bsp_priv->clk_phy, 50000000); + } } return 0; From a895dc47ceba63feb711905440585cf2b16e9ce2 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 3 Jul 2025 14:08:45 +0200 Subject: [PATCH 01421/11391] 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 01422/11391] 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 01423/11391] 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 01424/11391] 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 01425/11391] 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 01426/11391] 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 | 104 +++++++++++++++++++++++-------------- arch/x86/kvm/mmu/tdp_mmu.c | 42 ++++++++++++--- 2 files changed, 100 insertions(+), 46 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 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. - */ - slot = NULL; - if (atomic_read(&kvm->nr_memslots_dirty_logging)) { - struct kvm_memslots *slots; + unaccount_nx_huge_page(kvm, sp); + + if (is_tdp_mmu) + spin_unlock(tdp_mmu_pages_lock); + + /* + * 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. + */ + 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 01427/11391] 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 01428/11391] 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 cec6e40a02ef66e28208dc808cd28cce418efc1d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 19 Aug 2025 15:15:50 +0200 Subject: [PATCH 01429/11391] riscv: dts: microchip: Minor whitespace cleanup The DTS code coding style expects exactly one space around '=' character. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Conor Dooley --- arch/riscv/boot/dts/microchip/mpfs-beaglev-fire.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/boot/dts/microchip/mpfs-beaglev-fire.dts b/arch/riscv/boot/dts/microchip/mpfs-beaglev-fire.dts index 47cf693beb68..55e30f3636df 100644 --- a/arch/riscv/boot/dts/microchip/mpfs-beaglev-fire.dts +++ b/arch/riscv/boot/dts/microchip/mpfs-beaglev-fire.dts @@ -88,7 +88,7 @@ &gpio2 { <53>, <53>, <53>, <53>, <53>, <53>, <53>, <53>, <53>, <53>, <53>, <53>; - ngpios=<32>; + ngpios = <32>; gpio-line-names = "P8_PIN3_USER_LED_0", "P8_PIN4_USER_LED_1", "P8_PIN5_USER_LED_2", "P8_PIN6_USER_LED_3", "P8_PIN7_USER_LED_4", "P8_PIN8_USER_LED_5", "P8_PIN9_USER_LED_6", "P8_PIN10_USER_LED_7", "P8_PIN11_USER_LED_8", From f7f804633c91f0fbf03eefbae39eec2205191a82 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 18 Aug 2025 15:30:14 +0300 Subject: [PATCH 01430/11391] regulator: rt5133: Fix IS_ERR() vs NULL bug in rt5133_validate_vendor_info() The "priv->cdata" pointer isn't an error pointer; this should be a NULL check instead. Otherwise it leads to a NULL pointer dereference in the caller, rt5133_probe(). Fixes: 714165e1c4b0 ("regulator: rt5133: Add RT5133 PMIC regulator Support") Signed-off-by: Dan Carpenter Link: https://patch.msgid.link/aKMc1oK-7yY4cD3K@stanley.mountain Signed-off-by: Mark Brown --- drivers/regulator/rt5133-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/rt5133-regulator.c b/drivers/regulator/rt5133-regulator.c index 39532618e73d..129b1f13c880 100644 --- a/drivers/regulator/rt5133-regulator.c +++ b/drivers/regulator/rt5133-regulator.c @@ -510,7 +510,7 @@ static int rt5133_validate_vendor_info(struct rt5133_priv *priv) break; } } - if (IS_ERR(priv->cdata)) { + if (!priv->cdata) { dev_err(priv->dev, "Failed to find regulator match version\n"); return -ENODEV; } From ec0be3cdf40b5302248f3fb27a911cc630e8b855 Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Tue, 19 Aug 2025 12:25:43 +0800 Subject: [PATCH 01431/11391] regulator: consumer.rst: document bulk operations The current consumer documentation does not include bulk operations, providing an example of how to acquire multiple regulators by calling regulator_get() multiple times. That solution is valid and slightly simpler for a small amount of regulators, but it does not scale well. Document the bulk operations to get, enable and disable regulators. Signed-off-by: Javier Carrasco Link: https://patch.msgid.link/20250819-reg_consumer_doc-v1-1-b631fc0d35a3@gmail.com Signed-off-by: Mark Brown --- Documentation/power/regulator/consumer.rst | 30 +++++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/Documentation/power/regulator/consumer.rst b/Documentation/power/regulator/consumer.rst index 9d2416f63f6e..c01675b25a90 100644 --- a/Documentation/power/regulator/consumer.rst +++ b/Documentation/power/regulator/consumer.rst @@ -23,10 +23,18 @@ To release the regulator the consumer driver should call :: regulator_put(regulator); Consumers can be supplied by more than one regulator e.g. codec consumer with -analog and digital supplies :: +analog and digital supplies by means of bulk operations :: + + struct regulator_bulk_data supplies[2]; + + supplies[0].supply = "Vcc"; /* digital core */ + supplies[1].supply = "Avdd"; /* analog */ + + ret = regulator_bulk_get(dev, ARRAY_SIZE(supplies), supplies); + + // convenience helper to call regulator_put() on multiple regulators + regulator_bulk_free(ARRAY_SIZE(supplies), supplies); - digital = regulator_get(dev, "Vcc"); /* digital core */ - analog = regulator_get(dev, "Avdd"); /* analog */ The regulator access functions regulator_get() and regulator_put() will usually be called in your device drivers probe() and remove() respectively. @@ -51,11 +59,21 @@ A consumer can determine if a regulator is enabled by calling:: This will return > zero when the regulator is enabled. +A set of regulators can be enabled with a single bulk operation :: + + int regulator_bulk_enable(int num_consumers, + struct regulator_bulk_data *consumers); + A consumer can disable its supply when no longer needed by calling:: int regulator_disable(regulator); +Or a number of them :: + + int regulator_bulk_disable(int num_consumers, + struct regulator_bulk_data *consumers); + NOTE: This may not disable the supply if it's shared with other consumers. The regulator will only be disabled when the enabled reference count is zero. @@ -64,11 +82,15 @@ Finally, a regulator can be forcefully disabled in the case of an emergency:: int regulator_force_disable(regulator); +This operation is also supported for multiple regulators :: + + int regulator_bulk_force_disable(int num_consumers, + struct regulator_bulk_data *consumers); + NOTE: this will immediately and forcefully shutdown the regulator output. All consumers will be powered off. - 3. Regulator Voltage Control & Status (dynamic drivers) ======================================================= From 05f297c3e39f62f579458a59ab1b1c8bf3fc1c51 Mon Sep 17 00:00:00 2001 From: Gopi Krishna Menon Date: Wed, 13 Aug 2025 21:17:51 +0530 Subject: [PATCH 01432/11391] 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 01433/11391] 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 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, 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 01434/11391] 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 01435/11391] 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 8efe8816a7ddc98a733ca3326ae8794750bbbd34 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Mon, 18 Aug 2025 20:08:48 +0200 Subject: [PATCH 01436/11391] rust: alloc: add ARCH_KMALLOC_MINALIGN to bindgen blocklist For some architectures, such as X86_64, ARCH_KMALLOC_MINALIGN is not resolvable for bindgen. E.g. due to being defined as __alignof__(unsigned long long). Hence, we have to create a rust helper, i.e. let the C compiler evaluate the expression and store it in a const. However, if for other architectures, such as arm64, ARCH_KMALLOC_MINALIGN does evaluate to something that can be directly processed by bindgen, we end up with multiple definitions of ARCH_KMALLOC_MINALIGN in the generated bindings. error[E0428]: the name `ARCH_KMALLOC_MINALIGN` is defined multiple times --> /builddir/build/BUILD/kernel-6.17.0-build/kernel-next-20250818/linux-6.17.0-0.0.next.20250818.423.vanilla.fc44.aarch64/rust/bindings/bindings_generated.rs:134545:1 | 9622 | pub const ARCH_KMALLOC_MINALIGN: u32 = 8; | ----------------------------------------- previous definition of the value `ARCH_KMALLOC_MINALIGN` here ... 134545 | pub const ARCH_KMALLOC_MINALIGN: usize = 8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ARCH_KMALLOC_MINALIGN` redefined here | = note: `ARCH_KMALLOC_MINALIGN` must be defined only once in the value namespace of this module To fix this up, add ARCH_KMALLOC_MINALIGN to the blocklist of bindgen, such that we always only generate the symbol from the rust helper. Reported-by: Thorsten Leemhuis Closes: https://lore.kernel.org/all/8aa05f08-ef6e-4dfe-9453-beaab7b3cb98@leemhuis.info/ Fixes: 1b1a946dc2b5 ("rust: alloc: specify the minimum alignment of each allocator") Tested-by: Thorsten Leemhuis Reviewed-by: Alice Ryhl Link: https://lore.kernel.org/r/20250818180923.192042-1-dakr@kernel.org Signed-off-by: Danilo Krummrich --- rust/bindgen_parameters | 1 + 1 file changed, 1 insertion(+) diff --git a/rust/bindgen_parameters b/rust/bindgen_parameters index 0f96af8b9a7f..02b371b98b39 100644 --- a/rust/bindgen_parameters +++ b/rust/bindgen_parameters @@ -34,3 +34,4 @@ # We use const helpers to aid bindgen, to avoid conflicts when constants are # recognized, block generation of the non-helper constants. --blocklist-item ARCH_SLAB_MINALIGN +--blocklist-item ARCH_KMALLOC_MINALIGN From 481ee0fcbb9a0f0706d6d29de9570d1048aff631 Mon Sep 17 00:00:00 2001 From: E Shattow Date: Tue, 29 Jul 2025 07:11:35 -0700 Subject: [PATCH 01437/11391] riscv: dts: starfive: jh7110-common: drop no-sdio property from mmc1 Relax no-sdio restriction on mmc1 for jh7110 boards. Property was introduced for StarFive VisionFive2 dts to configure mmc1 for SD Card but this is not necessary, the restriction is only needed to block use of commands that would cause a device to malfunction. Signed-off-by: E Shattow Signed-off-by: Conor Dooley --- arch/riscv/boot/dts/starfive/jh7110-common.dtsi | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/riscv/boot/dts/starfive/jh7110-common.dtsi b/arch/riscv/boot/dts/starfive/jh7110-common.dtsi index 2eaf01775ef5..a315113840e5 100644 --- a/arch/riscv/boot/dts/starfive/jh7110-common.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110-common.dtsi @@ -299,7 +299,6 @@ &mmc1 { assigned-clock-rates = <50000000>; bus-width = <4>; bootph-pre-ram; - no-sdio; no-mmc; cd-gpios = <&sysgpio 41 GPIO_ACTIVE_LOW>; disable-wp; From cf6a8401b6a12c3bdd54c7414af28625ec6450da Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Thu, 7 Aug 2025 22:49:43 +0800 Subject: [PATCH 01438/11391] 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 01439/11391] 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 01440/11391] 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 01441/11391] 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 01442/11391] 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 01443/11391] 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 01444/11391] 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 01445/11391] 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 01446/11391] 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 01447/11391] 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 01448/11391] 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 01449/11391] 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 01450/11391] 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 01451/11391] 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 01452/11391] 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 01453/11391] 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 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, */ 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 01454/11391] 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 01455/11391] 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 01456/11391] 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 01457/11391] 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 01458/11391] 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 01459/11391] 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 01460/11391] 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 01461/11391] 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 01462/11391] 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 01463/11391] 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 01464/11391] 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 01465/11391] 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 01466/11391] 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 01467/11391] 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 01468/11391] 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 01469/11391] 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 01470/11391] 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 01471/11391] 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 01472/11391] 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 c5746dc1898a1bd5518a03081dc7e380569e269d Mon Sep 17 00:00:00 2001 From: Zihuan Zhang Date: Fri, 25 Jul 2025 12:14:50 +0800 Subject: [PATCH 01473/11391] cpufreq: Avoid calling get_governor() for first policy When a cpufreq driver registers the first policy, it may attempt to initialize the policy governor from `last_governor`. However, this is meaningless for the first policy instance, because `last_governor` is only updated when policies are removed (e.g. during CPU offline). The `last_governor` mechanism is intended to restore the previously used governor across CPU hotplug events. For the very first policy, there is no "previous governor" to restore, so calling get_governor(last_governor) is unnecessary and potentially confusing. Skip looking up `last_governor` when registering the first policy. Instead, it directly uses the default governor after all governors have been registered and are available. This avoids meaningless lookups, reduces unnecessary module reference handling, and simplifies the initial policy path. Signed-off-by: Zihuan Zhang Acked-by: Viresh Kumar Reviewed-by: Lifeng Zheng Link: https://patch.msgid.link/20250725041450.68754-1-zhangzihuan@kylinos.cn [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index fc7eace8b65b..b8937737d096 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1121,7 +1121,8 @@ static int cpufreq_init_policy(struct cpufreq_policy *policy) if (has_target()) { /* Update policy governor to the one used before hotplug. */ - gov = get_governor(policy->last_governor); + if (policy->last_governor[0] != '\0') + gov = get_governor(policy->last_governor); if (gov) { pr_debug("Restoring governor %s for cpu %d\n", gov->name, policy->cpu); From 3d9ab61f53cdf72fed737c66652a8aad9d27504c Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Fri, 25 Jul 2025 06:07:01 +0100 Subject: [PATCH 01474/11391] thermal: intel: int340x: Remove redundant acpi_has_method() call acpi_evaluate_object() returns an error if the needed method does not exist, so remove an unnecessary acpi_has_method() call preceding it. Signed-off-by: Salah Triki Link: https://patch.msgid.link/aIMQ9RFciI8jmmAh@pc [ rjw: Subject adjustment ] Signed-off-by: Rafael J. Wysocki --- drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c b/drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c index cb149bcdd7d5..ce5d53be108b 100644 --- a/drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c +++ b/drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c @@ -220,9 +220,6 @@ static int acpi_parse_psvt(acpi_handle handle, int *psvt_count, struct psvt **ps int i, result = 0; struct psvt *psvts; - if (!acpi_has_method(handle, "PSVT")) - return -ENODEV; - status = acpi_evaluate_object(handle, "PSVT", NULL, &buffer); if (ACPI_FAILURE(status)) return -ENODEV; From 046c56178a73ad7883fc38e6caa0474025c0fe86 Mon Sep 17 00:00:00 2001 From: Shankari Anand Date: Sat, 16 Aug 2025 17:14:09 +0530 Subject: [PATCH 01475/11391] rust,cred: update AlwaysRefCounted import to sync::aref Update the import of `AlwaysRefCounted` in `cred.rs` 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. Suggested-by: Benno Lossin Link: https://github.com/Rust-for-Linux/linux/issues/1173 Signed-off-by: Shankari Anand Acked-by: Serge Hallyn Reviewed-by: Benno Lossin Reviewed-by: Alice Ryhl [PM: subj tweak] Signed-off-by: Paul Moore --- rust/kernel/cred.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/rust/kernel/cred.rs b/rust/kernel/cred.rs index 2599f01e8b28..4a2229542fb7 100644 --- a/rust/kernel/cred.rs +++ b/rust/kernel/cred.rs @@ -8,11 +8,7 @@ //! //! Reference: -use crate::{ - bindings, - task::Kuid, - types::{AlwaysRefCounted, Opaque}, -}; +use crate::{bindings, sync::aref::AlwaysRefCounted, task::Kuid, types::Opaque}; /// Wraps the kernel's `struct cred`. /// From 71b69f817e91b588030d7d47ddbdc4857a92eb4e Mon Sep 17 00:00:00 2001 From: Kyle Manna Date: Tue, 19 Aug 2025 09:17:39 -0700 Subject: [PATCH 01476/11391] EDAC/ie31200: Add two more Intel Alder Lake-S SoCs for EDAC support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Host Device IDs (DID0) correspond to: * Intel Core i7-12700K * Intel Core i5-12600K See documentation: * 12th Generation Intel® Core™ Processors Datasheet * Volume 1 of 2, Doc. No.: 655258, Rev.: 011 * https://edc.intel.com/output/DownloadPdfDocument?id=8297 (PDF) Signed-off-by: Kyle Manna Signed-off-by: Tony Luck Reviewed-by: Qiuxu Zhuo Link: https://lore.kernel.org/r/20250819161739.3241152-1-kyle@kylemanna.com --- drivers/edac/ie31200_edac.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/edac/ie31200_edac.c b/drivers/edac/ie31200_edac.c index 5c1fa1c0d12e..5a080ab65476 100644 --- a/drivers/edac/ie31200_edac.c +++ b/drivers/edac/ie31200_edac.c @@ -99,6 +99,8 @@ /* Alder Lake-S */ #define PCI_DEVICE_ID_INTEL_IE31200_ADL_S_1 0x4660 +#define PCI_DEVICE_ID_INTEL_IE31200_ADL_S_2 0x4668 /* 8P+4E, e.g. i7-12700K */ +#define PCI_DEVICE_ID_INTEL_IE31200_ADL_S_3 0x4648 /* 6P+4E, e.g. i5-12600K */ /* Bartlett Lake-S */ #define PCI_DEVICE_ID_INTEL_IE31200_BTL_S_1 0x4639 @@ -761,6 +763,8 @@ static const struct pci_device_id ie31200_pci_tbl[] = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_6), (kernel_ulong_t)&rpl_s_cfg}, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_HX_1), (kernel_ulong_t)&rpl_s_cfg}, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_ADL_S_1), (kernel_ulong_t)&rpl_s_cfg}, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_ADL_S_2), (kernel_ulong_t)&rpl_s_cfg}, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_ADL_S_3), (kernel_ulong_t)&rpl_s_cfg}, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_1), (kernel_ulong_t)&rpl_s_cfg}, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_2), (kernel_ulong_t)&rpl_s_cfg}, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_3), (kernel_ulong_t)&rpl_s_cfg}, From 2e6fe1bbefd9c059c3787d1c620fe67343a94dff Mon Sep 17 00:00:00 2001 From: Qiuxu Zhuo Date: Wed, 6 Aug 2025 14:57:07 +0800 Subject: [PATCH 01477/11391] EDAC/i10nm: Skip DIMM enumeration on a disabled memory controller When loading the i10nm_edac driver on some Intel Granite Rapids servers, a call trace may appear as follows: UBSAN: shift-out-of-bounds in drivers/edac/skx_common.c:453:16 shift exponent -66 is negative ... __ubsan_handle_shift_out_of_bounds+0x1e3/0x390 skx_get_dimm_info.cold+0x47/0xd40 [skx_edac_common] i10nm_get_dimm_config+0x23e/0x390 [i10nm_edac] skx_register_mci+0x159/0x220 [skx_edac_common] i10nm_init+0xcb0/0x1ff0 [i10nm_edac] ... This occurs because some BIOS may disable a memory controller if there aren't any memory DIMMs populated on this memory controller. The DIMMMTR register of this disabled memory controller contains the invalid value ~0, resulting in the call trace above. Fix this call trace by skipping DIMM enumeration on a disabled memory controller. Fixes: ba987eaaabf9 ("EDAC/i10nm: Add Intel Granite Rapids server support") Reported-by: Jose Jesus Ambriz Meza Reported-by: Chia-Lin Kao (AceLan) Closes: https://lore.kernel.org/all/20250730063155.2612379-1-acelan.kao@canonical.com/ Signed-off-by: Qiuxu Zhuo Signed-off-by: Tony Luck Tested-by: Chia-Lin Kao (AceLan) Link: https://lore.kernel.org/r/20250806065707.3533345-1-qiuxu.zhuo@intel.com --- drivers/edac/i10nm_base.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c index bf4171ac191d..9d00f247f4e0 100644 --- a/drivers/edac/i10nm_base.c +++ b/drivers/edac/i10nm_base.c @@ -1057,6 +1057,15 @@ static bool i10nm_check_ecc(struct skx_imc *imc, int chan) return !!GET_BITFIELD(mcmtr, 2, 2); } +static bool i10nm_channel_disabled(struct skx_imc *imc, int chan) +{ + u32 mcmtr = I10NM_GET_MCMTR(imc, chan); + + edac_dbg(1, "mc%d ch%d mcmtr reg %x\n", imc->mc, chan, mcmtr); + + return (mcmtr == ~0 || GET_BITFIELD(mcmtr, 18, 18)); +} + static int i10nm_get_dimm_config(struct mem_ctl_info *mci, struct res_config *cfg) { @@ -1070,6 +1079,11 @@ static int i10nm_get_dimm_config(struct mem_ctl_info *mci, if (!imc->mbase) continue; + if (i10nm_channel_disabled(imc, i)) { + edac_dbg(1, "mc%d ch%d is disabled.\n", imc->mc, i); + continue; + } + ndimms = 0; if (res_cfg->type != GNR) From 219af5dfce98fe254335ea79c2bf98428c38370c Mon Sep 17 00:00:00 2001 From: Qiuxu Zhuo Date: Thu, 31 Jul 2025 22:55:28 +0800 Subject: [PATCH 01478/11391] EDAC/{skx_common,skx}: Use configuration data, not global macros Use model-specific configuration data for the number of memory controllers per socket, channels per memory controller, and DIMMs per channel as intended, instead of relying on global macros for maximum values. No functional changes intended. Signed-off-by: Qiuxu Zhuo Signed-off-by: Tony Luck Link: https://lore.kernel.org/r/20250731145534.2759334-2-qiuxu.zhuo@intel.com --- drivers/edac/skx_base.c | 33 ++++++++++++++++++++------------- drivers/edac/skx_common.c | 16 +++++++++------- drivers/edac/skx_common.h | 1 + 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/drivers/edac/skx_base.c b/drivers/edac/skx_base.c index 29897b21fb8e..078ddf95cc6e 100644 --- a/drivers/edac/skx_base.c +++ b/drivers/edac/skx_base.c @@ -33,6 +33,15 @@ static unsigned int nvdimm_count; #define MASK26 0x3FFFFFF /* Mask for 2^26 */ #define MASK29 0x1FFFFFFF /* Mask for 2^29 */ +static struct res_config skx_cfg = { + .type = SKX, + .decs_did = 0x2016, + .busno_cfg_offset = 0xcc, + .ddr_imc_num = 2, + .ddr_chan_num = 3, + .ddr_dimm_num = 2, +}; + static struct skx_dev *get_skx_dev(struct pci_bus *bus, u8 idx) { struct skx_dev *d; @@ -52,7 +61,7 @@ enum munittype { struct munit { u16 did; - u16 devfn[SKX_NUM_IMC]; + u16 devfn[2]; u8 busidx; u8 per_socket; enum munittype mtype; @@ -89,11 +98,11 @@ static int get_all_munits(const struct munit *m) if (!pdev) break; ndev++; - if (m->per_socket == SKX_NUM_IMC) { - for (i = 0; i < SKX_NUM_IMC; i++) + if (m->per_socket == skx_cfg.ddr_imc_num) { + for (i = 0; i < skx_cfg.ddr_imc_num; i++) if (m->devfn[i] == pdev->devfn) break; - if (i == SKX_NUM_IMC) + if (i == skx_cfg.ddr_imc_num) goto fail; } d = get_skx_dev(pdev->bus, m->busidx); @@ -157,12 +166,6 @@ static int get_all_munits(const struct munit *m) return -ENODEV; } -static struct res_config skx_cfg = { - .type = SKX, - .decs_did = 0x2016, - .busno_cfg_offset = 0xcc, -}; - static const struct x86_cpu_id skx_cpuids[] = { X86_MATCH_VFM(INTEL_SKYLAKE_X, &skx_cfg), { } @@ -186,11 +189,11 @@ static int skx_get_dimm_config(struct mem_ctl_info *mci, struct res_config *cfg) /* Only the mcmtr on the first channel is effective */ pci_read_config_dword(imc->chan[0].cdev, 0x87c, &mcmtr); - for (i = 0; i < SKX_NUM_CHANNELS; i++) { + for (i = 0; i < cfg->ddr_chan_num; i++) { ndimms = 0; pci_read_config_dword(imc->chan[i].cdev, 0x8C, &amap); pci_read_config_dword(imc->chan[i].cdev, 0x400, &mcddrtcfg); - for (j = 0; j < SKX_NUM_DIMMS; j++) { + for (j = 0; j < cfg->ddr_dimm_num; j++) { dimm = edac_get_dimm(mci, i, j, 0); pci_read_config_dword(imc->chan[i].cdev, 0x80 + 4 * j, &mtr); @@ -620,6 +623,7 @@ static int __init skx_init(void) return -ENODEV; cfg = (struct res_config *)id->driver_data; + skx_set_res_cfg(cfg); rc = skx_get_hi_lo(0x2034, off, &skx_tolm, &skx_tohm); if (rc) @@ -652,10 +656,13 @@ static int __init skx_init(void) goto fail; edac_dbg(2, "src_id = %d\n", src_id); - for (i = 0; i < SKX_NUM_IMC; i++) { + for (i = 0; i < cfg->ddr_imc_num; i++) { d->imc[i].mc = mc++; d->imc[i].lmc = i; d->imc[i].src_id = src_id; + d->imc[i].num_channels = cfg->ddr_chan_num; + d->imc[i].num_dimms = cfg->ddr_dimm_num; + rc = skx_register_mci(&d->imc[i], d->imc[i].chan[0].cdev, "Skylake Socket", EDAC_MOD_STR, skx_get_dimm_config, cfg); diff --git a/drivers/edac/skx_common.c b/drivers/edac/skx_common.c index 39c733dbc5b9..cc7d36cf7f3b 100644 --- a/drivers/edac/skx_common.c +++ b/drivers/edac/skx_common.c @@ -320,10 +320,10 @@ static int get_width(u32 mtr) */ int skx_get_all_bus_mappings(struct res_config *cfg, struct list_head **list) { + int ndev = 0, imc_num = cfg->ddr_imc_num + cfg->hbm_imc_num; struct pci_dev *pdev, *prev; struct skx_dev *d; u32 reg; - int ndev = 0; prev = NULL; for (;;) { @@ -354,8 +354,10 @@ int skx_get_all_bus_mappings(struct res_config *cfg, struct list_head **list) d->seg = GET_BITFIELD(reg, 16, 23); } - edac_dbg(2, "busses: 0x%x, 0x%x, 0x%x, 0x%x\n", - d->bus[0], d->bus[1], d->bus[2], d->bus[3]); + d->num_imc = imc_num; + + edac_dbg(2, "busses: 0x%x, 0x%x, 0x%x, 0x%x, imcs %d\n", + d->bus[0], d->bus[1], d->bus[2], d->bus[3], imc_num); list_add_tail(&d->list, &dev_edac_list); prev = pdev; @@ -541,10 +543,10 @@ int skx_register_mci(struct skx_imc *imc, struct pci_dev *pdev, /* Allocate a new MC control structure */ layers[0].type = EDAC_MC_LAYER_CHANNEL; - layers[0].size = NUM_CHANNELS; + layers[0].size = imc->num_channels; layers[0].is_virt_csrow = false; layers[1].type = EDAC_MC_LAYER_SLOT; - layers[1].size = NUM_DIMMS; + layers[1].size = imc->num_dimms; layers[1].is_virt_csrow = true; mci = edac_mc_alloc(imc->mc, ARRAY_SIZE(layers), layers, sizeof(struct skx_pvt)); @@ -784,7 +786,7 @@ void skx_remove(void) list_for_each_entry_safe(d, tmp, &dev_edac_list, list) { list_del(&d->list); - for (i = 0; i < NUM_IMC; i++) { + for (i = 0; i < d->num_imc; i++) { if (d->imc[i].mci) skx_unregister_mci(&d->imc[i]); @@ -794,7 +796,7 @@ void skx_remove(void) if (d->imc[i].mbase) iounmap(d->imc[i].mbase); - for (j = 0; j < NUM_CHANNELS; j++) { + for (j = 0; j < d->imc[i].num_channels; j++) { if (d->imc[i].chan[j].cdev) pci_dev_put(d->imc[i].chan[j].cdev); } diff --git a/drivers/edac/skx_common.h b/drivers/edac/skx_common.h index ec4966f7ea40..3f6007a97267 100644 --- a/drivers/edac/skx_common.h +++ b/drivers/edac/skx_common.h @@ -134,6 +134,7 @@ struct skx_dev { struct pci_dev *uracu; /* for i10nm CPU */ struct pci_dev *pcu_cr3; /* for HBM memory detection */ u32 mcroute; + int num_imc; /* * Some server BIOS may hide certain memory controllers, and the * EDAC driver skips those hidden memory controllers. However, the From 59cfc06a874e01633865d0b05eba47b09b8b3a8f Mon Sep 17 00:00:00 2001 From: Qiuxu Zhuo Date: Thu, 31 Jul 2025 22:55:29 +0800 Subject: [PATCH 01479/11391] EDAC/skx_common: Move mc_mapping to be a field inside struct skx_imc The mc_mapping and imc fields of struct skx_dev have the same size, NUM_IMC. Move mc_mapping to be a field inside struct skx_imc to prepare for making the imc array of memory controller instances a flexible array. No functional changes intended. Suggested-by: Tony Luck Signed-off-by: Qiuxu Zhuo Signed-off-by: Tony Luck Link: https://lore.kernel.org/r/20250731145534.2759334-3-qiuxu.zhuo@intel.com --- drivers/edac/skx_common.c | 8 ++++---- drivers/edac/skx_common.h | 20 ++++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/edac/skx_common.c b/drivers/edac/skx_common.c index cc7d36cf7f3b..3f6a074d685c 100644 --- a/drivers/edac/skx_common.c +++ b/drivers/edac/skx_common.c @@ -131,7 +131,7 @@ static void skx_init_mc_mapping(struct skx_dev *d) * EDAC driver. */ for (int i = 0; i < NUM_IMC; i++) - d->mc_mapping[i] = i; + d->imc[i].mc_mapping = i; } void skx_set_mc_mapping(struct skx_dev *d, u8 pmc, u8 lmc) @@ -139,16 +139,16 @@ void skx_set_mc_mapping(struct skx_dev *d, u8 pmc, u8 lmc) edac_dbg(0, "Set the mapping of mc phy idx to logical idx: %02d -> %02d\n", pmc, lmc); - d->mc_mapping[pmc] = lmc; + d->imc[pmc].mc_mapping = lmc; } EXPORT_SYMBOL_GPL(skx_set_mc_mapping); static u8 skx_get_mc_mapping(struct skx_dev *d, u8 pmc) { edac_dbg(0, "Get the mapping of mc phy idx to logical idx: %02d -> %02d\n", - pmc, d->mc_mapping[pmc]); + pmc, d->imc[pmc].mc_mapping); - return d->mc_mapping[pmc]; + return d->imc[pmc].mc_mapping; } static bool skx_adxl_decode(struct decoded_addr *res, enum error_source err_src) diff --git a/drivers/edac/skx_common.h b/drivers/edac/skx_common.h index 3f6007a97267..95d61d23f89e 100644 --- a/drivers/edac/skx_common.h +++ b/drivers/edac/skx_common.h @@ -135,16 +135,6 @@ struct skx_dev { struct pci_dev *pcu_cr3; /* for HBM memory detection */ u32 mcroute; int num_imc; - /* - * Some server BIOS may hide certain memory controllers, and the - * EDAC driver skips those hidden memory controllers. However, the - * ADXL still decodes memory error address using physical memory - * controller indices. The mapping table is used to convert the - * physical indices (reported by ADXL) to the logical indices - * (used the EDAC driver) of present memory controllers during the - * error handling process. - */ - u8 mc_mapping[NUM_IMC]; struct skx_imc { struct mem_ctl_info *mci; struct pci_dev *mdev; /* for i10nm CPU */ @@ -156,6 +146,16 @@ struct skx_dev { u8 mc; /* system wide mc# */ u8 lmc; /* socket relative mc# */ u8 src_id; + /* + * Some server BIOS may hide certain memory controllers, and the + * EDAC driver skips those hidden memory controllers. However, the + * ADXL still decodes memory error address using physical memory + * controller indices. The mapping table is used to convert the + * physical indices (reported by ADXL) to the logical indices + * (used the EDAC driver) of present memory controllers during the + * error handling process. + */ + u8 mc_mapping; struct skx_channel { struct pci_dev *cdev; struct pci_dev *edev; From 30b47b71fdc0091db5a4fa9503ad630aeb0ab3eb Mon Sep 17 00:00:00 2001 From: Qiuxu Zhuo Date: Thu, 31 Jul 2025 22:55:30 +0800 Subject: [PATCH 01480/11391] EDAC/skx_common: Swap memory controller index mapping The current mapping of memory controller indices is from physical index [1] to logical index [2], as show below: skx_dev->imc[pmc].mc_mapping = lmc Since skx_dev->imc[] is an array of present memory controller instances, mapping memory controller indices from logical index to physical index, as show below, is more reasonable. This is also a preparatory step for making skx_dev->imc[] a flexible array. skx_dev->imc[lmc].mc_mapping = pmc Both mappings are equivalent. No functional changes intended. [1] Indices for memory controllers include both those present to the OS and those disabled by BIOS. [2] Indices for memory controllers present to the OS. Signed-off-by: Qiuxu Zhuo Signed-off-by: Tony Luck Link: https://lore.kernel.org/r/20250731145534.2759334-4-qiuxu.zhuo@intel.com --- drivers/edac/skx_common.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/drivers/edac/skx_common.c b/drivers/edac/skx_common.c index 3f6a074d685c..e03268e9073f 100644 --- a/drivers/edac/skx_common.c +++ b/drivers/edac/skx_common.c @@ -130,7 +130,7 @@ static void skx_init_mc_mapping(struct skx_dev *d) * the logical indices of the memory controllers enumerated by the * EDAC driver. */ - for (int i = 0; i < NUM_IMC; i++) + for (int i = 0; i < d->num_imc; i++) d->imc[i].mc_mapping = i; } @@ -139,22 +139,28 @@ void skx_set_mc_mapping(struct skx_dev *d, u8 pmc, u8 lmc) edac_dbg(0, "Set the mapping of mc phy idx to logical idx: %02d -> %02d\n", pmc, lmc); - d->imc[pmc].mc_mapping = lmc; + d->imc[lmc].mc_mapping = pmc; } EXPORT_SYMBOL_GPL(skx_set_mc_mapping); -static u8 skx_get_mc_mapping(struct skx_dev *d, u8 pmc) +static int skx_get_mc_mapping(struct skx_dev *d, u8 pmc) { - edac_dbg(0, "Get the mapping of mc phy idx to logical idx: %02d -> %02d\n", - pmc, d->imc[pmc].mc_mapping); + for (int lmc = 0; lmc < d->num_imc; lmc++) { + if (d->imc[lmc].mc_mapping == pmc) { + edac_dbg(0, "Get the mapping of mc phy idx to logical idx: %02d -> %02d\n", + pmc, lmc); - return d->imc[pmc].mc_mapping; + return lmc; + } + } + + return -1; } static bool skx_adxl_decode(struct decoded_addr *res, enum error_source err_src) { + int i, lmc, len = 0; struct skx_dev *d; - int i, len = 0; if (res->addr >= skx_tohm || (res->addr >= skx_tolm && res->addr < BIT_ULL(32))) { @@ -218,7 +224,13 @@ static bool skx_adxl_decode(struct decoded_addr *res, enum error_source err_src) return false; } - res->imc = skx_get_mc_mapping(d, res->imc); + lmc = skx_get_mc_mapping(d, res->imc); + if (lmc < 0) { + skx_printk(KERN_ERR, "No lmc for imc %d\n", res->imc); + return false; + } + + res->imc = lmc; for (i = 0; i < adxl_component_count; i++) { if (adxl_values[i] == ~0x0ull) From 43060ca5332462903f57c2ff9b49b69124618070 Mon Sep 17 00:00:00 2001 From: Qiuxu Zhuo Date: Thu, 31 Jul 2025 22:55:31 +0800 Subject: [PATCH 01481/11391] EDAC/skx_common: Make skx_dev->imc[] a flexible array The current skx->imc[NUM_IMC] array of memory controller instances is sized using the macro NUM_IMC. Each time EDAC support is added for a new CPU, NUM_IMC needs to be updated to ensure it is greater than or equal to the number of memory controllers for the new CPU. This approach is inconvenient and results in memory waste for older CPUs with fewer memory controllers. To address this, make skx->imc[] a flexible array and determine its size from configuration data or at runtime. Suggested-by: Tony Luck Signed-off-by: Qiuxu Zhuo Signed-off-by: Tony Luck Link: https://lore.kernel.org/r/20250731145534.2759334-5-qiuxu.zhuo@intel.com --- drivers/edac/skx_common.c | 3 ++- drivers/edac/skx_common.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/edac/skx_common.c b/drivers/edac/skx_common.c index e03268e9073f..09187043c045 100644 --- a/drivers/edac/skx_common.c +++ b/drivers/edac/skx_common.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -343,7 +344,7 @@ int skx_get_all_bus_mappings(struct res_config *cfg, struct list_head **list) if (!pdev) break; ndev++; - d = kzalloc(sizeof(*d), GFP_KERNEL); + d = kzalloc(struct_size(d, imc, imc_num), GFP_KERNEL); if (!d) { pci_dev_put(pdev); return -ENOMEM; diff --git a/drivers/edac/skx_common.h b/drivers/edac/skx_common.h index 95d61d23f89e..e7038fd45d06 100644 --- a/drivers/edac/skx_common.h +++ b/drivers/edac/skx_common.h @@ -172,7 +172,7 @@ struct skx_dev { u8 colbits; } dimms[NUM_DIMMS]; } chan[NUM_CHANNELS]; - } imc[NUM_IMC]; + } imc[]; }; struct skx_pvt { From 91ded20fa2fefe2620b0abb998838312ea8bbfd2 Mon Sep 17 00:00:00 2001 From: Qiuxu Zhuo Date: Thu, 31 Jul 2025 22:55:32 +0800 Subject: [PATCH 01482/11391] EDAC/skx_common: Remove redundant upper bound check for res->imc The following upper bound check for the memory controller physical index decoded by ADXL is the only place where use the macro 'NUM_IMC' is used: res->imc > NUM_IMC - 1 Since this check is already covered by skx_get_mc_mapping(), meaning no memory controller logical index exists for an invalid memory controller physical index decoded by ADXL, remove the redundant upper bound check so that the definition for 'NUM_IMC' can be cleaned up (in another patch). Signed-off-by: Qiuxu Zhuo Signed-off-by: Tony Luck Link: https://lore.kernel.org/r/20250731145534.2759334-6-qiuxu.zhuo@intel.com --- drivers/edac/skx_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/edac/skx_common.c b/drivers/edac/skx_common.c index 09187043c045..5899a1110495 100644 --- a/drivers/edac/skx_common.c +++ b/drivers/edac/skx_common.c @@ -207,7 +207,7 @@ static bool skx_adxl_decode(struct decoded_addr *res, enum error_source err_src) res->cs = (int)adxl_values[component_indices[INDEX_CS]]; } - if (res->imc > NUM_IMC - 1 || res->imc < 0) { + if (res->imc < 0) { skx_printk(KERN_ERR, "Bad imc %d\n", res->imc); return false; } From f7a29a37373baa0bd0823a5d55e97dc7f75a4dab Mon Sep 17 00:00:00 2001 From: Qiuxu Zhuo Date: Thu, 31 Jul 2025 22:55:33 +0800 Subject: [PATCH 01483/11391] EDAC/i10nm: Reallocate skx_dev list if preconfigured cnt != runtime cnt Ideally, read the present DDR memory controller count first and then allocate the skx_dev list using this count. However, this approach requires adding a significant amount of code similar to skx_get_all_bus_mappings() to obtain the PCI bus mappings for the first socket and use these mappings along with the related PCI register offset to read the memory controller count. Given that the Granite Rapids CPU is the only one that can detect the count of memory controllers at runtime (other CPUs use the count in the configuration data), to reduce code complexity, reallocate the skx_dev list only if the preconfigured count of DDR memory controllers differs from the count read at runtime for Granite Rapids CPU. Signed-off-by: Qiuxu Zhuo Signed-off-by: Tony Luck Link: https://lore.kernel.org/r/20250731145534.2759334-7-qiuxu.zhuo@intel.com --- drivers/edac/i10nm_base.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c index 9d00f247f4e0..2010a47149f4 100644 --- a/drivers/edac/i10nm_base.c +++ b/drivers/edac/i10nm_base.c @@ -468,17 +468,18 @@ static int i10nm_get_imc_num(struct res_config *cfg) return -ENODEV; } - if (imc_num > I10NM_NUM_DDR_IMC) { - i10nm_printk(KERN_ERR, "Need to make I10NM_NUM_DDR_IMC >= %d\n", imc_num); - return -EINVAL; - } - if (cfg->ddr_imc_num != imc_num) { /* - * Store the number of present DDR memory controllers. + * Update the configuration data to reflect the number of + * present DDR memory controllers. */ cfg->ddr_imc_num = imc_num; edac_dbg(2, "Set DDR MC number: %d", imc_num); + + /* Release and reallocate skx_dev list with the updated number. */ + skx_remove(); + if (skx_get_all_bus_mappings(cfg, &i10nm_edac_list) <= 0) + return -ENODEV; } return 0; From a95dcf3d67430493554a9fe3a3a8717c21554508 Mon Sep 17 00:00:00 2001 From: Qiuxu Zhuo Date: Thu, 31 Jul 2025 22:55:34 +0800 Subject: [PATCH 01484/11391] EDAC/skx_common: Remove unused *NUM*_IMC macros There are no references to the *NUM*_IMC macros, so remove them. Signed-off-by: Qiuxu Zhuo Signed-off-by: Tony Luck Link: https://lore.kernel.org/r/20250731145534.2759334-8-qiuxu.zhuo@intel.com --- drivers/edac/skx_common.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/edac/skx_common.h b/drivers/edac/skx_common.h index e7038fd45d06..73ba89786cdf 100644 --- a/drivers/edac/skx_common.h +++ b/drivers/edac/skx_common.h @@ -29,23 +29,18 @@ #define GET_BITFIELD(v, lo, hi) \ (((v) & GENMASK_ULL((hi), (lo))) >> (lo)) -#define SKX_NUM_IMC 2 /* Memory controllers per socket */ #define SKX_NUM_CHANNELS 3 /* Channels per memory controller */ #define SKX_NUM_DIMMS 2 /* Max DIMMS per channel */ -#define I10NM_NUM_DDR_IMC 12 #define I10NM_NUM_DDR_CHANNELS 2 #define I10NM_NUM_DDR_DIMMS 2 -#define I10NM_NUM_HBM_IMC 16 #define I10NM_NUM_HBM_CHANNELS 2 #define I10NM_NUM_HBM_DIMMS 1 -#define I10NM_NUM_IMC (I10NM_NUM_DDR_IMC + I10NM_NUM_HBM_IMC) #define I10NM_NUM_CHANNELS MAX(I10NM_NUM_DDR_CHANNELS, I10NM_NUM_HBM_CHANNELS) #define I10NM_NUM_DIMMS MAX(I10NM_NUM_DDR_DIMMS, I10NM_NUM_HBM_DIMMS) -#define NUM_IMC MAX(SKX_NUM_IMC, I10NM_NUM_IMC) #define NUM_CHANNELS MAX(SKX_NUM_CHANNELS, I10NM_NUM_CHANNELS) #define NUM_DIMMS MAX(SKX_NUM_DIMMS, I10NM_NUM_DIMMS) From eddc821f98afaa13ecd09b02b73ac5946387ffcc Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 15 Aug 2025 15:41:00 -0700 Subject: [PATCH 01485/11391] selftests: drv-net: tso: increase the retransmit threshold We see quite a few flakes during the TSO test against virtualized devices in NIPA. There's often 10-30 retransmissions during the test. Sometimes as many as 100. Set the retransmission threshold at 1/4th of the wire frame target. Link: https://patch.msgid.link/20250815224100.363438-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/drivers/net/hw/tso.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/drivers/net/hw/tso.py b/tools/testing/selftests/drivers/net/hw/tso.py index c13dd5efa27a..0998e68ebaf0 100755 --- a/tools/testing/selftests/drivers/net/hw/tso.py +++ b/tools/testing/selftests/drivers/net/hw/tso.py @@ -60,16 +60,17 @@ def run_one_stream(cfg, ipver, remote_v4, remote_v6, should_lso): sock_wait_drain(sock) qstat_new = cfg.netnl.qstats_get({"ifindex": cfg.ifindex}, dump=True)[0] - # No math behind the 10 here, but try to catch cases where - # TCP falls back to non-LSO. - ksft_lt(tcp_sock_get_retrans(sock), 10) - sock.close() - # Check that at least 90% of the data was sent as LSO packets. # System noise may cause false negatives. Also header overheads # will add up to 5% of extra packes... The check is best effort. total_lso_wire = len(buf) * 0.90 // cfg.dev["mtu"] total_lso_super = len(buf) * 0.90 // cfg.dev["tso_max_size"] + + # Make sure we have order of magnitude more LSO packets than + # retransmits, in case TCP retransmitted all the LSO packets. + ksft_lt(tcp_sock_get_retrans(sock), total_lso_wire / 4) + sock.close() + if should_lso: if cfg.have_stat_super_count: ksft_ge(qstat_new['tx-hw-gso-packets'] - From 51992f99f068fba966a680a9ac118b815f2fe08e Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 15 Aug 2025 16:15:13 -0700 Subject: [PATCH 01486/11391] selftests: drv-net: ncdevmem: make configure_channels() support combined channels ncdevmem tests that the kernel correctly rejects attempts to deactivate queues with MPs bound. Make the configure_channels() test support combined channels. Currently it tries to set the queue counts to rx N tx N-1, which only makes sense for devices which have IRQs per ring type. Most modern devices used combined IRQs/channels with both Rx and Tx queues. Since the math is total Rx == combined+Rx setting Rx when combined is non-zero will be increasing the total queue count, not decreasing as the test intends. Note that the test would previously also try to set the Tx ring count to Rx - 1, for some reason. Which would be 0 if the device has only 2 queues configured. With this change (device with 2 queues): setting channel count rx:1 tx:1 YNL set channels: Kernel error: 'requested channel counts are too low for existing memory provider setting (2)' Reviewed-by: Mina Almasry Link: https://patch.msgid.link/20250815231513.381652-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- .../selftests/drivers/net/hw/ncdevmem.c | 78 ++++++++++++++++++- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/drivers/net/hw/ncdevmem.c b/tools/testing/selftests/drivers/net/hw/ncdevmem.c index be937542b4c0..71961a7688e6 100644 --- a/tools/testing/selftests/drivers/net/hw/ncdevmem.c +++ b/tools/testing/selftests/drivers/net/hw/ncdevmem.c @@ -356,7 +356,81 @@ static int configure_rss(void) static int configure_channels(unsigned int rx, unsigned int tx) { - return run_command("ethtool -L %s rx %u tx %u", ifname, rx, tx); + struct ethtool_channels_get_req *gchan; + struct ethtool_channels_set_req *schan; + struct ethtool_channels_get_rsp *chan; + struct ynl_error yerr; + struct ynl_sock *ys; + int ret; + + fprintf(stderr, "setting channel count rx:%u tx:%u\n", rx, tx); + + ys = ynl_sock_create(&ynl_ethtool_family, &yerr); + if (!ys) { + fprintf(stderr, "YNL: %s\n", yerr.msg); + return -1; + } + + gchan = ethtool_channels_get_req_alloc(); + if (!gchan) { + ret = -1; + goto exit_close_sock; + } + + ethtool_channels_get_req_set_header_dev_index(gchan, ifindex); + chan = ethtool_channels_get(ys, gchan); + ethtool_channels_get_req_free(gchan); + if (!chan) { + fprintf(stderr, "YNL get channels: %s\n", ys->err.msg); + ret = -1; + goto exit_close_sock; + } + + schan = ethtool_channels_set_req_alloc(); + if (!schan) { + ret = -1; + goto exit_free_chan; + } + + ethtool_channels_set_req_set_header_dev_index(schan, ifindex); + + if (chan->_present.combined_count) { + if (chan->_present.rx_count || chan->_present.tx_count) { + ethtool_channels_set_req_set_rx_count(schan, 0); + ethtool_channels_set_req_set_tx_count(schan, 0); + } + + if (rx == tx) { + ethtool_channels_set_req_set_combined_count(schan, rx); + } else if (rx > tx) { + ethtool_channels_set_req_set_combined_count(schan, tx); + ethtool_channels_set_req_set_rx_count(schan, rx - tx); + } else { + ethtool_channels_set_req_set_combined_count(schan, rx); + ethtool_channels_set_req_set_tx_count(schan, tx - rx); + } + + ret = ethtool_channels_set(ys, schan); + if (ret) + fprintf(stderr, "YNL set channels: %s\n", ys->err.msg); + } else if (chan->_present.rx_count) { + ethtool_channels_set_req_set_rx_count(schan, rx); + ethtool_channels_set_req_set_tx_count(schan, tx); + + ret = ethtool_channels_set(ys, schan); + if (ret) + fprintf(stderr, "YNL set channels: %s\n", ys->err.msg); + } else { + fprintf(stderr, "Error: device has neither combined nor rx channels\n"); + ret = -1; + } + ethtool_channels_set_req_free(schan); +exit_free_chan: + ethtool_channels_get_rsp_free(chan); +exit_close_sock: + ynl_sock_destroy(ys); + + return ret; } static int configure_flow_steering(struct sockaddr_in6 *server_sin) @@ -752,7 +826,7 @@ void run_devmem_tests(void) error(1, 0, "Failed to bind\n"); /* Deactivating a bound queue should not be legal */ - if (!configure_channels(num_queues, num_queues - 1)) + if (!configure_channels(num_queues, num_queues)) error(1, 0, "Deactivating a bound queue should be illegal.\n"); /* Closing the netlink socket does an implicit unbind */ From 5236f57e7c033d869fe8f2080a977ea47882b26f Mon Sep 17 00:00:00 2001 From: Christoph Paasch Date: Sat, 16 Aug 2025 16:12:48 -0700 Subject: [PATCH 01487/11391] net: Make nexthop-dumps scale linearly with the number of nexthops When we have a (very) large number of nexthops, they do not fit within a single message. rtm_dump_walk_nexthops() thus will be called repeatedly and ctx->idx is used to avoid dumping the same nexthops again. The approach in which we avoid dumping the same nexthops is by basically walking the entire nexthop rb-tree from the left-most node until we find a node whose id is >= s_idx. That does not scale well. Instead of this inefficient approach, rather go directly through the tree to the nexthop that should be dumped (the one whose nh_id >= s_idx). This allows us to find the relevant node in O(log(n)). We have quite a nice improvement with this: Before: ======= --> ~1M nexthops: $ time ~/libnl/src/nl-nh-list | wc -l 1050624 real 0m21.080s user 0m0.666s sys 0m20.384s --> ~2M nexthops: $ time ~/libnl/src/nl-nh-list | wc -l 2101248 real 1m51.649s user 0m1.540s sys 1m49.908s After: ====== --> ~1M nexthops: $ time ~/libnl/src/nl-nh-list | wc -l 1050624 real 0m1.157s user 0m0.926s sys 0m0.259s --> ~2M nexthops: $ time ~/libnl/src/nl-nh-list | wc -l 2101248 real 0m2.763s user 0m2.042s sys 0m0.776s Signed-off-by: Christoph Paasch Reviewed-by: Ido Schimmel Reviewed-by: Nikolay Aleksandrov Reviewed-by: Eric Dumazet Reviewed-by: David Ahern Link: https://patch.msgid.link/20250816-nexthop_dump-v2-1-491da3462118@openai.com Signed-off-by: Jakub Kicinski --- net/ipv4/nexthop.c | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c index 29118c43ebf5..509004bfd08e 100644 --- a/net/ipv4/nexthop.c +++ b/net/ipv4/nexthop.c @@ -3511,12 +3511,42 @@ static int rtm_dump_walk_nexthops(struct sk_buff *skb, int err; s_idx = ctx->idx; - for (node = rb_first(root); node; node = rb_next(node)) { + + /* If this is not the first invocation, ctx->idx will contain the id of + * the last nexthop we processed. Instead of starting from the very + * first element of the red/black tree again and linearly skipping the + * (potentially large) set of nodes with an id smaller than s_idx, walk + * the tree and find the left-most node whose id is >= s_idx. This + * provides an efficient O(log n) starting point for the dump + * continuation. + */ + if (s_idx != 0) { + struct rb_node *tmp = root->rb_node; + + node = NULL; + while (tmp) { + struct nexthop *nh; + + nh = rb_entry(tmp, struct nexthop, rb_node); + if (nh->id < s_idx) { + tmp = tmp->rb_right; + } else { + /* Track current candidate and keep looking on + * the left side to find the left-most + * (smallest id) that is still >= s_idx. + */ + node = tmp; + tmp = tmp->rb_left; + } + } + } else { + node = rb_first(root); + } + + for (; node; node = rb_next(node)) { struct nexthop *nh; nh = rb_entry(node, struct nexthop, rb_node); - if (nh->id < s_idx) - continue; ctx->idx = nh->id; err = nh_cb(skb, cb, nh, data); From b0ac6d3b56a2384db151696cfda2836a8a961b6d Mon Sep 17 00:00:00 2001 From: Christoph Paasch Date: Sat, 16 Aug 2025 16:12:49 -0700 Subject: [PATCH 01488/11391] net: When removing nexthops, don't call synchronize_net if it is not necessary When removing a nexthop, commit 90f33bffa382 ("nexthops: don't modify published nexthop groups") added a call to synchronize_rcu() (later changed to _net()) to make sure everyone sees the new nexthop-group before the rtnl-lock is released. When one wants to delete a large number of groups and nexthops, it is fastest to first flush the groups (ip nexthop flush groups) and then flush the nexthops themselves (ip -6 nexthop flush). As that way the groups don't need to be rebalanced. However, `ip -6 nexthop flush` will still take a long time if there is a very large number of nexthops because of the call to synchronize_net(). Now, if there are no more groups, there is no point in calling synchronize_net(). So, let's skip that entirely by checking if nh->grp_list is empty. This gives us a nice speedup: BEFORE: ======= $ time sudo ip -6 nexthop flush Dump was interrupted and may be inconsistent. Flushed 2097152 nexthops real 1m45.345s user 0m0.001s sys 0m0.005s $ time sudo ip -6 nexthop flush Dump was interrupted and may be inconsistent. Flushed 4194304 nexthops real 3m10.430s user 0m0.002s sys 0m0.004s AFTER: ====== $ time sudo ip -6 nexthop flush Dump was interrupted and may be inconsistent. Flushed 2097152 nexthops real 0m17.545s user 0m0.003s sys 0m0.003s $ time sudo ip -6 nexthop flush Dump was interrupted and may be inconsistent. Flushed 4194304 nexthops real 0m35.823s user 0m0.002s sys 0m0.004s Signed-off-by: Christoph Paasch Reviewed-by: Ido Schimmel Reviewed-by: Nikolay Aleksandrov Reviewed-by: Eric Dumazet Reviewed-by: David Ahern Link: https://patch.msgid.link/20250816-nexthop_dump-v2-2-491da3462118@openai.com Signed-off-by: Jakub Kicinski --- net/ipv4/nexthop.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c index 509004bfd08e..0a20625f5ffb 100644 --- a/net/ipv4/nexthop.c +++ b/net/ipv4/nexthop.c @@ -2087,6 +2087,12 @@ static void remove_nexthop_from_groups(struct net *net, struct nexthop *nh, { struct nh_grp_entry *nhge, *tmp; + /* If there is nothing to do, let's avoid the costly call to + * synchronize_net() + */ + if (list_empty(&nh->grp_list)) + return; + list_for_each_entry_safe(nhge, tmp, &nh->grp_list, nh_list) remove_nh_grp_entry(net, nhge, nlinfo); From c3f0c02997c7f8489fec259e28e0e04e9811edac Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 18 Aug 2025 08:40:26 -0700 Subject: [PATCH 01489/11391] net: Add skb_dstref_steal and skb_dstref_restore Going forward skb_dst_set will assert that skb dst_entry is empty during skb_dst_set to prevent potential leaks. There are few places that still manually manage dst_entry not using the helpers. Convert them to the following new helpers: - skb_dstref_steal that resets dst_entry and returns previous dst_entry value - skb_dstref_restore that restores dst_entry previously reset via skb_dstref_steal Signed-off-by: Stanislav Fomichev Link: https://patch.msgid.link/20250818154032.3173645-2-sdf@fomichev.me Signed-off-by: Jakub Kicinski --- include/linux/skbuff.h | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 14b923ddb6df..7538ca507ee9 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1159,6 +1159,38 @@ static inline struct dst_entry *skb_dst(const struct sk_buff *skb) return (struct dst_entry *)(skb->_skb_refdst & SKB_DST_PTRMASK); } +/** + * skb_dstref_steal() - return current dst_entry value and clear it + * @skb: buffer + * + * Resets skb dst_entry without adjusting its reference count. Useful in + * cases where dst_entry needs to be temporarily reset and restored. + * Note that the returned value cannot be used directly because it + * might contain SKB_DST_NOREF bit. + * + * When in doubt, prefer skb_dst_drop() over skb_dstref_steal() to correctly + * handle dst_entry reference counting. + * + * Returns: original skb dst_entry. + */ +static inline unsigned long skb_dstref_steal(struct sk_buff *skb) +{ + unsigned long refdst = skb->_skb_refdst; + + skb->_skb_refdst = 0; + return refdst; +} + +/** + * skb_dstref_restore() - restore skb dst_entry removed via skb_dstref_steal() + * @skb: buffer + * @refdst: dst entry from a call to skb_dstref_steal() + */ +static inline void skb_dstref_restore(struct sk_buff *skb, unsigned long refdst) +{ + skb->_skb_refdst = refdst; +} + /** * skb_dst_set - sets skb dst * @skb: buffer From c829aab21ed55d9e38346604259aa3ff88d17274 Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 18 Aug 2025 08:40:27 -0700 Subject: [PATCH 01490/11391] xfrm: Switch to skb_dstref_steal to clear dst_entry Going forward skb_dst_set will assert that skb dst_entry is empty during skb_dst_set. skb_dstref_steal is added to reset existing entry without doing refcnt. Switch to skb_dstref_steal in __xfrm_route_forward and add a comment on why it's safe to skip skb_dstref_restore. Signed-off-by: Stanislav Fomichev Link: https://patch.msgid.link/20250818154032.3173645-3-sdf@fomichev.me Signed-off-by: Jakub Kicinski --- net/xfrm/xfrm_policy.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index c5035a9bc3bb..7111184eef59 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -3881,12 +3881,18 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family) } skb_dst_force(skb); - if (!skb_dst(skb)) { + dst = skb_dst(skb); + if (!dst) { XFRM_INC_STATS(net, LINUX_MIB_XFRMFWDHDRERROR); return 0; } - dst = xfrm_lookup(net, skb_dst(skb), &fl, NULL, XFRM_LOOKUP_QUEUE); + /* ignore return value from skb_dstref_steal, xfrm_lookup takes + * care of dropping the refcnt if needed. + */ + skb_dstref_steal(skb); + + dst = xfrm_lookup(net, dst, &fl, NULL, XFRM_LOOKUP_QUEUE); if (IS_ERR(dst)) { res = 0; dst = NULL; From 15488d4d8dc10a575f32cc692b6c9aa99f66bc7b Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 18 Aug 2025 08:40:28 -0700 Subject: [PATCH 01491/11391] netfilter: Switch to skb_dstref_steal to clear dst_entry Going forward skb_dst_set will assert that skb dst_entry is empty during skb_dst_set. skb_dstref_steal is added to reset existing entry without doing refcnt. Switch to skb_dstref_steal in ip[6]_route_me_harder and add a comment on why it's safe to skip skb_dstref_restore. Acked-by: Florian Westphal Signed-off-by: Stanislav Fomichev Link: https://patch.msgid.link/20250818154032.3173645-4-sdf@fomichev.me Signed-off-by: Jakub Kicinski --- net/ipv4/netfilter.c | 5 ++++- net/ipv6/netfilter.c | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index 0565f001120d..e60e54e7945d 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c @@ -65,7 +65,10 @@ int ip_route_me_harder(struct net *net, struct sock *sk, struct sk_buff *skb, un if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) && xfrm_decode_session(net, skb, flowi4_to_flowi(&fl4), AF_INET) == 0) { struct dst_entry *dst = skb_dst(skb); - skb_dst_set(skb, NULL); + /* ignore return value from skb_dstref_steal, xfrm_lookup takes + * care of dropping the refcnt if needed. + */ + skb_dstref_steal(skb); dst = xfrm_lookup(net, dst, flowi4_to_flowi(&fl4), sk, 0); if (IS_ERR(dst)) return PTR_ERR(dst); diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index 45f9105f9ac1..46540a5a4331 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c @@ -63,7 +63,10 @@ int ip6_route_me_harder(struct net *net, struct sock *sk_partial, struct sk_buff #ifdef CONFIG_XFRM if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && xfrm_decode_session(net, skb, flowi6_to_flowi(&fl6), AF_INET6) == 0) { - skb_dst_set(skb, NULL); + /* ignore return value from skb_dstref_steal, xfrm_lookup takes + * care of dropping the refcnt if needed. + */ + skb_dstref_steal(skb); dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), sk, 0); if (IS_ERR(dst)) return PTR_ERR(dst); From e97e6a1830ddb5885ba312e56b6fa3aa39b5f47e Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 18 Aug 2025 08:40:29 -0700 Subject: [PATCH 01492/11391] net: Switch to skb_dstref_steal/skb_dstref_restore for ip_route_input callers Going forward skb_dst_set will assert that skb dst_entry is empty during skb_dst_set. skb_dstref_steal is added to reset existing entry without doing refcnt. skb_dstref_restore should be used to restore the previous entry. Convert icmp_route_lookup and ip_options_rcv_srr to these helpers. Add extra call to skb_dstref_reset to icmp_route_lookup to clear the ip_route_input entry. Signed-off-by: Stanislav Fomichev Link: https://patch.msgid.link/20250818154032.3173645-5-sdf@fomichev.me Signed-off-by: Jakub Kicinski --- net/ipv4/icmp.c | 7 ++++--- net/ipv4/ip_options.c | 5 ++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 2ffe73ea644f..91765057aa1d 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -544,14 +544,15 @@ static struct rtable *icmp_route_lookup(struct net *net, struct flowi4 *fl4, goto relookup_failed; } /* Ugh! */ - orefdst = skb_in->_skb_refdst; /* save old refdst */ - skb_dst_set(skb_in, NULL); + orefdst = skb_dstref_steal(skb_in); err = ip_route_input(skb_in, fl4_dec.daddr, fl4_dec.saddr, dscp, rt2->dst.dev) ? -EINVAL : 0; dst_release(&rt2->dst); rt2 = skb_rtable(skb_in); - skb_in->_skb_refdst = orefdst; /* restore old refdst */ + /* steal dst entry from skb_in, don't drop refcnt */ + skb_dstref_steal(skb_in); + skb_dstref_restore(skb_in, orefdst); } if (err) diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index e3321932bec0..be8815ce3ac2 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -615,14 +615,13 @@ int ip_options_rcv_srr(struct sk_buff *skb, struct net_device *dev) } memcpy(&nexthop, &optptr[srrptr-1], 4); - orefdst = skb->_skb_refdst; - skb_dst_set(skb, NULL); + orefdst = skb_dstref_steal(skb); err = ip_route_input(skb, nexthop, iph->saddr, ip4h_dscp(iph), dev) ? -EINVAL : 0; rt2 = skb_rtable(skb); if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) { skb_dst_drop(skb); - skb->_skb_refdst = orefdst; + skb_dstref_restore(skb, orefdst); return -EINVAL; } refdst_drop(orefdst); From da3b9d493ba27c710f4812f1d0a98846f3043f94 Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 18 Aug 2025 08:40:30 -0700 Subject: [PATCH 01493/11391] staging: octeon: Convert to skb_dst_drop Instead of doing dst_release and skb_dst_set, do skb_dst_drop which should do the right thing. Acked-by: Greg Kroah-Hartman Signed-off-by: Stanislav Fomichev Link: https://patch.msgid.link/20250818154032.3173645-6-sdf@fomichev.me Signed-off-by: Jakub Kicinski --- drivers/staging/octeon/ethernet-tx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/staging/octeon/ethernet-tx.c b/drivers/staging/octeon/ethernet-tx.c index 261f8dbdc382..0ba240e634a1 100644 --- a/drivers/staging/octeon/ethernet-tx.c +++ b/drivers/staging/octeon/ethernet-tx.c @@ -346,8 +346,7 @@ netdev_tx_t cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev) * The skbuff will be reused without ever being freed. We must * cleanup a bunch of core things. */ - dst_release(skb_dst(skb)); - skb_dst_set(skb, NULL); + skb_dst_drop(skb); skb_ext_reset(skb); nf_reset_ct(skb); skb_reset_redirect(skb); From 3e31075a119409613627517f205edd86a7f89d7b Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 18 Aug 2025 08:40:31 -0700 Subject: [PATCH 01494/11391] chtls: Convert to skb_dst_reset Going forward skb_dst_set will assert that skb dst_entry is empty during skb_dst_set. skb_dstref_steal is added to reset existing entry without doing refcnt. Chelsio driver is doing extra dst management via skb_dst_set(NULL). Replace these calls with skb_dstref_steal. Signed-off-by: Stanislav Fomichev Link: https://patch.msgid.link/20250818154032.3173645-7-sdf@fomichev.me Signed-off-by: Jakub Kicinski --- .../ethernet/chelsio/inline_crypto/chtls/chtls_cm.c | 10 +++++----- .../ethernet/chelsio/inline_crypto/chtls/chtls_cm.h | 4 ++-- .../ethernet/chelsio/inline_crypto/chtls/chtls_io.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c index 6f6525983130..2e7c2691a193 100644 --- a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c +++ b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c @@ -171,7 +171,7 @@ static void chtls_purge_receive_queue(struct sock *sk) struct sk_buff *skb; while ((skb = __skb_dequeue(&sk->sk_receive_queue)) != NULL) { - skb_dst_set(skb, (void *)NULL); + skb_dstref_steal(skb); kfree_skb(skb); } } @@ -194,7 +194,7 @@ static void chtls_purge_recv_queue(struct sock *sk) struct sk_buff *skb; while ((skb = __skb_dequeue(&tlsk->sk_recv_queue)) != NULL) { - skb_dst_set(skb, NULL); + skb_dstref_steal(skb); kfree_skb(skb); } } @@ -1734,7 +1734,7 @@ static int chtls_rx_data(struct chtls_dev *cdev, struct sk_buff *skb) pr_err("can't find conn. for hwtid %u.\n", hwtid); return -EINVAL; } - skb_dst_set(skb, NULL); + skb_dstref_steal(skb); process_cpl_msg(chtls_recv_data, sk, skb); return 0; } @@ -1786,7 +1786,7 @@ static int chtls_rx_pdu(struct chtls_dev *cdev, struct sk_buff *skb) pr_err("can't find conn. for hwtid %u.\n", hwtid); return -EINVAL; } - skb_dst_set(skb, NULL); + skb_dstref_steal(skb); process_cpl_msg(chtls_recv_pdu, sk, skb); return 0; } @@ -1855,7 +1855,7 @@ static int chtls_rx_cmp(struct chtls_dev *cdev, struct sk_buff *skb) pr_err("can't find conn. for hwtid %u.\n", hwtid); return -EINVAL; } - skb_dst_set(skb, NULL); + skb_dstref_steal(skb); process_cpl_msg(chtls_rx_hdr, sk, skb); return 0; diff --git a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.h b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.h index f61ca657601c..2285cf2df251 100644 --- a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.h +++ b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.h @@ -171,14 +171,14 @@ static inline void chtls_set_req_addr(struct request_sock *oreq, static inline void chtls_free_skb(struct sock *sk, struct sk_buff *skb) { - skb_dst_set(skb, NULL); + skb_dstref_steal(skb); __skb_unlink(skb, &sk->sk_receive_queue); __kfree_skb(skb); } static inline void chtls_kfree_skb(struct sock *sk, struct sk_buff *skb) { - skb_dst_set(skb, NULL); + skb_dstref_steal(skb); __skb_unlink(skb, &sk->sk_receive_queue); kfree_skb(skb); } diff --git a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c index 465fa8077964..4036db466e18 100644 --- a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c +++ b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c @@ -1434,7 +1434,7 @@ static int chtls_pt_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, continue; found_ok_skb: if (!skb->len) { - skb_dst_set(skb, NULL); + skb_dstref_steal(skb); __skb_unlink(skb, &sk->sk_receive_queue); kfree_skb(skb); From a890348adcc993f48d1ae38f1174dc8de4c3c5ac Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 18 Aug 2025 08:40:32 -0700 Subject: [PATCH 01495/11391] net: Add skb_dst_check_unset To prevent dst_entry leaks, add warning when the non-NULL dst_entry is rewritten. Signed-off-by: Stanislav Fomichev Link: https://patch.msgid.link/20250818154032.3173645-8-sdf@fomichev.me Signed-off-by: Jakub Kicinski --- include/linux/skbuff.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 7538ca507ee9..ca8be45dd8be 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1159,6 +1159,12 @@ static inline struct dst_entry *skb_dst(const struct sk_buff *skb) return (struct dst_entry *)(skb->_skb_refdst & SKB_DST_PTRMASK); } +static inline void skb_dst_check_unset(struct sk_buff *skb) +{ + DEBUG_NET_WARN_ON_ONCE((skb->_skb_refdst & SKB_DST_PTRMASK) && + !(skb->_skb_refdst & SKB_DST_NOREF)); +} + /** * skb_dstref_steal() - return current dst_entry value and clear it * @skb: buffer @@ -1188,6 +1194,7 @@ static inline unsigned long skb_dstref_steal(struct sk_buff *skb) */ static inline void skb_dstref_restore(struct sk_buff *skb, unsigned long refdst) { + skb_dst_check_unset(skb); skb->_skb_refdst = refdst; } @@ -1201,6 +1208,7 @@ static inline void skb_dstref_restore(struct sk_buff *skb, unsigned long refdst) */ static inline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst) { + skb_dst_check_unset(skb); skb->slow_gro |= !!dst; skb->_skb_refdst = (unsigned long)dst; } @@ -1217,6 +1225,7 @@ static inline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst) */ static inline void skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst) { + skb_dst_check_unset(skb); WARN_ON(!rcu_read_lock_held() && !rcu_read_lock_bh_held()); skb->slow_gro |= !!dst; skb->_skb_refdst = (unsigned long)dst | SKB_DST_NOREF; From 09bde6fdcd752b4512e7b554a3259e4f6b77c6d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Garc=C3=ADa?= Date: Tue, 19 Aug 2025 00:02:03 +0200 Subject: [PATCH 01496/11391] ipv6: ip6_gre: replace strcpy with strscpy for tunnel name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the strcpy() call that copies the device name into tunnel->parms.name with strscpy(), to avoid potential overflow and guarantee NULL termination. This uses the two-argument form of strscpy(), where the destination size is inferred from the array type. Destination is tunnel->parms.name (size IFNAMSIZ). Tested in QEMU (Alpine rootfs): - Created IPv6 GRE tunnels over loopback - Assigned overlay IPv6 addresses - Verified bidirectional ping through the tunnel - Changed tunnel parameters at runtime (`ip -6 tunnel change`) Signed-off-by: Miguel García Link: https://patch.msgid.link/20250818220203.899338-1-miguelgarciaroman8@gmail.com Signed-off-by: Jakub Kicinski --- net/ipv6/ip6_gre.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 74d49dd6124d..c82a75510c0e 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -329,9 +329,9 @@ static struct ip6_tnl *ip6gre_tunnel_locate(struct net *net, if (parms->name[0]) { if (!dev_valid_name(parms->name)) return NULL; - strscpy(name, parms->name, IFNAMSIZ); + strscpy(name, parms->name); } else { - strcpy(name, "ip6gre%d"); + strscpy(name, "ip6gre%d"); } dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN, ip6gre_tunnel_setup); @@ -1469,7 +1469,7 @@ static int ip6gre_tunnel_init_common(struct net_device *dev) tunnel = netdev_priv(dev); tunnel->dev = dev; - strcpy(tunnel->parms.name, dev->name); + strscpy(tunnel->parms.name, dev->name); ret = dst_cache_init(&tunnel->dst_cache, GFP_KERNEL); if (ret) @@ -1529,7 +1529,7 @@ static void ip6gre_fb_tunnel_init(struct net_device *dev) tunnel->dev = dev; tunnel->net = dev_net(dev); - strcpy(tunnel->parms.name, dev->name); + strscpy(tunnel->parms.name, dev->name); tunnel->hlen = sizeof(struct ipv6hdr) + 4; } @@ -1842,7 +1842,7 @@ static int ip6erspan_tap_init(struct net_device *dev) tunnel = netdev_priv(dev); tunnel->dev = dev; - strcpy(tunnel->parms.name, dev->name); + strscpy(tunnel->parms.name, dev->name); ret = dst_cache_init(&tunnel->dst_cache, GFP_KERNEL); if (ret) From 3a752e67800106a5c42d802d67e06c60aa71d07b Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Fri, 15 Aug 2025 04:20:09 -0400 Subject: [PATCH 01497/11391] net: phy: realtek: enable serdes option mode for RTL8226-CG The RTL8226-CG can make use of the serdes option mode feature to dynamically switch between SGMII and 2500base-X. From what is known the setup sequence is much simpler with no magic values. Convert the exiting config_init() into a helper that configures the PHY depending on generation 1 or 2. Call the helper from two separated new config_init() functions. Finally convert the phy_driver specs of the RTL8226-CG to make use of the new configuration and switch over to the extended read_status() function to dynamically change the interface according to the serdes mode. Remark! The logic could be simpler if the serdes mode could be set before all other generation 2 magic values. Due to missing RTL8221B test hardware the mmd command order was kept. Tested on Zyxel XGS1210-12. Signed-off-by: Markus Stockhausen Link: https://patch.msgid.link/20250815082009.3678865-1-markus.stockhausen@gmx.de Signed-off-by: Jakub Kicinski --- drivers/net/phy/realtek/realtek_main.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index 904fa8b1aa03..b2d0c0f88f75 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -1146,7 +1146,7 @@ static int rtl822x_probe(struct phy_device *phydev) return 0; } -static int rtl822xb_config_init(struct phy_device *phydev) +static int rtl822x_set_serdes_option_mode(struct phy_device *phydev, bool gen1) { bool has_2500, has_sgmii; u16 mode; @@ -1181,15 +1181,18 @@ static int rtl822xb_config_init(struct phy_device *phydev) /* the following sequence with magic numbers sets up the SerDes * option mode */ - ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x75f3, 0); - if (ret < 0) - return ret; + + if (!gen1) { + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x75f3, 0); + if (ret < 0) + return ret; + } ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_OPTION, RTL822X_VND1_SERDES_OPTION_MODE_MASK, mode); - if (ret < 0) + if (gen1 || ret < 0) return ret; ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6a04, 0x0503); @@ -1203,6 +1206,16 @@ static int rtl822xb_config_init(struct phy_device *phydev) return phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020); } +static int rtl822x_config_init(struct phy_device *phydev) +{ + return rtl822x_set_serdes_option_mode(phydev, true); +} + +static int rtl822xb_config_init(struct phy_device *phydev) +{ + return rtl822x_set_serdes_option_mode(phydev, false); +} + static int rtl822xb_get_rate_matching(struct phy_device *phydev, phy_interface_t iface) { @@ -1801,7 +1814,8 @@ static struct phy_driver realtek_drvs[] = { .soft_reset = rtl822x_c45_soft_reset, .get_features = rtl822x_c45_get_features, .config_aneg = rtl822x_c45_config_aneg, - .read_status = rtl822x_c45_read_status, + .config_init = rtl822x_config_init, + .read_status = rtl822xb_c45_read_status, .suspend = genphy_c45_pma_suspend, .resume = rtlgen_c45_resume, }, { From e16e973c576f89be26837778a5566ab9c4231852 Mon Sep 17 00:00:00 2001 From: Jijie Shao Date: Fri, 15 Aug 2025 18:04:13 +0800 Subject: [PATCH 01498/11391] net: hns3: add parameter check for tx_copybreak and tx_spare_buf_size Since the driver always enables tx bounce buffer, there are minimum values for `copybreak` and `tx_spare_buf_size`. This patch will check and reject configurations with values smaller than these minimums. Closes: https://lore.kernel.org/all/20250723072900.GV2459@horms.kernel.org/ Signed-off-by: Jijie Shao Link: https://patch.msgid.link/20250815100414.949752-2-shaojijie@huawei.com Signed-off-by: Jakub Kicinski --- .../ethernet/hisilicon/hns3/hns3_ethtool.c | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index d5454e126c85..a752d0e3db3a 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -1927,6 +1927,31 @@ static int hns3_set_tx_spare_buf_size(struct net_device *netdev, return ret; } +static int hns3_check_tx_copybreak(struct net_device *netdev, u32 copybreak) +{ + struct hns3_nic_priv *priv = netdev_priv(netdev); + + if (copybreak < priv->min_tx_copybreak) { + netdev_err(netdev, "tx copybreak %u should be no less than %u!\n", + copybreak, priv->min_tx_copybreak); + return -EINVAL; + } + return 0; +} + +static int hns3_check_tx_spare_buf_size(struct net_device *netdev, u32 buf_size) +{ + struct hns3_nic_priv *priv = netdev_priv(netdev); + + if (buf_size < priv->min_tx_spare_buf_size) { + netdev_err(netdev, + "tx spare buf size %u should be no less than %u!\n", + buf_size, priv->min_tx_spare_buf_size); + return -EINVAL; + } + return 0; +} + static int hns3_set_tunable(struct net_device *netdev, const struct ethtool_tunable *tuna, const void *data) @@ -1943,6 +1968,10 @@ static int hns3_set_tunable(struct net_device *netdev, switch (tuna->id) { case ETHTOOL_TX_COPYBREAK: + ret = hns3_check_tx_copybreak(netdev, *(u32 *)data); + if (ret) + return ret; + priv->tx_copybreak = *(u32 *)data; for (i = 0; i < h->kinfo.num_tqps; i++) @@ -1957,6 +1986,10 @@ static int hns3_set_tunable(struct net_device *netdev, break; case ETHTOOL_TX_COPYBREAK_BUF_SIZE: + ret = hns3_check_tx_spare_buf_size(netdev, *(u32 *)data); + if (ret) + return ret; + old_tx_spare_buf_size = h->kinfo.tx_spare_buf_size; new_tx_spare_buf_size = *(u32 *)data; netdev_info(netdev, "request to set tx spare buf size from %u to %u\n", From 021f989c863b40613d1a7595e6f88524fd5a531a Mon Sep 17 00:00:00 2001 From: Jijie Shao Date: Fri, 15 Aug 2025 18:04:14 +0800 Subject: [PATCH 01499/11391] net: hns3: change the function return type from int to bool hclge_only_alloc_priv_buff() only return true or false, So, change the function return type from integer to boolean. Signed-off-by: Jijie Shao Link: https://patch.msgid.link/20250815100414.949752-3-shaojijie@huawei.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index f209a05e2033..f5457ae0b64f 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -2182,8 +2182,8 @@ static bool hclge_drop_pfc_buf_till_fit(struct hclge_dev *hdev, return hclge_is_rx_buf_ok(hdev, buf_alloc, rx_all); } -static int hclge_only_alloc_priv_buff(struct hclge_dev *hdev, - struct hclge_pkt_buf_alloc *buf_alloc) +static bool hclge_only_alloc_priv_buff(struct hclge_dev *hdev, + struct hclge_pkt_buf_alloc *buf_alloc) { #define COMPENSATE_BUFFER 0x3C00 #define COMPENSATE_HALF_MPS_NUM 5 From ee0aace5f844ef59335148875d05bec8764e71e8 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Mon, 18 Aug 2025 11:02:15 +0200 Subject: [PATCH 01500/11391] net: stmmac: Correctly handle Rx checksum offload errors The stmmac_rx function would previously set skb->ip_summed to CHECKSUM_UNNECESSARY if hardware checksum offload (CoE) was enabled and the packet was of a known IP ethertype. However, this logic failed to check if the hardware had actually reported a checksum error. The hardware status, indicating a header or payload checksum failure, was being ignored at this stage. This could cause corrupt packets to be passed up the network stack as valid. This patch corrects the logic by checking the `csum_none` status flag, which is set when the hardware reports a checksum error. If this flag is set, skb->ip_summed is now correctly set to CHECKSUM_NONE, ensuring the kernel's network stack will perform its own validation and properly handle the corrupt packet. Signed-off-by: Oleksij Rempel Link: https://patch.msgid.link/20250818090217.2789521-2-o.rempel@pengutronix.de Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 0bbdc1f1a691..a55e43804670 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -5737,7 +5737,8 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) skb->protocol = eth_type_trans(skb, priv->dev); - if (unlikely(!coe) || !stmmac_has_ip_ethertype(skb)) + if (unlikely(!coe) || !stmmac_has_ip_ethertype(skb) || + (status & csum_none)) skb_checksum_none_assert(skb); else skb->ip_summed = CHECKSUM_UNNECESSARY; From 644b8437ccef9e7444164d8c4409933565928371 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Mon, 18 Aug 2025 11:02:16 +0200 Subject: [PATCH 01501/11391] net: stmmac: dwmac4: report Rx checksum errors in status Propagate hardware checksum failures from the descriptor parser to the caller. Currently, dwmac4_wrback_get_rx_status() updates stats when the Rx descriptor signals an IP header or payload checksum error, but it does not reflect this in its return value. The higher-level stmmac_rx() code therefore cannot tell that hardware checksum validation failed. Set the csum_none flag in the returned status when either RDES1_IP_HDR_ERROR or RDES1_IP_PAYLOAD_ERROR is present. This aligns dwmac4 with enh_desc_coe_rdes0() and lets stmmac_rx() mark the skb as CHECKSUM_NONE for software verification. This is a preparatory step for disabling the hardware filter that drops frames which do not pass checksum validation. Signed-off-by: Oleksij Rempel Link: https://patch.msgid.link/20250818090217.2789521-3-o.rempel@pengutronix.de Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c index a5fb31eb0192..aac68dc28dc1 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c @@ -110,16 +110,20 @@ static int dwmac4_wrback_get_rx_status(struct stmmac_extra_stats *x, message_type = (rdes1 & ERDES4_MSG_TYPE_MASK) >> 8; - if (rdes1 & RDES1_IP_HDR_ERROR) + if (rdes1 & RDES1_IP_HDR_ERROR) { x->ip_hdr_err++; + ret |= csum_none; + } if (rdes1 & RDES1_IP_CSUM_BYPASSED) x->ip_csum_bypassed++; if (rdes1 & RDES1_IPV4_HEADER) x->ipv4_pkt_rcvd++; if (rdes1 & RDES1_IPV6_HEADER) x->ipv6_pkt_rcvd++; - if (rdes1 & RDES1_IP_PAYLOAD_ERROR) + if (rdes1 & RDES1_IP_PAYLOAD_ERROR) { x->ip_payload_err++; + ret |= csum_none; + } if (message_type == RDES_EXT_NO_PTP) x->no_ptp_rx_msg_type_ext++; From fe4042797651215ca9acd83035122b5e940acf2e Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Mon, 18 Aug 2025 11:02:17 +0200 Subject: [PATCH 01502/11391] net: stmmac: dwmac4: stop hardware from dropping checksum-error packets Tell the MAC not to discard frames that fail TCP/IP checksum validation. By default, when the hardware checksum engine (CoE) is enabled, dwmac4 silently drops any packet where the offload engine detects a checksum error. These frames are not reported to the driver and are not counted in any statistics as dropped packets. Set the MTL_OP_MODE_DIS_TCP_EF bit when initializing the Rx channel so that all packets are delivered, even if they failed hardware checksum validation. CoE remains enabled, but instead of dropping such frames, the driver propagates the error status and marks the skb with CHECKSUM_NONE. This allows the stack to verify and drop the packet while updating statistics. This change follows the decision made in the discussion: Link: https://lore.kernel.org/all/20250625132117.1b3264e8@kernel.org/ It depends on the previous patches that added proper error propagation in the Rx path. Signed-off-by: Oleksij Rempel Link: https://patch.msgid.link/20250818090217.2789521-4-o.rempel@pengutronix.de Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac4.h | 1 + drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h index f4694fd576f5..3dec1a264cf6 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h @@ -341,6 +341,7 @@ static inline u32 mtl_chanx_base_addr(const struct dwmac4_addrs *addrs, #define MTL_OP_MODE_RFA_SHIFT 8 #define MTL_OP_MODE_EHFC BIT(7) +#define MTL_OP_MODE_DIS_TCP_EF BIT(6) #define MTL_OP_MODE_RTC_MASK GENMASK(1, 0) #define MTL_OP_MODE_RTC_SHIFT 0 diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c index 0cb84a0041a4..d87a8b595e6a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c @@ -268,6 +268,8 @@ static void dwmac4_dma_rx_chan_op_mode(struct stmmac_priv *priv, mtl_rx_op = readl(ioaddr + MTL_CHAN_RX_OP_MODE(dwmac4_addrs, channel)); + mtl_rx_op |= MTL_OP_MODE_DIS_TCP_EF; + if (mode == SF_DMA_MODE) { pr_debug("GMAC: enable RX store and forward mode\n"); mtl_rx_op |= MTL_OP_MODE_RSF; From e115d3d70ecc674df2e716e7030893424fa110fb Mon Sep 17 00:00:00 2001 From: Cryolitia PukNgae Date: Wed, 6 Aug 2025 11:13:16 +0800 Subject: [PATCH 01503/11391] scsi: hpsa: Fix incorrect comment format Comments should not have a leading plus sign. Signed-off-by: Cryolitia PukNgae Link: https://lore.kernel.org/r/20250806-scsi_typo-v1-1-ec353a303b31@uniontech.com Signed-off-by: Martin K. Petersen --- drivers/scsi/hpsa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index c73a71ac3c29..3bb7a1d9af53 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -7632,8 +7632,8 @@ static void hpsa_free_cfgtables(struct ctlr_info *h) } /* Find and map CISS config table and transfer table -+ * several items must be unmapped (freed) later -+ * */ + * several items must be unmapped (freed) later + */ static int hpsa_find_cfgtables(struct ctlr_info *h) { u64 cfg_offset; From daedd69abfee3a871b3a8791ffe20b398e055b87 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Wed, 6 Aug 2025 20:46:32 +0800 Subject: [PATCH 01504/11391] scsi: ipr: Use vmalloc_array() to simplify code Use vmalloc_array() instead of vmalloc() to simplify the function ipr_alloc_dump(). Signed-off-by: Qianfeng Rong Link: https://lore.kernel.org/r/20250806124633.383426-2-rongqianfeng@vivo.com Signed-off-by: Martin K. Petersen --- drivers/scsi/ipr.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index d06b79f03538..4fb5654472d8 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -4281,11 +4281,11 @@ static int ipr_alloc_dump(struct ipr_ioa_cfg *ioa_cfg) } if (ioa_cfg->sis64) - ioa_data = vmalloc(array_size(IPR_FMT3_MAX_NUM_DUMP_PAGES, - sizeof(__be32 *))); + ioa_data = vmalloc_array(IPR_FMT3_MAX_NUM_DUMP_PAGES, + sizeof(__be32 *)); else - ioa_data = vmalloc(array_size(IPR_FMT2_MAX_NUM_DUMP_PAGES, - sizeof(__be32 *))); + ioa_data = vmalloc_array(IPR_FMT2_MAX_NUM_DUMP_PAGES, + sizeof(__be32 *)); if (!ioa_data) { ipr_err("Dump memory allocation failed\n"); From 6b5da52a1825d600cdee1dd8bf90e95fa12620f0 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Wed, 6 Aug 2025 20:46:33 +0800 Subject: [PATCH 01505/11391] scsi: scsi_debug: Use vcalloc() to simplify code Use vcalloc() instead of vmalloc() followed by bitmap_zero() to simplify the function sdebug_add_store(). Signed-off-by: Qianfeng Rong Link: https://lore.kernel.org/r/20250806124633.383426-3-rongqianfeng@vivo.com Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_debug.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 0847767d4d43..90943857243c 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -8782,8 +8782,8 @@ static int sdebug_add_store(void) /* Logical Block Provisioning */ if (scsi_debug_lbp()) { map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1; - sip->map_storep = vmalloc(array_size(sizeof(long), - BITS_TO_LONGS(map_size))); + sip->map_storep = vcalloc(BITS_TO_LONGS(map_size), + sizeof(long)); pr_info("%lu provisioning blocks\n", map_size); @@ -8792,8 +8792,6 @@ static int sdebug_add_store(void) goto err; } - bitmap_zero(sip->map_storep, map_size); - /* Map first 1KB for partition table */ if (sdebug_num_parts) map_region(sip, 0, 2); From 6f4b10226b6b1e7d1ff3cdb006cf0f6da6eed71e Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 13 Aug 2025 16:07:44 -0400 Subject: [PATCH 01506/11391] scsi: qla2xxx: Fix memcpy() field-spanning write issue purex_item.iocb is defined as a 64-element u8 array, but 64 is the minimum size and it can be allocated larger. This makes it a standard empty flex array. This was motivated by field-spanning write warnings during FPIN testing: https://lore.kernel.org/linux-nvme/20250709211919.49100-1-bgurney@redhat.com/ > kernel: memcpy: detected field-spanning write (size 60) of single field > "((uint8_t *)fpin_pkt + buffer_copy_offset)" > at drivers/scsi/qla2xxx/qla_isr.c:1221 (size 44) I removed the outer wrapper from the iocb flex array, so that it can be linked to 'purex_item.size' with '__counted_by'. These changes remove the default minimum 64-byte allocation, requiring further changes. In 'struct scsi_qla_host' the embedded 'default_item' is now followed by '__default_item_iocb[QLA_DEFAULT_PAYLOAD_SIZE]' to reserve space that will be used as 'default_item.iocb'. This is wrapped using the 'TRAILING_OVERLAP()' macro helper, which effectively creates a union between flexible-array member 'default_item.iocb' and '__default_item_iocb'. Since 'struct pure_item' now contains a flexible-array member, the helper must be placed at the end of 'struct scsi_qla_host' to prevent a '-Wflex-array-member-not-at-end' warning. 'qla24xx_alloc_purex_item()' is adjusted to no longer expect the default minimum size to be part of 'sizeof(struct purex_item)', the entire flexible array size is added to the structure size for allocation. This also slightly changes the layout of the purex_item struct, as 2-bytes of padding are added between 'size' and 'iocb'. The resulting size is the same, but iocb is shifted 2-bytes (the original 'purex_item' structure was padded at the end, after the 64-byte defined array size). I don't think this is a problem. Tested-by: Bryan Gurney Co-developed-by: Chris Leech Signed-off-by: Chris Leech Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/20250813200744.17975-10-bgurney@redhat.com Reviewed-by: Hannes Reinecke 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, 18 insertions(+), 16 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index cb95b7b12051..604e66bead1e 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -4890,9 +4890,7 @@ struct purex_item { struct purex_item *pkt); atomic_t in_use; uint16_t size; - struct { - uint8_t iocb[64]; - } iocb; + uint8_t iocb[] __counted_by(size); }; #include "qla_edif.h" @@ -5101,7 +5099,6 @@ 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 */ @@ -5130,6 +5127,11 @@ 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 c4c6b5c6658c..4559b490614d 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(item_hdr_size + - (size - QLA_DEFAULT_PAYLOAD_SIZE), GFP_ATOMIC); + item = kzalloc(struct_size(item, iocb, 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(item_hdr_size, GFP_ATOMIC); + item = kzalloc( + struct_size(item, iocb, QLA_DEFAULT_PAYLOAD_SIZE), + GFP_ATOMIC); } } if (!item) { @@ -1127,17 +1127,16 @@ 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, sizeof(item->iocb)); + memcpy(&item->iocb, pkt, QLA_DEFAULT_PAYLOAD_SIZE); return item; } diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index 8ee2e337c9e1..92488890bc04 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.iocb[3], item->size, uctx->exchange_address, + item->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 d4b484c0fd9d..253f802605d6 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -6459,9 +6459,10 @@ void qla24xx_process_purex_rdp(struct scsi_qla_host *vha, 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)); - else + memset(&item->vha->__default_item_iocb, 0, QLA_DEFAULT_PAYLOAD_SIZE); + } else kfree(item); } From 68889dfd547bd8eabc5a98b58475d7b901cf5129 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Fri, 15 Aug 2025 20:16:09 +0000 Subject: [PATCH 01507/11391] mptcp: Fix up subflow's memcg when CONFIG_SOCK_CGROUP_DATA=n. When sk_alloc() allocates a socket, mem_cgroup_sk_alloc() sets sk->sk_memcg based on the current task. MPTCP subflow socket creation is triggered from userspace or an in-kernel worker. In the latter case, sk->sk_memcg is not what we want. So, we fix it up from the parent socket's sk->sk_memcg in mptcp_attach_cgroup(). Although the code is placed under #ifdef CONFIG_MEMCG, it is buried under #ifdef CONFIG_SOCK_CGROUP_DATA. The two configs are orthogonal. If CONFIG_MEMCG is enabled without CONFIG_SOCK_CGROUP_DATA, the subflow's memory usage is not charged correctly. Let's move the code out of the wrong ifdef guard. Note that sk->sk_memcg is freed in sk_prot_free() and the parent sk holds the refcnt of memcg->css here, so we don't need to use css_tryget(). Fixes: 3764b0c5651e3 ("mptcp: attach subflow socket to parent cgroup") Signed-off-by: Kuniyuki Iwashima Reviewed-by: Eric Dumazet Acked-by: Matthieu Baerts (NGI0) Acked-by: Shakeel Butt Link: https://patch.msgid.link/20250815201712.1745332-2-kuniyu@google.com Signed-off-by: Jakub Kicinski --- include/linux/memcontrol.h | 6 ++++++ mm/memcontrol.c | 13 +++++++++++++ net/mptcp/subflow.c | 11 +++-------- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index 785173aa0739..25921fbec685 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -1604,6 +1604,7 @@ extern struct static_key_false memcg_sockets_enabled_key; #define mem_cgroup_sockets_enabled static_branch_unlikely(&memcg_sockets_enabled_key) void mem_cgroup_sk_alloc(struct sock *sk); void mem_cgroup_sk_free(struct sock *sk); +void mem_cgroup_sk_inherit(const struct sock *sk, struct sock *newsk); #if BITS_PER_LONG < 64 static inline void mem_cgroup_set_socket_pressure(struct mem_cgroup *memcg) @@ -1661,6 +1662,11 @@ void reparent_shrinker_deferred(struct mem_cgroup *memcg); #define mem_cgroup_sockets_enabled 0 static inline void mem_cgroup_sk_alloc(struct sock *sk) { }; static inline void mem_cgroup_sk_free(struct sock *sk) { }; + +static inline void mem_cgroup_sk_inherit(const struct sock *sk, struct sock *newsk) +{ +} + static inline bool mem_cgroup_under_socket_pressure(struct mem_cgroup *memcg) { return false; diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 8dd7fbed5a94..46713b9ece06 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -5024,6 +5024,19 @@ void mem_cgroup_sk_free(struct sock *sk) css_put(&sk->sk_memcg->css); } +void mem_cgroup_sk_inherit(const struct sock *sk, struct sock *newsk) +{ + if (sk->sk_memcg == newsk->sk_memcg) + return; + + mem_cgroup_sk_free(newsk); + + if (sk->sk_memcg) + css_get(&sk->sk_memcg->css); + + newsk->sk_memcg = sk->sk_memcg; +} + /** * mem_cgroup_charge_skmem - charge socket memory * @memcg: memcg to charge diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index 3f1b62a9fe88..c8a7e4b59db1 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -1717,19 +1717,14 @@ static void mptcp_attach_cgroup(struct sock *parent, struct sock *child) /* only the additional subflows created by kworkers have to be modified */ if (cgroup_id(sock_cgroup_ptr(parent_skcd)) != cgroup_id(sock_cgroup_ptr(child_skcd))) { -#ifdef CONFIG_MEMCG - struct mem_cgroup *memcg = parent->sk_memcg; - - mem_cgroup_sk_free(child); - if (memcg && css_tryget(&memcg->css)) - child->sk_memcg = memcg; -#endif /* CONFIG_MEMCG */ - cgroup_sk_free(child_skcd); *child_skcd = *parent_skcd; cgroup_sk_clone(child_skcd); } #endif /* CONFIG_SOCK_CGROUP_DATA */ + + if (mem_cgroup_sockets_enabled) + mem_cgroup_sk_inherit(parent, child); } static void mptcp_subflow_ops_override(struct sock *ssk) From 1068b48ed10805b61be0668cd774af97163479a7 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Fri, 15 Aug 2025 20:16:10 +0000 Subject: [PATCH 01508/11391] mptcp: Use tcp_under_memory_pressure() in mptcp_epollin_ready(). Some conditions used in mptcp_epollin_ready() are the same as tcp_under_memory_pressure(). We will modify tcp_under_memory_pressure() in the later patch. Let's use tcp_under_memory_pressure() instead. Signed-off-by: Kuniyuki Iwashima Reviewed-by: Eric Dumazet Reviewed-by: Matthieu Baerts (NGI0) Reviewed-by: Shakeel Butt Link: https://patch.msgid.link/20250815201712.1745332-3-kuniyu@google.com Signed-off-by: Jakub Kicinski --- net/mptcp/protocol.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index b15d7fab5c4b..a1787a1344ac 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -788,9 +788,7 @@ static inline bool mptcp_epollin_ready(const struct sock *sk) * as it can always coalesce them */ return (data_avail >= sk->sk_rcvlowat) || - (mem_cgroup_sockets_enabled && sk->sk_memcg && - mem_cgroup_under_socket_pressure(sk->sk_memcg)) || - READ_ONCE(tcp_memory_pressure); + tcp_under_memory_pressure(sk); } int mptcp_set_rcvlowat(struct sock *sk, int val); From e2afa83296bbac40829624b508492b562a21e4d4 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Fri, 15 Aug 2025 20:16:11 +0000 Subject: [PATCH 01509/11391] tcp: Simplify error path in inet_csk_accept(). When an error occurs in inet_csk_accept(), what we should do is only call release_sock() and set the errno to arg->err. But the path jumps to another label, which introduces unnecessary initialisation and tests for newsk. Let's simplify the error path and remove the redundant NULL checks for newsk. Signed-off-by: Kuniyuki Iwashima Reviewed-by: Eric Dumazet Reviewed-by: Shakeel Butt Link: https://patch.msgid.link/20250815201712.1745332-4-kuniyu@google.com Signed-off-by: Jakub Kicinski --- net/ipv4/inet_connection_sock.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 1e2df51427fe..724bd9ed6cd4 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -706,9 +706,9 @@ struct sock *inet_csk_accept(struct sock *sk, struct proto_accept_arg *arg) spin_unlock_bh(&queue->fastopenq.lock); } -out: release_sock(sk); - if (newsk && mem_cgroup_sockets_enabled) { + + if (mem_cgroup_sockets_enabled) { gfp_t gfp = GFP_KERNEL | __GFP_NOFAIL; int amt = 0; @@ -732,18 +732,17 @@ struct sock *inet_csk_accept(struct sock *sk, struct proto_accept_arg *arg) release_sock(newsk); } + if (req) reqsk_put(req); - if (newsk) - inet_init_csk_locks(newsk); - + inet_init_csk_locks(newsk); return newsk; + out_err: - newsk = NULL; - req = NULL; + release_sock(sk); arg->err = error; - goto out; + return NULL; } EXPORT_SYMBOL(inet_csk_accept); From 9d85c565a7b7c78b732393c02bcaa4d5c275fe58 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Fri, 15 Aug 2025 20:16:12 +0000 Subject: [PATCH 01510/11391] net: Call trace_sock_exceed_buf_limit() for memcg failure with SK_MEM_RECV. Initially, trace_sock_exceed_buf_limit() was invoked when __sk_mem_raise_allocated() failed due to the memcg limit or the global limit. However, commit d6f19938eb031 ("net: expose sk wmem in sock_exceed_buf_limit tracepoint") somehow suppressed the event only when memcg failed to charge for SK_MEM_RECV, although the memcg failure for SK_MEM_SEND still triggers the event. Let's restore the event for SK_MEM_RECV. Signed-off-by: Kuniyuki Iwashima Reviewed-by: Eric Dumazet Reviewed-by: Shakeel Butt Link: https://patch.msgid.link/20250815201712.1745332-5-kuniyu@google.com Signed-off-by: Jakub Kicinski --- net/core/sock.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/core/sock.c b/net/core/sock.c index 7c26ec8dce63..380bc1aa6982 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -3354,8 +3354,7 @@ int __sk_mem_raise_allocated(struct sock *sk, int size, int amt, int kind) } } - if (kind == SK_MEM_SEND || (kind == SK_MEM_RECV && charged)) - trace_sock_exceed_buf_limit(sk, prot, allocated, kind); + trace_sock_exceed_buf_limit(sk, prot, allocated, kind); sk_memory_allocated_sub(sk, amt); From bd4aa2337374dd04b8627efd26227ebd49f69285 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Fri, 15 Aug 2025 20:16:13 +0000 Subject: [PATCH 01511/11391] net: Clean up __sk_mem_raise_allocated(). In __sk_mem_raise_allocated(), charged is initialised as true due to the weird condition removed in the previous patch. It makes the variable unreliable by itself, so we have to check another variable, memcg, in advance. Also, we will factorise the common check below for memcg later. if (mem_cgroup_sockets_enabled && sk->sk_memcg) As a prep, let's initialise charged as false and memcg as NULL. Signed-off-by: Kuniyuki Iwashima Reviewed-by: Eric Dumazet Reviewed-by: Shakeel Butt Link: https://patch.msgid.link/20250815201712.1745332-6-kuniyu@google.com Signed-off-by: Jakub Kicinski --- net/core/sock.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/net/core/sock.c b/net/core/sock.c index 380bc1aa6982..000940ecf360 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -3263,15 +3263,16 @@ EXPORT_SYMBOL(sk_wait_data); */ int __sk_mem_raise_allocated(struct sock *sk, int size, int amt, int kind) { - struct mem_cgroup *memcg = mem_cgroup_sockets_enabled ? sk->sk_memcg : NULL; struct proto *prot = sk->sk_prot; - bool charged = true; + struct mem_cgroup *memcg = NULL; + bool charged = false; long allocated; sk_memory_allocated_add(sk, amt); allocated = sk_memory_allocated(sk); - if (memcg) { + if (mem_cgroup_sockets_enabled && sk->sk_memcg) { + memcg = sk->sk_memcg; charged = mem_cgroup_charge_skmem(memcg, amt, gfp_memcg_charge()); if (!charged) goto suppress_allocation; @@ -3358,7 +3359,7 @@ int __sk_mem_raise_allocated(struct sock *sk, int size, int amt, int kind) sk_memory_allocated_sub(sk, amt); - if (memcg && charged) + if (charged) mem_cgroup_uncharge_skmem(memcg, amt); return 0; From f7161b234f2ec7f18999009c4becc04eeb6b12a7 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Fri, 15 Aug 2025 20:16:14 +0000 Subject: [PATCH 01512/11391] net-memcg: Introduce mem_cgroup_from_sk(). We will store a flag in the lowest bit of sk->sk_memcg. Then, directly dereferencing sk->sk_memcg will be illegal, and we do not want to allow touching the raw sk->sk_memcg in many places. Let's introduce mem_cgroup_from_sk(). Other places accessing the raw sk->sk_memcg will be converted later. Note that we cannot define the helper as an inline function in memcontrol.h as we cannot access any fields of struct sock there due to circular dependency, so it is placed in sock.h. Signed-off-by: Kuniyuki Iwashima Reviewed-by: Eric Dumazet Acked-by: Roman Gushchin Acked-by: Shakeel Butt Link: https://patch.msgid.link/20250815201712.1745332-7-kuniyu@google.com Signed-off-by: Jakub Kicinski --- include/net/sock.h | 12 ++++++++++++ mm/memcontrol.c | 13 +++++++++---- net/ipv4/inet_connection_sock.c | 2 +- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index c8a4b283df6f..811f95ea8d00 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -2594,6 +2594,18 @@ static inline gfp_t gfp_memcg_charge(void) return in_softirq() ? GFP_ATOMIC : GFP_KERNEL; } +#ifdef CONFIG_MEMCG +static inline struct mem_cgroup *mem_cgroup_from_sk(const struct sock *sk) +{ + return sk->sk_memcg; +} +#else +static inline struct mem_cgroup *mem_cgroup_from_sk(const struct sock *sk) +{ + return NULL; +} +#endif + static inline long sock_rcvtimeo(const struct sock *sk, bool noblock) { return noblock ? 0 : READ_ONCE(sk->sk_rcvtimeo); diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 46713b9ece06..d8a52d1d08fa 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -5020,19 +5020,24 @@ void mem_cgroup_sk_alloc(struct sock *sk) void mem_cgroup_sk_free(struct sock *sk) { - if (sk->sk_memcg) - css_put(&sk->sk_memcg->css); + struct mem_cgroup *memcg = mem_cgroup_from_sk(sk); + + if (memcg) + css_put(&memcg->css); } void mem_cgroup_sk_inherit(const struct sock *sk, struct sock *newsk) { + struct mem_cgroup *memcg; + if (sk->sk_memcg == newsk->sk_memcg) return; mem_cgroup_sk_free(newsk); - if (sk->sk_memcg) - css_get(&sk->sk_memcg->css); + memcg = mem_cgroup_from_sk(sk); + if (memcg) + css_get(&memcg->css); newsk->sk_memcg = sk->sk_memcg; } diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 724bd9ed6cd4..93569bbe00f4 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -718,7 +718,7 @@ struct sock *inet_csk_accept(struct sock *sk, struct proto_accept_arg *arg) lock_sock(newsk); mem_cgroup_sk_alloc(newsk); - if (newsk->sk_memcg) { + if (mem_cgroup_from_sk(newsk)) { /* The socket has not been accepted yet, no need * to look at newsk->sk_wmem_queued. */ From 43049b0db03823c2cd003ca7d3dddcd3924da8dc Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Fri, 15 Aug 2025 20:16:15 +0000 Subject: [PATCH 01513/11391] net-memcg: Introduce mem_cgroup_sk_enabled(). The socket memcg feature is enabled by a static key and only works for non-root cgroup. We check both conditions in many places. Let's factorise it as a helper function. Signed-off-by: Kuniyuki Iwashima Reviewed-by: Eric Dumazet Acked-by: Roman Gushchin Acked-by: Shakeel Butt Link: https://patch.msgid.link/20250815201712.1745332-8-kuniyu@google.com Signed-off-by: Jakub Kicinski --- include/net/proto_memory.h | 2 +- include/net/sock.h | 10 ++++++++++ include/net/tcp.h | 2 +- net/core/sock.c | 6 +++--- net/ipv4/tcp_output.c | 2 +- 5 files changed, 16 insertions(+), 6 deletions(-) diff --git a/include/net/proto_memory.h b/include/net/proto_memory.h index a6ab2f4f5e28..859e63de81c4 100644 --- a/include/net/proto_memory.h +++ b/include/net/proto_memory.h @@ -31,7 +31,7 @@ static inline bool sk_under_memory_pressure(const struct sock *sk) if (!sk->sk_prot->memory_pressure) return false; - if (mem_cgroup_sockets_enabled && sk->sk_memcg && + if (mem_cgroup_sk_enabled(sk) && mem_cgroup_under_socket_pressure(sk->sk_memcg)) return true; diff --git a/include/net/sock.h b/include/net/sock.h index 811f95ea8d00..3efdf680401d 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -2599,11 +2599,21 @@ static inline struct mem_cgroup *mem_cgroup_from_sk(const struct sock *sk) { return sk->sk_memcg; } + +static inline bool mem_cgroup_sk_enabled(const struct sock *sk) +{ + return mem_cgroup_sockets_enabled && mem_cgroup_from_sk(sk); +} #else static inline struct mem_cgroup *mem_cgroup_from_sk(const struct sock *sk) { return NULL; } + +static inline bool mem_cgroup_sk_enabled(const struct sock *sk) +{ + return false; +} #endif static inline long sock_rcvtimeo(const struct sock *sk, bool noblock) diff --git a/include/net/tcp.h b/include/net/tcp.h index 526a26e7a150..9f01b6be6444 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -275,7 +275,7 @@ extern unsigned long tcp_memory_pressure; /* optimized version of sk_under_memory_pressure() for TCP sockets */ static inline bool tcp_under_memory_pressure(const struct sock *sk) { - if (mem_cgroup_sockets_enabled && sk->sk_memcg && + if (mem_cgroup_sk_enabled(sk) && mem_cgroup_under_socket_pressure(sk->sk_memcg)) return true; diff --git a/net/core/sock.c b/net/core/sock.c index 000940ecf360..ab658fe23e1e 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1032,7 +1032,7 @@ static int sock_reserve_memory(struct sock *sk, int bytes) bool charged; int pages; - if (!mem_cgroup_sockets_enabled || !sk->sk_memcg || !sk_has_account(sk)) + if (!mem_cgroup_sk_enabled(sk) || !sk_has_account(sk)) return -EOPNOTSUPP; if (!bytes) @@ -3271,7 +3271,7 @@ int __sk_mem_raise_allocated(struct sock *sk, int size, int amt, int kind) sk_memory_allocated_add(sk, amt); allocated = sk_memory_allocated(sk); - if (mem_cgroup_sockets_enabled && sk->sk_memcg) { + if (mem_cgroup_sk_enabled(sk)) { memcg = sk->sk_memcg; charged = mem_cgroup_charge_skmem(memcg, amt, gfp_memcg_charge()); if (!charged) @@ -3398,7 +3398,7 @@ void __sk_mem_reduce_allocated(struct sock *sk, int amount) { sk_memory_allocated_sub(sk, amount); - if (mem_cgroup_sockets_enabled && sk->sk_memcg) + if (mem_cgroup_sk_enabled(sk)) mem_cgroup_uncharge_skmem(sk->sk_memcg, amount); if (sk_under_global_memory_pressure(sk) && diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index caf11920a878..37fb320e6f70 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -3578,7 +3578,7 @@ void sk_forced_mem_schedule(struct sock *sk, int size) sk_forward_alloc_add(sk, amt << PAGE_SHIFT); sk_memory_allocated_add(sk, amt); - if (mem_cgroup_sockets_enabled && sk->sk_memcg) + if (mem_cgroup_sk_enabled(sk)) mem_cgroup_charge_skmem(sk->sk_memcg, amt, gfp_memcg_charge() | __GFP_NOFAIL); } From bb178c6bc08525d758a57775458d644304011bf8 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Fri, 15 Aug 2025 20:16:16 +0000 Subject: [PATCH 01514/11391] net-memcg: Pass struct sock to mem_cgroup_sk_(un)?charge(). We will store a flag in the lowest bit of sk->sk_memcg. Then, we cannot pass the raw pointer to mem_cgroup_charge_skmem() and mem_cgroup_uncharge_skmem(). Let's pass struct sock to the functions. While at it, they are renamed to match other functions starting with mem_cgroup_sk_. Signed-off-by: Kuniyuki Iwashima Reviewed-by: Eric Dumazet Acked-by: Roman Gushchin Acked-by: Shakeel Butt Link: https://patch.msgid.link/20250815201712.1745332-9-kuniyu@google.com Signed-off-by: Jakub Kicinski --- include/linux/memcontrol.h | 29 ++++++++++++++++++++++++----- mm/memcontrol.c | 18 +++++++++++------- net/core/sock.c | 24 +++++++++++------------- net/ipv4/inet_connection_sock.c | 2 +- net/ipv4/tcp_output.c | 3 +-- 5 files changed, 48 insertions(+), 28 deletions(-) diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index 25921fbec685..0837d3de3a68 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -1596,15 +1596,16 @@ static inline void mem_cgroup_flush_foreign(struct bdi_writeback *wb) #endif /* CONFIG_CGROUP_WRITEBACK */ struct sock; -bool mem_cgroup_charge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages, - gfp_t gfp_mask); -void mem_cgroup_uncharge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages); #ifdef CONFIG_MEMCG extern struct static_key_false memcg_sockets_enabled_key; #define mem_cgroup_sockets_enabled static_branch_unlikely(&memcg_sockets_enabled_key) + void mem_cgroup_sk_alloc(struct sock *sk); void mem_cgroup_sk_free(struct sock *sk); void mem_cgroup_sk_inherit(const struct sock *sk, struct sock *newsk); +bool mem_cgroup_sk_charge(const struct sock *sk, unsigned int nr_pages, + gfp_t gfp_mask); +void mem_cgroup_sk_uncharge(const struct sock *sk, unsigned int nr_pages); #if BITS_PER_LONG < 64 static inline void mem_cgroup_set_socket_pressure(struct mem_cgroup *memcg) @@ -1660,13 +1661,31 @@ void set_shrinker_bit(struct mem_cgroup *memcg, int nid, int shrinker_id); void reparent_shrinker_deferred(struct mem_cgroup *memcg); #else #define mem_cgroup_sockets_enabled 0 -static inline void mem_cgroup_sk_alloc(struct sock *sk) { }; -static inline void mem_cgroup_sk_free(struct sock *sk) { }; + +static inline void mem_cgroup_sk_alloc(struct sock *sk) +{ +} + +static inline void mem_cgroup_sk_free(struct sock *sk) +{ +} static inline void mem_cgroup_sk_inherit(const struct sock *sk, struct sock *newsk) { } +static inline bool mem_cgroup_sk_charge(const struct sock *sk, + unsigned int nr_pages, + gfp_t gfp_mask) +{ + return false; +} + +static inline void mem_cgroup_sk_uncharge(const struct sock *sk, + unsigned int nr_pages) +{ +} + static inline bool mem_cgroup_under_socket_pressure(struct mem_cgroup *memcg) { return false; diff --git a/mm/memcontrol.c b/mm/memcontrol.c index d8a52d1d08fa..df3e9205c9e6 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -5043,17 +5043,19 @@ void mem_cgroup_sk_inherit(const struct sock *sk, struct sock *newsk) } /** - * mem_cgroup_charge_skmem - charge socket memory - * @memcg: memcg to charge + * mem_cgroup_sk_charge - charge socket memory + * @sk: socket in memcg to charge * @nr_pages: number of pages to charge * @gfp_mask: reclaim mode * * Charges @nr_pages to @memcg. Returns %true if the charge fit within * @memcg's configured limit, %false if it doesn't. */ -bool mem_cgroup_charge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages, - gfp_t gfp_mask) +bool mem_cgroup_sk_charge(const struct sock *sk, unsigned int nr_pages, + gfp_t gfp_mask) { + struct mem_cgroup *memcg = mem_cgroup_from_sk(sk); + if (!cgroup_subsys_on_dfl(memory_cgrp_subsys)) return memcg1_charge_skmem(memcg, nr_pages, gfp_mask); @@ -5066,12 +5068,14 @@ bool mem_cgroup_charge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages, } /** - * mem_cgroup_uncharge_skmem - uncharge socket memory - * @memcg: memcg to uncharge + * mem_cgroup_sk_uncharge - uncharge socket memory + * @sk: socket in memcg to uncharge * @nr_pages: number of pages to uncharge */ -void mem_cgroup_uncharge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages) +void mem_cgroup_sk_uncharge(const struct sock *sk, unsigned int nr_pages) { + struct mem_cgroup *memcg = mem_cgroup_from_sk(sk); + if (!cgroup_subsys_on_dfl(memory_cgrp_subsys)) { memcg1_uncharge_skmem(memcg, nr_pages); return; diff --git a/net/core/sock.c b/net/core/sock.c index ab658fe23e1e..5537ca263858 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1041,8 +1041,8 @@ static int sock_reserve_memory(struct sock *sk, int bytes) pages = sk_mem_pages(bytes); /* pre-charge to memcg */ - charged = mem_cgroup_charge_skmem(sk->sk_memcg, pages, - GFP_KERNEL | __GFP_RETRY_MAYFAIL); + charged = mem_cgroup_sk_charge(sk, pages, + GFP_KERNEL | __GFP_RETRY_MAYFAIL); if (!charged) return -ENOMEM; @@ -1054,7 +1054,7 @@ static int sock_reserve_memory(struct sock *sk, int bytes) */ if (allocated > sk_prot_mem_limits(sk, 1)) { sk_memory_allocated_sub(sk, pages); - mem_cgroup_uncharge_skmem(sk->sk_memcg, pages); + mem_cgroup_sk_uncharge(sk, pages); return -ENOMEM; } sk_forward_alloc_add(sk, pages << PAGE_SHIFT); @@ -3263,17 +3263,16 @@ EXPORT_SYMBOL(sk_wait_data); */ int __sk_mem_raise_allocated(struct sock *sk, int size, int amt, int kind) { + bool memcg_enabled = false, charged = false; struct proto *prot = sk->sk_prot; - struct mem_cgroup *memcg = NULL; - bool charged = false; long allocated; sk_memory_allocated_add(sk, amt); allocated = sk_memory_allocated(sk); if (mem_cgroup_sk_enabled(sk)) { - memcg = sk->sk_memcg; - charged = mem_cgroup_charge_skmem(memcg, amt, gfp_memcg_charge()); + memcg_enabled = true; + charged = mem_cgroup_sk_charge(sk, amt, gfp_memcg_charge()); if (!charged) goto suppress_allocation; } @@ -3347,10 +3346,9 @@ int __sk_mem_raise_allocated(struct sock *sk, int size, int amt, int kind) */ if (sk->sk_wmem_queued + size >= sk->sk_sndbuf) { /* Force charge with __GFP_NOFAIL */ - if (memcg && !charged) { - mem_cgroup_charge_skmem(memcg, amt, - gfp_memcg_charge() | __GFP_NOFAIL); - } + if (memcg_enabled && !charged) + mem_cgroup_sk_charge(sk, amt, + gfp_memcg_charge() | __GFP_NOFAIL); return 1; } } @@ -3360,7 +3358,7 @@ int __sk_mem_raise_allocated(struct sock *sk, int size, int amt, int kind) sk_memory_allocated_sub(sk, amt); if (charged) - mem_cgroup_uncharge_skmem(memcg, amt); + mem_cgroup_sk_uncharge(sk, amt); return 0; } @@ -3399,7 +3397,7 @@ void __sk_mem_reduce_allocated(struct sock *sk, int amount) sk_memory_allocated_sub(sk, amount); if (mem_cgroup_sk_enabled(sk)) - mem_cgroup_uncharge_skmem(sk->sk_memcg, amount); + mem_cgroup_sk_uncharge(sk, amount); if (sk_under_global_memory_pressure(sk) && (sk_memory_allocated(sk) < sk_prot_mem_limits(sk, 0))) diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 93569bbe00f4..0ef1eacd539d 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -727,7 +727,7 @@ struct sock *inet_csk_accept(struct sock *sk, struct proto_accept_arg *arg) } if (amt) - mem_cgroup_charge_skmem(newsk->sk_memcg, amt, gfp); + mem_cgroup_sk_charge(newsk, amt, gfp); kmem_cache_charge(newsk, gfp); release_sock(newsk); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 37fb320e6f70..dfbac0876d96 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -3579,8 +3579,7 @@ void sk_forced_mem_schedule(struct sock *sk, int size) sk_memory_allocated_add(sk, amt); if (mem_cgroup_sk_enabled(sk)) - mem_cgroup_charge_skmem(sk->sk_memcg, amt, - gfp_memcg_charge() | __GFP_NOFAIL); + mem_cgroup_sk_charge(sk, amt, gfp_memcg_charge() | __GFP_NOFAIL); } /* Send a FIN. The caller locks the socket for us. From b2ffd10cddde47cc6830e4981e91e3215def62b1 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Fri, 15 Aug 2025 20:16:17 +0000 Subject: [PATCH 01515/11391] net-memcg: Pass struct sock to mem_cgroup_sk_under_memory_pressure(). We will store a flag in the lowest bit of sk->sk_memcg. Then, we cannot pass the raw pointer to mem_cgroup_under_socket_pressure(). Let's pass struct sock to it and rename the function to match other functions starting with mem_cgroup_sk_. Note that the helper is moved to sock.h to use mem_cgroup_from_sk(). Signed-off-by: Kuniyuki Iwashima Reviewed-by: Eric Dumazet Acked-by: Roman Gushchin Acked-by: Shakeel Butt Link: https://patch.msgid.link/20250815201712.1745332-10-kuniyu@google.com Signed-off-by: Jakub Kicinski --- include/linux/memcontrol.h | 18 ------------------ include/net/proto_memory.h | 2 +- include/net/sock.h | 22 ++++++++++++++++++++++ include/net/tcp.h | 2 +- 4 files changed, 24 insertions(+), 20 deletions(-) diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index 0837d3de3a68..fb27e3d2fdac 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -1642,19 +1642,6 @@ static inline u64 mem_cgroup_get_socket_pressure(struct mem_cgroup *memcg) } #endif -static inline bool mem_cgroup_under_socket_pressure(struct mem_cgroup *memcg) -{ -#ifdef CONFIG_MEMCG_V1 - if (!cgroup_subsys_on_dfl(memory_cgrp_subsys)) - return !!memcg->tcpmem_pressure; -#endif /* CONFIG_MEMCG_V1 */ - do { - if (time_before64(get_jiffies_64(), mem_cgroup_get_socket_pressure(memcg))) - return true; - } while ((memcg = parent_mem_cgroup(memcg))); - return false; -} - int alloc_shrinker_info(struct mem_cgroup *memcg); void free_shrinker_info(struct mem_cgroup *memcg); void set_shrinker_bit(struct mem_cgroup *memcg, int nid, int shrinker_id); @@ -1686,11 +1673,6 @@ static inline void mem_cgroup_sk_uncharge(const struct sock *sk, { } -static inline bool mem_cgroup_under_socket_pressure(struct mem_cgroup *memcg) -{ - return false; -} - static inline void set_shrinker_bit(struct mem_cgroup *memcg, int nid, int shrinker_id) { diff --git a/include/net/proto_memory.h b/include/net/proto_memory.h index 859e63de81c4..8e91a8fa31b5 100644 --- a/include/net/proto_memory.h +++ b/include/net/proto_memory.h @@ -32,7 +32,7 @@ static inline bool sk_under_memory_pressure(const struct sock *sk) return false; if (mem_cgroup_sk_enabled(sk) && - mem_cgroup_under_socket_pressure(sk->sk_memcg)) + mem_cgroup_sk_under_memory_pressure(sk)) return true; return !!READ_ONCE(*sk->sk_prot->memory_pressure); diff --git a/include/net/sock.h b/include/net/sock.h index 3efdf680401d..3bc4d566f7d0 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -2604,6 +2604,23 @@ static inline bool mem_cgroup_sk_enabled(const struct sock *sk) { return mem_cgroup_sockets_enabled && mem_cgroup_from_sk(sk); } + +static inline bool mem_cgroup_sk_under_memory_pressure(const struct sock *sk) +{ + struct mem_cgroup *memcg = mem_cgroup_from_sk(sk); + +#ifdef CONFIG_MEMCG_V1 + if (!cgroup_subsys_on_dfl(memory_cgrp_subsys)) + return !!memcg->tcpmem_pressure; +#endif /* CONFIG_MEMCG_V1 */ + + do { + if (time_before64(get_jiffies_64(), mem_cgroup_get_socket_pressure(memcg))) + return true; + } while ((memcg = parent_mem_cgroup(memcg))); + + return false; +} #else static inline struct mem_cgroup *mem_cgroup_from_sk(const struct sock *sk) { @@ -2614,6 +2631,11 @@ static inline bool mem_cgroup_sk_enabled(const struct sock *sk) { return false; } + +static inline bool mem_cgroup_sk_under_memory_pressure(const struct sock *sk) +{ + return false; +} #endif static inline long sock_rcvtimeo(const struct sock *sk, bool noblock) diff --git a/include/net/tcp.h b/include/net/tcp.h index 9f01b6be6444..2936b8175950 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -276,7 +276,7 @@ extern unsigned long tcp_memory_pressure; static inline bool tcp_under_memory_pressure(const struct sock *sk) { if (mem_cgroup_sk_enabled(sk) && - mem_cgroup_under_socket_pressure(sk->sk_memcg)) + mem_cgroup_sk_under_memory_pressure(sk)) return true; return READ_ONCE(tcp_memory_pressure); From bf64002c94fc330b996bc438f3d1b6bd3d781659 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Fri, 15 Aug 2025 20:16:18 +0000 Subject: [PATCH 01516/11391] net: Define sk_memcg under CONFIG_MEMCG. Except for sk_clone_lock(), all accesses to sk->sk_memcg is done under CONFIG_MEMCG. As a bonus, let's define sk->sk_memcg under CONFIG_MEMCG. Signed-off-by: Kuniyuki Iwashima Reviewed-by: Eric Dumazet Acked-by: Roman Gushchin Acked-by: Shakeel Butt Link: https://patch.msgid.link/20250815201712.1745332-11-kuniyu@google.com Signed-off-by: Jakub Kicinski --- include/net/sock.h | 2 ++ net/core/sock.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/include/net/sock.h b/include/net/sock.h index 3bc4d566f7d0..1c49ea13af4a 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -443,7 +443,9 @@ struct sock { __cacheline_group_begin(sock_read_rxtx); int sk_err; struct socket *sk_socket; +#ifdef CONFIG_MEMCG struct mem_cgroup *sk_memcg; +#endif #ifdef CONFIG_XFRM struct xfrm_policy __rcu *sk_policy[2]; #endif diff --git a/net/core/sock.c b/net/core/sock.c index 5537ca263858..ab6953d295df 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -2512,8 +2512,10 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority) sock_reset_flag(newsk, SOCK_DONE); +#ifdef CONFIG_MEMCG /* sk->sk_memcg will be populated at accept() time */ newsk->sk_memcg = NULL; +#endif cgroup_sk_clone(&newsk->sk_cgrp_data); @@ -4452,7 +4454,9 @@ static int __init sock_struct_check(void) CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_read_rxtx, sk_err); CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_read_rxtx, sk_socket); +#ifdef CONFIG_MEMCG CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_read_rxtx, sk_memcg); +#endif CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_write_rxtx, sk_lock); CACHELINE_ASSERT_GROUP_MEMBER(struct sock, sock_write_rxtx, sk_reserved_mem); From cb7cc0cfb38cf50c902caadee0e0e87fc38490aa Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 19 Aug 2025 08:39:50 -0700 Subject: [PATCH 01517/11391] scsi: ufs: core: Only collect timestamps if monitoring is enabled Every ktime_get() call in the hot path has a measurable impact on IOPS. Hence, only collect timestamps if the monitoring functionality is enabled. See also commit 1d8613a23f3c ("scsi: ufs: core: Introduce HBA performance monitor sysfs nodes"). Cc: Can Guo Cc: Bean Huo Cc: Daejun Park Reviewed-by: Peter Wang Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20250819153958.2255907-1-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index daae452a1d25..ca6a0f8ccbea 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -606,10 +606,12 @@ void ufshcd_print_tr(struct ufs_hba *hba, int tag, bool pr_prdt) lrbp = &hba->lrb[tag]; - dev_err(hba->dev, "UPIU[%d] - issue time %lld us\n", - tag, div_u64(lrbp->issue_time_stamp_local_clock, 1000)); - dev_err(hba->dev, "UPIU[%d] - complete time %lld us\n", - tag, div_u64(lrbp->compl_time_stamp_local_clock, 1000)); + if (hba->monitor.enabled) { + dev_err(hba->dev, "UPIU[%d] - issue time %lld us\n", tag, + div_u64(lrbp->issue_time_stamp_local_clock, 1000)); + dev_err(hba->dev, "UPIU[%d] - complete time %lld us\n", tag, + div_u64(lrbp->compl_time_stamp_local_clock, 1000)); + } dev_err(hba->dev, "UPIU[%d] - Transfer Request Descriptor phys@0x%llx\n", tag, (u64)lrbp->utrd_dma_addr); @@ -2356,10 +2358,12 @@ void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag, struct ufshcd_lrb *lrbp = &hba->lrb[task_tag]; unsigned long flags; - lrbp->issue_time_stamp = ktime_get(); - lrbp->issue_time_stamp_local_clock = local_clock(); - lrbp->compl_time_stamp = ktime_set(0, 0); - lrbp->compl_time_stamp_local_clock = 0; + if (hba->monitor.enabled) { + lrbp->issue_time_stamp = ktime_get(); + lrbp->issue_time_stamp_local_clock = local_clock(); + lrbp->compl_time_stamp = ktime_set(0, 0); + lrbp->compl_time_stamp_local_clock = 0; + } ufshcd_add_command_trace(hba, task_tag, UFS_CMD_SEND); if (lrbp->cmd) ufshcd_clk_scaling_start_busy(hba); @@ -5619,8 +5623,10 @@ void ufshcd_compl_one_cqe(struct ufs_hba *hba, int task_tag, enum utp_ocs ocs; lrbp = &hba->lrb[task_tag]; - lrbp->compl_time_stamp = ktime_get(); - lrbp->compl_time_stamp_local_clock = local_clock(); + if (hba->monitor.enabled) { + lrbp->compl_time_stamp = ktime_get(); + lrbp->compl_time_stamp_local_clock = local_clock(); + } cmd = lrbp->cmd; if (cmd) { if (unlikely(ufshcd_should_inform_monitor(hba, lrbp))) From b5940feda3dc7a12133c6589e463d2b3b6c7fe96 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 19 Aug 2025 08:43:49 -0700 Subject: [PATCH 01518/11391] scsi: ufs: core: Reduce the size of struct ufshcd_lrb The size of the data structures that are used in the hot path matters for performance (IOPS). Hence this patch that reduces the size of struct ufshcd_lrb on 64-bit systems by 16 bytes. The size of this data structure is reduced from 152 to 136 bytes. Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20250819154356.2256952-1-bvanassche@acm.org Reviewed-by: Peter Wang Signed-off-by: Martin K. Petersen --- include/ufs/ufshcd.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 1d3943777584..30ff169878dc 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -167,13 +167,13 @@ struct ufs_pm_lvl_states { * @task_tag: Task tag of the command * @lun: LUN of the command * @intr_cmd: Interrupt command (doesn't participate in interrupt aggregation) + * @req_abort_skip: skip request abort task flag * @issue_time_stamp: time stamp for debug purposes (CLOCK_MONOTONIC) * @issue_time_stamp_local_clock: time stamp for debug purposes (local_clock) * @compl_time_stamp: time stamp for statistics (CLOCK_MONOTONIC) * @compl_time_stamp_local_clock: time stamp for debug purposes (local_clock) * @crypto_key_slot: the key slot to use for inline crypto (-1 if none) * @data_unit_num: the data unit number for the first block for inline crypto - * @req_abort_skip: skip request abort task flag */ struct ufshcd_lrb { struct utp_transfer_req_desc *utr_descriptor_ptr; @@ -193,6 +193,7 @@ struct ufshcd_lrb { int task_tag; u8 lun; /* UPIU LUN id field is only 8-bit wide */ bool intr_cmd; + bool req_abort_skip; ktime_t issue_time_stamp; u64 issue_time_stamp_local_clock; ktime_t compl_time_stamp; @@ -201,8 +202,6 @@ struct ufshcd_lrb { int crypto_key_slot; u64 data_unit_num; #endif - - bool req_abort_skip; }; /** From 0138c16872bdda6b5113dec1cde5f93815c9f75c Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Fri, 15 Aug 2025 20:16:04 +0800 Subject: [PATCH 01519/11391] scsi: hpsa: use min()/min_t() to improve code Use min()/min_t() to reduce the code in complete_scsi_command() and hpsa_vpd_page_supported(), and improve readability. Signed-off-by: Qianfeng Rong Link: https://lore.kernel.org/r/20250815121609.384914-3-rongqianfeng@vivo.com Acked-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/hpsa.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 3bb7a1d9af53..8738ad757235 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2662,10 +2662,8 @@ static void complete_scsi_command(struct CommandList *cp) case CMD_TARGET_STATUS: cmd->result |= ei->ScsiStatus; /* copy the sense data */ - if (SCSI_SENSE_BUFFERSIZE < sizeof(ei->SenseInfo)) - sense_data_size = SCSI_SENSE_BUFFERSIZE; - else - sense_data_size = sizeof(ei->SenseInfo); + sense_data_size = min_t(unsigned long, SCSI_SENSE_BUFFERSIZE, + sizeof(ei->SenseInfo)); if (ei->SenseLen < sense_data_size) sense_data_size = ei->SenseLen; memcpy(cmd->sense_buffer, ei->SenseInfo, sense_data_size); @@ -3628,10 +3626,7 @@ static bool hpsa_vpd_page_supported(struct ctlr_info *h, if (rc != 0) goto exit_unsupported; pages = buf[3]; - if ((pages + HPSA_VPD_HEADER_SZ) <= 255) - bufsize = pages + HPSA_VPD_HEADER_SZ; - else - bufsize = 255; + bufsize = min(pages + HPSA_VPD_HEADER_SZ, 255); /* Get the whole VPD page list */ rc = hpsa_scsi_do_inquiry(h, scsi3addr, From e79aa10e288c617c12ac4eb3fe7962f5c644b8fe Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Fri, 15 Aug 2025 20:16:05 +0800 Subject: [PATCH 01520/11391] scsi: lpfc: use min() to improve code Use min_t() to reduce the code in lpfc_sli4_driver_resource_setup() and lpfc_nvme_prep_io_cmd(), and improve readability. Signed-off-by: Qianfeng Rong Link: https://lore.kernel.org/r/20250815121609.384914-4-rongqianfeng@vivo.com Reviewed-by: Justin Tee Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_init.c | 5 +---- drivers/scsi/lpfc/lpfc_nvme.c | 8 ++------ 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 4081d2a358ee..ad8a85c65bfd 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -8300,10 +8300,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) phba->cfg_total_seg_cnt, phba->cfg_scsi_seg_cnt, phba->cfg_nvme_seg_cnt); - if (phba->cfg_sg_dma_buf_size < SLI4_PAGE_SIZE) - i = phba->cfg_sg_dma_buf_size; - else - i = SLI4_PAGE_SIZE; + i = min(phba->cfg_sg_dma_buf_size, SLI4_PAGE_SIZE); phba->lpfc_sg_dma_buf_pool = dma_pool_create("lpfc_sg_dma_buf_pool", diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index a6647dd360d1..e6f632521cff 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -1234,12 +1234,8 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport, if ((phba->cfg_nvme_enable_fb) && test_bit(NLP_FIRSTBURST, &pnode->nlp_flag)) { req_len = lpfc_ncmd->nvmeCmd->payload_length; - if (req_len < pnode->nvme_fb_size) - wqe->fcp_iwrite.initial_xfer_len = - req_len; - else - wqe->fcp_iwrite.initial_xfer_len = - pnode->nvme_fb_size; + wqe->fcp_iwrite.initial_xfer_len = min(req_len, + pnode->nvme_fb_size); } else { wqe->fcp_iwrite.initial_xfer_len = 0; } From edb35b1ffc686fd9b5a91902f034eb9f4d2c9f6b Mon Sep 17 00:00:00 2001 From: Thomas Fourier Date: Fri, 25 Jul 2025 10:31:06 +0200 Subject: [PATCH 01521/11391] scsi: myrs: Fix dma_alloc_coherent() error check Check for NULL return value with dma_alloc_coherent(), because DMA address is not always set by dma_alloc_coherent() on failure. Fixes: 77266186397c ("scsi: myrs: Add Mylex RAID controller (SCSI interface)") Signed-off-by: Thomas Fourier Link: https://lore.kernel.org/r/20250725083112.43975-2-fourier.thomas@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/myrs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/myrs.c b/drivers/scsi/myrs.c index 95af3bb03834..a58abd796603 100644 --- a/drivers/scsi/myrs.c +++ b/drivers/scsi/myrs.c @@ -498,14 +498,14 @@ static bool myrs_enable_mmio_mbox(struct myrs_hba *cs, /* Temporary dma mapping, used only in the scope of this function */ mbox = dma_alloc_coherent(&pdev->dev, sizeof(union myrs_cmd_mbox), &mbox_addr, GFP_KERNEL); - if (dma_mapping_error(&pdev->dev, mbox_addr)) + if (!mbox) return false; /* These are the base addresses for the command memory mailbox array */ cs->cmd_mbox_size = MYRS_MAX_CMD_MBOX * sizeof(union myrs_cmd_mbox); cmd_mbox = dma_alloc_coherent(&pdev->dev, cs->cmd_mbox_size, &cs->cmd_mbox_addr, GFP_KERNEL); - if (dma_mapping_error(&pdev->dev, cs->cmd_mbox_addr)) { + if (!cmd_mbox) { dev_err(&pdev->dev, "Failed to map command mailbox\n"); goto out_free; } @@ -520,7 +520,7 @@ static bool myrs_enable_mmio_mbox(struct myrs_hba *cs, cs->stat_mbox_size = MYRS_MAX_STAT_MBOX * sizeof(struct myrs_stat_mbox); stat_mbox = dma_alloc_coherent(&pdev->dev, cs->stat_mbox_size, &cs->stat_mbox_addr, GFP_KERNEL); - if (dma_mapping_error(&pdev->dev, cs->stat_mbox_addr)) { + if (!stat_mbox) { dev_err(&pdev->dev, "Failed to map status mailbox\n"); goto out_free; } @@ -533,7 +533,7 @@ static bool myrs_enable_mmio_mbox(struct myrs_hba *cs, cs->fwstat_buf = dma_alloc_coherent(&pdev->dev, sizeof(struct myrs_fwstat), &cs->fwstat_addr, GFP_KERNEL); - if (dma_mapping_error(&pdev->dev, cs->fwstat_addr)) { + if (!cs->fwstat_buf) { dev_err(&pdev->dev, "Failed to map firmware health buffer\n"); cs->fwstat_buf = NULL; goto out_free; From 36def5f2b958113b9009144fb54b0cee2c11afb5 Mon Sep 17 00:00:00 2001 From: Christoph Stoidner Date: Sat, 24 May 2025 13:23:15 +0200 Subject: [PATCH 01522/11391] arm64: dts: freescale: imx93-phycore-som: Delay the phy reset by a gpio According to the datasheet the phy needs to be held in reset until the reference clock got stable. Even though no issue was observed, fix this as the software should always comply with the specification. Use gpio4 23, which is connected to the phy reset pin. On the same pin RX_ER was used before, but this signal is optional and can be dropped. Note: This comes into effect with the phyCOREs SOM hardware revision 4. In revisions before, this gpio is not connected, and the phy reset is managed with the global hardware reset circuit. Signed-off-by: Christoph Stoidner Reviewed-by: Andrew Lunn Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx93-phycore-som.dtsi | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/imx93-phycore-som.dtsi b/arch/arm64/boot/dts/freescale/imx93-phycore-som.dtsi index c6f5aa38ebf9..89552ae70660 100644 --- a/arch/arm64/boot/dts/freescale/imx93-phycore-som.dtsi +++ b/arch/arm64/boot/dts/freescale/imx93-phycore-som.dtsi @@ -85,6 +85,8 @@ mdio: mdio { ethphy1: ethernet-phy@1 { compatible = "ethernet-phy-ieee802.3-c22"; reg = <1>; + reset-gpios = <&gpio4 23 GPIO_ACTIVE_HIGH>; + reset-assert-us = <30>; }; }; }; @@ -206,14 +208,17 @@ pinctrl_fec: fecgrp { fsl,pins = < MX93_PAD_ENET2_MDC__ENET1_MDC 0x50e MX93_PAD_ENET2_MDIO__ENET1_MDIO 0x502 - MX93_PAD_ENET2_RD0__ENET1_RGMII_RD0 0x57e - MX93_PAD_ENET2_RD1__ENET1_RGMII_RD1 0x57e - MX93_PAD_ENET2_RXC__ENET1_RX_ER 0x5fe + /* the three pins below are connected to PHYs straps, + * that is what the pull-up/down setting is for. + */ + MX93_PAD_ENET2_RD0__ENET1_RGMII_RD0 0x37e + MX93_PAD_ENET2_RD1__ENET1_RGMII_RD1 0x37e MX93_PAD_ENET2_RX_CTL__ENET1_RGMII_RX_CTL 0x57e MX93_PAD_ENET2_TD0__ENET1_RGMII_TD0 0x50e MX93_PAD_ENET2_TD1__ENET1_RGMII_TD1 0x50e MX93_PAD_ENET2_TX_CTL__ENET1_RGMII_TX_CTL 0x50e MX93_PAD_ENET2_TD2__ENET1_TX_CLK 0x4000050e + MX93_PAD_ENET2_RXC__GPIO4_IO23 0x51e >; }; From 490a9591b5feb40b91052bbb0e6bc038ed8490ff Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 18 Aug 2025 13:54:22 -0700 Subject: [PATCH 01523/11391] selftests: net: Explicitly enable CONFIG_CRYPTO_SHA1 for IPsec xfrm_policy.sh, nft_flowtable.sh, and vrf-xfrm-tests.sh use 'ip xfrm' with SHA-1, either 'auth sha1' or 'auth-trunc hmac(sha1)'. That requires CONFIG_CRYPTO_SHA1, which CONFIG_INET_ESP intentionally doesn't select (as per its help text). Previously, the config for these tests relied on CONFIG_CRYPTO_SHA1 being selected by the unrelated option CONFIG_IP_SCTP. Since CONFIG_IP_SCTP is being changed to no longer do that, instead add CONFIG_CRYPTO_SHA1 to the configs explicitly. Reported-by: Paolo Abeni Closes: https://lore.kernel.org/r/766e4508-aaba-4cdc-92b4-e116e52ae13b@redhat.com Suggested-by: Florian Westphal Acked-by: Xin Long Signed-off-by: Eric Biggers Link: https://patch.msgid.link/20250818205426.30222-2-ebiggers@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/config | 1 + tools/testing/selftests/net/netfilter/config | 1 + 2 files changed, 2 insertions(+) diff --git a/tools/testing/selftests/net/config b/tools/testing/selftests/net/config index c24417d0047b..d548611e2698 100644 --- a/tools/testing/selftests/net/config +++ b/tools/testing/selftests/net/config @@ -26,6 +26,7 @@ CONFIG_IFB=y CONFIG_INET_DIAG=y CONFIG_INET_ESP=y CONFIG_INET_ESP_OFFLOAD=y +CONFIG_CRYPTO_SHA1=y CONFIG_NET_FOU=y CONFIG_NET_FOU_IP_TUNNELS=y CONFIG_NETFILTER=y diff --git a/tools/testing/selftests/net/netfilter/config b/tools/testing/selftests/net/netfilter/config index 79d5b33966ba..305e46b819cb 100644 --- a/tools/testing/selftests/net/netfilter/config +++ b/tools/testing/selftests/net/netfilter/config @@ -13,6 +13,7 @@ CONFIG_BRIDGE_VLAN_FILTERING=y CONFIG_CGROUP_BPF=y CONFIG_DUMMY=m CONFIG_INET_ESP=m +CONFIG_CRYPTO_SHA1=m CONFIG_IP_NF_MATCH_RPFILTER=m CONFIG_IP6_NF_MATCH_RPFILTER=m CONFIG_IP_NF_IPTABLES=m From dd91c79e4f58fbe2898dac84858033700e0e99fb Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 18 Aug 2025 13:54:23 -0700 Subject: [PATCH 01524/11391] sctp: Fix MAC comparison to be constant-time To prevent timing attacks, MACs need to be compared in constant time. Use the appropriate helper function for this. Fixes: bbd0d59809f9 ("[SCTP]: Implement the receive and verification of AUTH chunk") Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Signed-off-by: Eric Biggers Link: https://patch.msgid.link/20250818205426.30222-3-ebiggers@kernel.org Signed-off-by: Jakub Kicinski --- net/sctp/sm_make_chunk.c | 3 ++- net/sctp/sm_statefuns.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 3ead591c72fd..d099b605e44a 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -31,6 +31,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include #include @@ -1788,7 +1789,7 @@ struct sctp_association *sctp_unpack_cookie( } } - if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) { + if (crypto_memneq(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) { *error = -SCTP_IERROR_BAD_SIG; goto fail; } diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index a0524ba8d787..d4d5b14b49b3 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -30,6 +30,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include #include #include @@ -4416,7 +4417,7 @@ static enum sctp_ierror sctp_sf_authenticate( sh_key, GFP_ATOMIC); /* Discard the packet if the digests do not match */ - if (memcmp(save_digest, digest, sig_len)) { + if (crypto_memneq(save_digest, digest, sig_len)) { kfree(save_digest); return SCTP_IERROR_BAD_SIG; } From bf40785fa437c1752117df2edb3220e9c37d98a6 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 18 Aug 2025 13:54:24 -0700 Subject: [PATCH 01525/11391] sctp: Use HMAC-SHA1 and HMAC-SHA256 library for chunk authentication For SCTP chunk authentication, use the HMAC-SHA1 and HMAC-SHA256 library functions instead of crypto_shash. This is simpler and faster. There's no longer any need to pre-allocate 'crypto_shash' objects; the SCTP code now simply calls into the HMAC code directly. As part of this, make SCTP always support both HMAC-SHA1 and HMAC-SHA256. Previously, it only guaranteed support for HMAC-SHA1. However, HMAC-SHA256 tended to be supported too anyway, as it was supported if CONFIG_CRYPTO_SHA256 was enabled elsewhere in the kconfig. Acked-by: Xin Long Signed-off-by: Eric Biggers Link: https://patch.msgid.link/20250818205426.30222-4-ebiggers@kernel.org Signed-off-by: Jakub Kicinski --- include/net/sctp/auth.h | 17 ++-- include/net/sctp/constants.h | 4 - include/net/sctp/structs.h | 5 -- net/sctp/Kconfig | 16 ++-- net/sctp/auth.c | 166 ++++++----------------------------- net/sctp/chunk.c | 3 +- net/sctp/sm_make_chunk.c | 2 +- net/sctp/sm_statefuns.c | 2 +- net/sctp/socket.c | 10 --- 9 files changed, 48 insertions(+), 177 deletions(-) diff --git a/include/net/sctp/auth.h b/include/net/sctp/auth.h index d4b3b2dcd15b..3d5879e08e78 100644 --- a/include/net/sctp/auth.h +++ b/include/net/sctp/auth.h @@ -22,16 +22,11 @@ struct sctp_endpoint; struct sctp_association; struct sctp_authkey; struct sctp_hmacalgo; -struct crypto_shash; -/* - * Define a generic struct that will hold all the info - * necessary for an HMAC transform - */ +/* Defines an HMAC algorithm supported by SCTP chunk authentication */ struct sctp_hmac { - __u16 hmac_id; /* one of the above ids */ - char *hmac_name; /* name for loading */ - __u16 hmac_len; /* length of the signature */ + __u16 hmac_id; /* one of SCTP_AUTH_HMAC_ID_* */ + __u16 hmac_len; /* length of the HMAC value in bytes */ }; /* This is generic structure that containst authentication bytes used @@ -78,9 +73,9 @@ int sctp_auth_asoc_copy_shkeys(const struct sctp_endpoint *ep, struct sctp_association *asoc, gfp_t gfp); int sctp_auth_init_hmacs(struct sctp_endpoint *ep, gfp_t gfp); -void sctp_auth_destroy_hmacs(struct crypto_shash *auth_hmacs[]); -struct sctp_hmac *sctp_auth_get_hmac(__u16 hmac_id); -struct sctp_hmac *sctp_auth_asoc_get_hmac(const struct sctp_association *asoc); +const struct sctp_hmac *sctp_auth_get_hmac(__u16 hmac_id); +const struct sctp_hmac * +sctp_auth_asoc_get_hmac(const struct sctp_association *asoc); void sctp_auth_asoc_set_default_hmac(struct sctp_association *asoc, struct sctp_hmac_algo_param *hmacs); int sctp_auth_asoc_verify_hmac_id(const struct sctp_association *asoc, diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h index 5859e0a16a58..8e0f4c4f7750 100644 --- a/include/net/sctp/constants.h +++ b/include/net/sctp/constants.h @@ -417,16 +417,12 @@ enum { SCTP_AUTH_HMAC_ID_RESERVED_0, SCTP_AUTH_HMAC_ID_SHA1, SCTP_AUTH_HMAC_ID_RESERVED_2, -#if defined (CONFIG_CRYPTO_SHA256) || defined (CONFIG_CRYPTO_SHA256_MODULE) SCTP_AUTH_HMAC_ID_SHA256, -#endif __SCTP_AUTH_HMAC_MAX }; #define SCTP_AUTH_HMAC_ID_MAX __SCTP_AUTH_HMAC_MAX - 1 #define SCTP_AUTH_NUM_HMACS __SCTP_AUTH_HMAC_MAX -#define SCTP_SHA1_SIG_SIZE 20 -#define SCTP_SHA256_SIG_SIZE 32 /* SCTP-AUTH, Section 3.2 * The chunk types for INIT, INIT-ACK, SHUTDOWN-COMPLETE and AUTH chunks diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 8a540ad9b509..6be6aec25731 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -1329,11 +1329,6 @@ struct sctp_endpoint { /* rcvbuf acct. policy. */ __u32 rcvbuf_policy; - /* SCTP AUTH: array of the HMACs that will be allocated - * we need this per association so that we don't serialize - */ - struct crypto_shash **auth_hmacs; - /* SCTP-AUTH: hmacs for the endpoint encoded into parameter */ struct sctp_hmac_algo_param *auth_hmacs_list; diff --git a/net/sctp/Kconfig b/net/sctp/Kconfig index 24d5a35ce894..09c77b4d161b 100644 --- a/net/sctp/Kconfig +++ b/net/sctp/Kconfig @@ -7,9 +7,9 @@ menuconfig IP_SCTP tristate "The SCTP Protocol" depends on INET depends on IPV6 || IPV6=n - select CRYPTO - select CRYPTO_HMAC - select CRYPTO_SHA1 + select CRYPTO_LIB_SHA1 + select CRYPTO_LIB_SHA256 + select CRYPTO_LIB_UTILS select NET_CRC32C select NET_UDP_TUNNEL help @@ -79,15 +79,17 @@ config SCTP_COOKIE_HMAC_MD5 bool "Enable optional MD5 hmac cookie generation" help Enable optional MD5 hmac based SCTP cookie generation - select CRYPTO_HMAC if SCTP_COOKIE_HMAC_MD5 - select CRYPTO_MD5 if SCTP_COOKIE_HMAC_MD5 + select CRYPTO + select CRYPTO_HMAC + select CRYPTO_MD5 config SCTP_COOKIE_HMAC_SHA1 bool "Enable optional SHA1 hmac cookie generation" help Enable optional SHA1 hmac based SCTP cookie generation - select CRYPTO_HMAC if SCTP_COOKIE_HMAC_SHA1 - select CRYPTO_SHA1 if SCTP_COOKIE_HMAC_SHA1 + select CRYPTO + select CRYPTO_HMAC + select CRYPTO_SHA1 config INET_SCTP_DIAG depends on INET_DIAG diff --git a/net/sctp/auth.c b/net/sctp/auth.c index c58fffc86a0c..82aad477590e 100644 --- a/net/sctp/auth.c +++ b/net/sctp/auth.c @@ -12,36 +12,37 @@ * Vlad Yasevich */ -#include +#include +#include #include #include -#include #include #include -static struct sctp_hmac sctp_hmac_list[SCTP_AUTH_NUM_HMACS] = { +static const struct sctp_hmac sctp_hmac_list[SCTP_AUTH_NUM_HMACS] = { { /* id 0 is reserved. as all 0 */ .hmac_id = SCTP_AUTH_HMAC_ID_RESERVED_0, }, { .hmac_id = SCTP_AUTH_HMAC_ID_SHA1, - .hmac_name = "hmac(sha1)", - .hmac_len = SCTP_SHA1_SIG_SIZE, + .hmac_len = SHA1_DIGEST_SIZE, }, { /* id 2 is reserved as well */ .hmac_id = SCTP_AUTH_HMAC_ID_RESERVED_2, }, -#if IS_ENABLED(CONFIG_CRYPTO_SHA256) { .hmac_id = SCTP_AUTH_HMAC_ID_SHA256, - .hmac_name = "hmac(sha256)", - .hmac_len = SCTP_SHA256_SIG_SIZE, + .hmac_len = SHA256_DIGEST_SIZE, } -#endif }; +static bool sctp_hmac_supported(__u16 hmac_id) +{ + return hmac_id < ARRAY_SIZE(sctp_hmac_list) && + sctp_hmac_list[hmac_id].hmac_len != 0; +} void sctp_auth_key_put(struct sctp_auth_bytes *key) { @@ -444,76 +445,7 @@ struct sctp_shared_key *sctp_auth_get_shkey( return NULL; } -/* - * Initialize all the possible digest transforms that we can use. Right - * now, the supported digests are SHA1 and SHA256. We do this here once - * because of the restrictiong that transforms may only be allocated in - * user context. This forces us to pre-allocated all possible transforms - * at the endpoint init time. - */ -int sctp_auth_init_hmacs(struct sctp_endpoint *ep, gfp_t gfp) -{ - struct crypto_shash *tfm = NULL; - __u16 id; - - /* If the transforms are already allocated, we are done */ - if (ep->auth_hmacs) - return 0; - - /* Allocated the array of pointers to transorms */ - ep->auth_hmacs = kcalloc(SCTP_AUTH_NUM_HMACS, - sizeof(struct crypto_shash *), - gfp); - if (!ep->auth_hmacs) - return -ENOMEM; - - for (id = 0; id < SCTP_AUTH_NUM_HMACS; id++) { - - /* See is we support the id. Supported IDs have name and - * length fields set, so that we can allocated and use - * them. We can safely just check for name, for without the - * name, we can't allocate the TFM. - */ - if (!sctp_hmac_list[id].hmac_name) - continue; - - /* If this TFM has been allocated, we are all set */ - if (ep->auth_hmacs[id]) - continue; - - /* Allocate the ID */ - tfm = crypto_alloc_shash(sctp_hmac_list[id].hmac_name, 0, 0); - if (IS_ERR(tfm)) - goto out_err; - - ep->auth_hmacs[id] = tfm; - } - - return 0; - -out_err: - /* Clean up any successful allocations */ - sctp_auth_destroy_hmacs(ep->auth_hmacs); - ep->auth_hmacs = NULL; - return -ENOMEM; -} - -/* Destroy the hmac tfm array */ -void sctp_auth_destroy_hmacs(struct crypto_shash *auth_hmacs[]) -{ - int i; - - if (!auth_hmacs) - return; - - for (i = 0; i < SCTP_AUTH_NUM_HMACS; i++) { - crypto_free_shash(auth_hmacs[i]); - } - kfree(auth_hmacs); -} - - -struct sctp_hmac *sctp_auth_get_hmac(__u16 hmac_id) +const struct sctp_hmac *sctp_auth_get_hmac(__u16 hmac_id) { return &sctp_hmac_list[hmac_id]; } @@ -521,7 +453,8 @@ struct sctp_hmac *sctp_auth_get_hmac(__u16 hmac_id) /* Get an hmac description information that we can use to build * the AUTH chunk */ -struct sctp_hmac *sctp_auth_asoc_get_hmac(const struct sctp_association *asoc) +const struct sctp_hmac * +sctp_auth_asoc_get_hmac(const struct sctp_association *asoc) { struct sctp_hmac_algo_param *hmacs; __u16 n_elt; @@ -543,26 +476,10 @@ struct sctp_hmac *sctp_auth_asoc_get_hmac(const struct sctp_association *asoc) sizeof(struct sctp_paramhdr)) >> 1; for (i = 0; i < n_elt; i++) { id = ntohs(hmacs->hmac_ids[i]); - - /* Check the id is in the supported range. And - * see if we support the id. Supported IDs have name and - * length fields set, so that we can allocate and use - * them. We can safely just check for name, for without the - * name, we can't allocate the TFM. - */ - if (id > SCTP_AUTH_HMAC_ID_MAX || - !sctp_hmac_list[id].hmac_name) { - id = 0; - continue; - } - - break; + if (sctp_hmac_supported(id)) + return &sctp_hmac_list[id]; } - - if (id == 0) - return NULL; - - return &sctp_hmac_list[id]; + return NULL; } static int __sctp_auth_find_hmacid(__be16 *hmacs, int n_elts, __be16 hmac_id) @@ -606,7 +523,6 @@ int sctp_auth_asoc_verify_hmac_id(const struct sctp_association *asoc, void sctp_auth_asoc_set_default_hmac(struct sctp_association *asoc, struct sctp_hmac_algo_param *hmacs) { - struct sctp_endpoint *ep; __u16 id; int i; int n_params; @@ -617,16 +533,9 @@ void sctp_auth_asoc_set_default_hmac(struct sctp_association *asoc, n_params = (ntohs(hmacs->param_hdr.length) - sizeof(struct sctp_paramhdr)) >> 1; - ep = asoc->ep; for (i = 0; i < n_params; i++) { id = ntohs(hmacs->hmac_ids[i]); - - /* Check the id is in the supported range */ - if (id > SCTP_AUTH_HMAC_ID_MAX) - continue; - - /* If this TFM has been allocated, use this id */ - if (ep->auth_hmacs[id]) { + if (sctp_hmac_supported(id)) { asoc->default_hmac_id = id; break; } @@ -709,10 +618,9 @@ void sctp_auth_calculate_hmac(const struct sctp_association *asoc, struct sctp_shared_key *ep_key, gfp_t gfp) { struct sctp_auth_bytes *asoc_key; - struct crypto_shash *tfm; __u16 key_id, hmac_id; - unsigned char *end; int free_key = 0; + size_t data_len; __u8 *digest; /* Extract the info we need: @@ -733,19 +641,17 @@ void sctp_auth_calculate_hmac(const struct sctp_association *asoc, free_key = 1; } - /* set up scatter list */ - end = skb_tail_pointer(skb); - - tfm = asoc->ep->auth_hmacs[hmac_id]; - + data_len = skb_tail_pointer(skb) - (unsigned char *)auth; digest = (u8 *)(&auth->auth_hdr + 1); - if (crypto_shash_setkey(tfm, &asoc_key->data[0], asoc_key->len)) - goto free; + if (hmac_id == SCTP_AUTH_HMAC_ID_SHA1) { + hmac_sha1_usingrawkey(asoc_key->data, asoc_key->len, + (const u8 *)auth, data_len, digest); + } else { + WARN_ON_ONCE(hmac_id != SCTP_AUTH_HMAC_ID_SHA256); + hmac_sha256_usingrawkey(asoc_key->data, asoc_key->len, + (const u8 *)auth, data_len, digest); + } - crypto_shash_tfm_digest(tfm, (u8 *)auth, end - (unsigned char *)auth, - digest); - -free: if (free_key) sctp_auth_key_put(asoc_key); } @@ -788,14 +694,11 @@ int sctp_auth_ep_set_hmacs(struct sctp_endpoint *ep, for (i = 0; i < hmacs->shmac_num_idents; i++) { id = hmacs->shmac_idents[i]; - if (id > SCTP_AUTH_HMAC_ID_MAX) + if (!sctp_hmac_supported(id)) return -EOPNOTSUPP; if (SCTP_AUTH_HMAC_ID_SHA1 == id) has_sha1 = 1; - - if (!sctp_hmac_list[id].hmac_name) - return -EOPNOTSUPP; } if (!has_sha1) @@ -1021,8 +924,6 @@ int sctp_auth_deact_key_id(struct sctp_endpoint *ep, int sctp_auth_init(struct sctp_endpoint *ep, gfp_t gfp) { - int err = -ENOMEM; - /* Allocate space for HMACS and CHUNKS authentication * variables. There are arrays that we encode directly * into parameters to make the rest of the operations easier. @@ -1060,13 +961,6 @@ int sctp_auth_init(struct sctp_endpoint *ep, gfp_t gfp) ep->auth_chunk_list = auth_chunks; } - /* Allocate and initialize transorms arrays for supported - * HMACs. - */ - err = sctp_auth_init_hmacs(ep, gfp); - if (err) - goto nomem; - return 0; nomem: @@ -1075,7 +969,7 @@ int sctp_auth_init(struct sctp_endpoint *ep, gfp_t gfp) kfree(ep->auth_chunk_list); ep->auth_hmacs_list = NULL; ep->auth_chunk_list = NULL; - return err; + return -ENOMEM; } void sctp_auth_free(struct sctp_endpoint *ep) @@ -1084,6 +978,4 @@ void sctp_auth_free(struct sctp_endpoint *ep) kfree(ep->auth_chunk_list); ep->auth_hmacs_list = NULL; ep->auth_chunk_list = NULL; - sctp_auth_destroy_hmacs(ep->auth_hmacs); - ep->auth_hmacs = NULL; } diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c index fd4f8243cc35..c655b571ca01 100644 --- a/net/sctp/chunk.c +++ b/net/sctp/chunk.c @@ -184,7 +184,8 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, * DATA. */ if (sctp_auth_send_cid(SCTP_CID_DATA, asoc)) { - struct sctp_hmac *hmac_desc = sctp_auth_asoc_get_hmac(asoc); + const struct sctp_hmac *hmac_desc = + sctp_auth_asoc_get_hmac(asoc); if (hmac_desc) max_data -= SCTP_PAD4(sizeof(struct sctp_auth_chunk) + diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index d099b605e44a..a1a3c8494c5d 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -1320,7 +1320,7 @@ struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc, __u16 key_id) { struct sctp_authhdr auth_hdr; - struct sctp_hmac *hmac_desc; + const struct sctp_hmac *hmac_desc; struct sctp_chunk *retval; /* Get the first hmac that the peer told us to use */ diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index d4d5b14b49b3..4cb8f393434d 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -4362,7 +4362,7 @@ static enum sctp_ierror sctp_sf_authenticate( struct sctp_shared_key *sh_key = NULL; struct sctp_authhdr *auth_hdr; __u8 *save_digest, *digest; - struct sctp_hmac *hmac; + const struct sctp_hmac *hmac; unsigned int sig_len; __u16 key_id; diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 4921416434f9..0292881a847c 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -9581,16 +9581,6 @@ static int sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, if (err) return err; - /* New ep's auth_hmacs should be set if old ep's is set, in case - * that net->sctp.auth_enable has been changed to 0 by users and - * new ep's auth_hmacs couldn't be set in sctp_endpoint_init(). - */ - if (oldsp->ep->auth_hmacs) { - err = sctp_auth_init_hmacs(newsp->ep, GFP_KERNEL); - if (err) - return err; - } - sctp_auto_asconf_init(newsp); /* Move any messages in the old socket's receive queue that are for the From 2f3dd6ec901f29aef5fff3d7a63b1371d67c1760 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 18 Aug 2025 13:54:25 -0700 Subject: [PATCH 01526/11391] sctp: Convert cookie authentication to use HMAC-SHA256 Convert SCTP cookies to use HMAC-SHA256, instead of the previous choice of the legacy algorithms HMAC-MD5 and HMAC-SHA1. Simplify and optimize the code by using the HMAC-SHA256 library instead of crypto_shash, and by preparing the HMAC key when it is generated instead of per-operation. This doesn't break compatibility, since the cookie format is an implementation detail, not part of the SCTP protocol itself. Note that the cookie size doesn't change either. The HMAC field was already 32 bytes, even though previously at most 20 bytes were actually compared. 32 bytes exactly fits an untruncated HMAC-SHA256 value. So, although we could safely truncate the MAC to something slightly shorter, for now just keep the cookie size the same. I also considered SipHash, but that would generate only 8-byte MACs. An 8-byte MAC *might* suffice here. However, there's quite a lot of information in the SCTP cookies: more than in TCP SYN cookies. So absent an analysis that occasional forgeries of all that information is okay in SCTP, I errored on the side of caution. Remove HMAC-MD5 and HMAC-SHA1 as options, since the new HMAC-SHA256 option is just better. It's faster as well as more secure. For example, benchmarking on x86_64, cookie authentication is now nearly 3x as fast as the previous default choice and implementation of HMAC-MD5. Also just make the kernel always support cookie authentication if SCTP is supported at all, rather than making it optional in the build. (It was sort of optional before, but it didn't really work properly. E.g., a kernel with CONFIG_SCTP_COOKIE_HMAC_MD5=n still supported HMAC-MD5 cookie authentication if CONFIG_CRYPTO_HMAC and CONFIG_CRYPTO_MD5 happened to be enabled in the kconfig for other reasons.) Acked-by: Xin Long Signed-off-by: Eric Biggers Link: https://patch.msgid.link/20250818205426.30222-5-ebiggers@kernel.org Signed-off-by: Jakub Kicinski --- Documentation/networking/ip-sysctl.rst | 11 ++--- include/net/netns/sctp.h | 4 +- include/net/sctp/constants.h | 5 +-- include/net/sctp/structs.h | 28 +++---------- net/sctp/Kconfig | 43 +++++-------------- net/sctp/endpointola.c | 23 ++++++----- net/sctp/protocol.c | 11 ++--- net/sctp/sm_make_chunk.c | 57 ++++++++------------------ net/sctp/socket.c | 31 +------------- net/sctp/sysctl.c | 55 +++++++++++-------------- 10 files changed, 80 insertions(+), 188 deletions(-) diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst index 9756d16e3df1..3d6782683eee 100644 --- a/Documentation/networking/ip-sysctl.rst +++ b/Documentation/networking/ip-sysctl.rst @@ -3508,16 +3508,13 @@ cookie_hmac_alg - STRING a listening sctp socket to a connecting client in the INIT-ACK chunk. Valid values are: - * md5 - * sha1 + * sha256 * none - Ability to assign md5 or sha1 as the selected alg is predicated on the - configuration of those algorithms at build time (CONFIG_CRYPTO_MD5 and - CONFIG_CRYPTO_SHA1). + md5 and sha1 are also accepted for backwards compatibility, but cause + sha256 to be selected. - Default: Dependent on configuration. MD5 if available, else SHA1 if - available, else none. + Default: sha256 rcvbuf_policy - INTEGER Determines if the receive buffer is attributed to the socket or to diff --git a/include/net/netns/sctp.h b/include/net/netns/sctp.h index d25cd7a9c5ff..c0f97f36389e 100644 --- a/include/net/netns/sctp.h +++ b/include/net/netns/sctp.h @@ -75,8 +75,8 @@ struct netns_sctp { /* Whether Cookie Preservative is enabled(1) or not(0) */ int cookie_preserve_enable; - /* The namespace default hmac alg */ - char *sctp_hmac_alg; + /* Whether cookie authentication is enabled(1) or not(0) */ + int cookie_auth_enable; /* Valid.Cookie.Life - 60 seconds */ unsigned int valid_cookie_life; diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h index 8e0f4c4f7750..ae3376ba0b99 100644 --- a/include/net/sctp/constants.h +++ b/include/net/sctp/constants.h @@ -296,9 +296,8 @@ enum { SCTP_MAX_GABS = 16 }; */ #define SCTP_DEFAULT_MINSEGMENT 512 /* MTU size ... if no mtu disc */ -#define SCTP_SECRET_SIZE 32 /* Number of octets in a 256 bits. */ - -#define SCTP_SIGNATURE_SIZE 20 /* size of a SLA-1 signature */ +#define SCTP_COOKIE_KEY_SIZE 32 /* size of cookie HMAC key */ +#define SCTP_COOKIE_MAC_SIZE 32 /* size of HMAC field in cookies */ #define SCTP_COOKIE_MULTIPLE 32 /* Pad out our cookie to make our hash * functions simpler to write. diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 6be6aec25731..2ae390219efd 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -32,6 +32,7 @@ #ifndef __sctp_structs_h__ #define __sctp_structs_h__ +#include #include #include #include @@ -68,7 +69,6 @@ struct sctp_outq; struct sctp_bind_addr; struct sctp_ulpq; struct sctp_ep_common; -struct crypto_shash; struct sctp_stream; @@ -155,10 +155,6 @@ struct sctp_sock { /* PF_ family specific functions. */ struct sctp_pf *pf; - /* Access to HMAC transform. */ - struct crypto_shash *hmac; - char *sctp_hmac_alg; - /* What is our base endpointer? */ struct sctp_endpoint *ep; @@ -227,7 +223,8 @@ struct sctp_sock { frag_interleave:1, recvrcvinfo:1, recvnxtinfo:1, - data_ready_signalled:1; + data_ready_signalled:1, + cookie_auth_enable:1; atomic_t pd_mode; @@ -335,7 +332,7 @@ struct sctp_cookie { /* The format of our cookie that we send to our peer. */ struct sctp_signed_cookie { - __u8 signature[SCTP_SECRET_SIZE]; + __u8 mac[SCTP_COOKIE_MAC_SIZE]; __u32 __pad; /* force sctp_cookie alignment to 64 bits */ struct sctp_cookie c; } __packed; @@ -1307,22 +1304,9 @@ struct sctp_endpoint { /* This is really a list of struct sctp_association entries. */ struct list_head asocs; - /* Secret Key: A secret key used by this endpoint to compute - * the MAC. This SHOULD be a cryptographic quality - * random number with a sufficient length. - * Discussion in [RFC1750] can be helpful in - * selection of the key. - */ - __u8 secret_key[SCTP_SECRET_SIZE]; + /* Cookie authentication key used by this endpoint */ + struct hmac_sha256_key cookie_auth_key; - /* digest: This is a digest of the sctp cookie. This field is - * only used on the receive path when we try to validate - * that the cookie has not been tampered with. We put - * this here so we pre-allocate this once and can re-use - * on every receive. - */ - __u8 *digest; - /* sendbuf acct. policy. */ __u32 sndbuf_policy; diff --git a/net/sctp/Kconfig b/net/sctp/Kconfig index 09c77b4d161b..e947646a380c 100644 --- a/net/sctp/Kconfig +++ b/net/sctp/Kconfig @@ -49,48 +49,25 @@ config SCTP_DBG_OBJCNT 'cat /proc/net/sctp/sctp_dbg_objcnt' If unsure, say N + choice - prompt "Default SCTP cookie HMAC encoding" - default SCTP_DEFAULT_COOKIE_HMAC_MD5 + prompt "Default SCTP cookie authentication method" + default SCTP_DEFAULT_COOKIE_HMAC_SHA256 help - This option sets the default sctp cookie hmac algorithm - when in doubt select 'md5' + This option sets the default SCTP cookie authentication method, for + when a method hasn't been explicitly selected via the + net.sctp.cookie_hmac_alg sysctl. -config SCTP_DEFAULT_COOKIE_HMAC_MD5 - bool "Enable optional MD5 hmac cookie generation" - help - Enable optional MD5 hmac based SCTP cookie generation - select SCTP_COOKIE_HMAC_MD5 + If unsure, choose the default (HMAC-SHA256). -config SCTP_DEFAULT_COOKIE_HMAC_SHA1 - bool "Enable optional SHA1 hmac cookie generation" - help - Enable optional SHA1 hmac based SCTP cookie generation - select SCTP_COOKIE_HMAC_SHA1 +config SCTP_DEFAULT_COOKIE_HMAC_SHA256 + bool "HMAC-SHA256" config SCTP_DEFAULT_COOKIE_HMAC_NONE - bool "Use no hmac alg in SCTP cookie generation" - help - Use no hmac algorithm in SCTP cookie generation + bool "None" endchoice -config SCTP_COOKIE_HMAC_MD5 - bool "Enable optional MD5 hmac cookie generation" - help - Enable optional MD5 hmac based SCTP cookie generation - select CRYPTO - select CRYPTO_HMAC - select CRYPTO_MD5 - -config SCTP_COOKIE_HMAC_SHA1 - bool "Enable optional SHA1 hmac cookie generation" - help - Enable optional SHA1 hmac based SCTP cookie generation - select CRYPTO - select CRYPTO_HMAC - select CRYPTO_SHA1 - config INET_SCTP_DIAG depends on INET_DIAG def_tristate INET_DIAG diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 7e77b450697c..31e989dfe846 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -35,6 +35,15 @@ /* Forward declarations for internal helpers. */ static void sctp_endpoint_bh_rcv(struct work_struct *work); +static void gen_cookie_auth_key(struct hmac_sha256_key *key) +{ + u8 raw_key[SCTP_COOKIE_KEY_SIZE]; + + get_random_bytes(raw_key, sizeof(raw_key)); + hmac_sha256_preparekey(key, raw_key, sizeof(raw_key)); + memzero_explicit(raw_key, sizeof(raw_key)); +} + /* * Initialize the base fields of the endpoint structure. */ @@ -45,10 +54,6 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, struct net *net = sock_net(sk); struct sctp_shared_key *null_key; - ep->digest = kzalloc(SCTP_SIGNATURE_SIZE, gfp); - if (!ep->digest) - return NULL; - ep->asconf_enable = net->sctp.addip_enable; ep->auth_enable = net->sctp.auth_enable; if (ep->auth_enable) { @@ -90,8 +95,8 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, /* Get the receive buffer policy for this endpoint */ ep->rcvbuf_policy = net->sctp.rcvbuf_policy; - /* Initialize the secret key used with cookie. */ - get_random_bytes(ep->secret_key, sizeof(ep->secret_key)); + /* Generate the cookie authentication key. */ + gen_cookie_auth_key(&ep->cookie_auth_key); /* SCTP-AUTH extensions*/ INIT_LIST_HEAD(&ep->endpoint_shared_keys); @@ -118,7 +123,6 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, nomem_shkey: sctp_auth_free(ep); nomem: - kfree(ep->digest); return NULL; } @@ -205,9 +209,6 @@ static void sctp_endpoint_destroy(struct sctp_endpoint *ep) return; } - /* Free the digest buffer */ - kfree(ep->digest); - /* SCTP-AUTH: Free up AUTH releated data such as shared keys * chunks and hmacs arrays that were allocated */ @@ -218,7 +219,7 @@ static void sctp_endpoint_destroy(struct sctp_endpoint *ep) sctp_inq_free(&ep->base.inqueue); sctp_bind_addr_free(&ep->base.bind_addr); - memset(ep->secret_key, 0, sizeof(ep->secret_key)); + memzero_explicit(&ep->cookie_auth_key, sizeof(ep->cookie_auth_key)); sk = ep->base.sk; /* Remove and free the port */ diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index a5ccada55f2b..3b2373b3bd5d 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -1334,14 +1334,9 @@ static int __net_init sctp_defaults_init(struct net *net) /* Whether Cookie Preservative is enabled(1) or not(0) */ net->sctp.cookie_preserve_enable = 1; - /* Default sctp sockets to use md5 as their hmac alg */ -#if defined (CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5) - net->sctp.sctp_hmac_alg = "md5"; -#elif defined (CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1) - net->sctp.sctp_hmac_alg = "sha1"; -#else - net->sctp.sctp_hmac_alg = NULL; -#endif + /* Whether cookie authentication is enabled(1) or not(0) */ + net->sctp.cookie_auth_enable = + !IS_ENABLED(CONFIG_SCTP_DEFAULT_COOKIE_HMAC_NONE); /* Max.Burst - 4 */ net->sctp.max_burst = SCTP_DEFAULT_MAX_BURST; diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index a1a3c8494c5d..2c0017d058d4 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -30,7 +30,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include #include #include #include @@ -1675,8 +1674,10 @@ static struct sctp_cookie_param *sctp_pack_cookie( * out on the network. */ retval = kzalloc(*cookie_len, GFP_ATOMIC); - if (!retval) - goto nodata; + if (!retval) { + *cookie_len = 0; + return NULL; + } cookie = (struct sctp_signed_cookie *) retval->body; @@ -1707,26 +1708,14 @@ static struct sctp_cookie_param *sctp_pack_cookie( memcpy((__u8 *)(cookie + 1) + ntohs(init_chunk->chunk_hdr->length), raw_addrs, addrs_len); - if (sctp_sk(ep->base.sk)->hmac) { - struct crypto_shash *tfm = sctp_sk(ep->base.sk)->hmac; - int err; - - /* Sign the message. */ - err = crypto_shash_setkey(tfm, ep->secret_key, - sizeof(ep->secret_key)) ?: - crypto_shash_tfm_digest(tfm, (u8 *)&cookie->c, bodysize, - cookie->signature); - if (err) - goto free_cookie; + /* Sign the cookie, if cookie authentication is enabled. */ + if (sctp_sk(ep->base.sk)->cookie_auth_enable) { + static_assert(sizeof(cookie->mac) == SHA256_DIGEST_SIZE); + hmac_sha256(&ep->cookie_auth_key, (const u8 *)&cookie->c, + bodysize, cookie->mac); } return retval; - -free_cookie: - kfree(retval); -nodata: - *cookie_len = 0; - return NULL; } /* Unpack the cookie from COOKIE ECHO chunk, recreating the association. */ @@ -1741,7 +1730,6 @@ struct sctp_association *sctp_unpack_cookie( struct sctp_signed_cookie *cookie; struct sk_buff *skb = chunk->skb; struct sctp_cookie *bear_cookie; - __u8 *digest = ep->digest; enum sctp_scope scope; unsigned int len; ktime_t kt; @@ -1771,30 +1759,19 @@ struct sctp_association *sctp_unpack_cookie( cookie = chunk->subh.cookie_hdr; bear_cookie = &cookie->c; - if (!sctp_sk(ep->base.sk)->hmac) - goto no_hmac; + /* Verify the cookie's MAC, if cookie authentication is enabled. */ + if (sctp_sk(ep->base.sk)->cookie_auth_enable) { + u8 mac[SHA256_DIGEST_SIZE]; - /* Check the signature. */ - { - struct crypto_shash *tfm = sctp_sk(ep->base.sk)->hmac; - int err; - - err = crypto_shash_setkey(tfm, ep->secret_key, - sizeof(ep->secret_key)) ?: - crypto_shash_tfm_digest(tfm, (u8 *)bear_cookie, bodysize, - digest); - if (err) { - *error = -SCTP_IERROR_NOMEM; + hmac_sha256(&ep->cookie_auth_key, (const u8 *)bear_cookie, + bodysize, mac); + static_assert(sizeof(cookie->mac) == sizeof(mac)); + if (crypto_memneq(mac, cookie->mac, sizeof(mac))) { + *error = -SCTP_IERROR_BAD_SIG; goto fail; } } - if (crypto_memneq(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) { - *error = -SCTP_IERROR_BAD_SIG; - goto fail; - } - -no_hmac: /* IG Section 2.35.2: * 3) Compare the port numbers and the verification tag contained * within the COOKIE ECHO chunk to the actual port numbers and the diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 0292881a847c..ed8293a34240 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -37,7 +37,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include #include #include #include @@ -4987,7 +4986,7 @@ static int sctp_init_sock(struct sock *sk) sp->default_rcv_context = 0; sp->max_burst = net->sctp.max_burst; - sp->sctp_hmac_alg = net->sctp.sctp_hmac_alg; + sp->cookie_auth_enable = net->sctp.cookie_auth_enable; /* Initialize default setup parameters. These parameters * can be modified with the SCTP_INITMSG socket option or @@ -5079,8 +5078,6 @@ static int sctp_init_sock(struct sock *sk) if (!sp->ep) return -ENOMEM; - sp->hmac = NULL; - sk->sk_destruct = sctp_destruct_sock; SCTP_DBG_OBJCNT_INC(sock); @@ -5117,18 +5114,8 @@ static void sctp_destroy_sock(struct sock *sk) sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); } -/* Triggered when there are no references on the socket anymore */ -static void sctp_destruct_common(struct sock *sk) -{ - struct sctp_sock *sp = sctp_sk(sk); - - /* Free up the HMAC transform. */ - crypto_free_shash(sp->hmac); -} - static void sctp_destruct_sock(struct sock *sk) { - sctp_destruct_common(sk); inet_sock_destruct(sk); } @@ -8530,22 +8517,8 @@ static int sctp_listen_start(struct sock *sk, int backlog) { struct sctp_sock *sp = sctp_sk(sk); struct sctp_endpoint *ep = sp->ep; - struct crypto_shash *tfm = NULL; - char alg[32]; int err; - /* Allocate HMAC for generating cookie. */ - if (!sp->hmac && sp->sctp_hmac_alg) { - sprintf(alg, "hmac(%s)", sp->sctp_hmac_alg); - tfm = crypto_alloc_shash(alg, 0, 0); - if (IS_ERR(tfm)) { - net_info_ratelimited("failed to load transform for %s: %ld\n", - sp->sctp_hmac_alg, PTR_ERR(tfm)); - return -ENOSYS; - } - sctp_sk(sk)->hmac = tfm; - } - /* * If a bind() or sctp_bindx() is not called prior to a listen() * call that allows new associations to be accepted, the system @@ -9561,7 +9534,6 @@ static int sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, * copy. */ newsp->ep = newep; - newsp->hmac = NULL; /* Hook this new socket in to the bind_hash list. */ head = &sctp_port_hashtable[sctp_phashfn(sock_net(oldsk), @@ -9713,7 +9685,6 @@ struct proto sctp_prot = { static void sctp_v6_destruct_sock(struct sock *sk) { - sctp_destruct_common(sk); inet6_sock_destruct(sk); } diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index ee3eac338a9d..19acc57c3ed9 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c @@ -174,7 +174,7 @@ static struct ctl_table sctp_net_table[] = { }, { .procname = "cookie_hmac_alg", - .data = &init_net.sctp.sctp_hmac_alg, + .data = &init_net.sctp.cookie_auth_enable, .maxlen = 8, .mode = 0644, .proc_handler = proc_sctp_do_hmac_alg, @@ -388,10 +388,8 @@ static int proc_sctp_do_hmac_alg(const struct ctl_table *ctl, int write, void *buffer, size_t *lenp, loff_t *ppos) { struct net *net = container_of(ctl->data, struct net, - sctp.sctp_hmac_alg); + sctp.cookie_auth_enable); struct ctl_table tbl; - bool changed = false; - char *none = "none"; char tmp[8] = {0}; int ret; @@ -399,35 +397,28 @@ static int proc_sctp_do_hmac_alg(const struct ctl_table *ctl, int write, if (write) { tbl.data = tmp; - tbl.maxlen = sizeof(tmp); - } else { - tbl.data = net->sctp.sctp_hmac_alg ? : none; - tbl.maxlen = strlen(tbl.data); + tbl.maxlen = sizeof(tmp) - 1; + ret = proc_dostring(&tbl, 1, buffer, lenp, ppos); + if (ret) + return ret; + if (!strcmp(tmp, "sha256") || + /* for backwards compatibility */ + !strcmp(tmp, "md5") || !strcmp(tmp, "sha1")) { + net->sctp.cookie_auth_enable = 1; + return 0; + } + if (!strcmp(tmp, "none")) { + net->sctp.cookie_auth_enable = 0; + return 0; + } + return -EINVAL; } - - ret = proc_dostring(&tbl, write, buffer, lenp, ppos); - if (write && ret == 0) { -#ifdef CONFIG_CRYPTO_MD5 - if (!strncmp(tmp, "md5", 3)) { - net->sctp.sctp_hmac_alg = "md5"; - changed = true; - } -#endif -#ifdef CONFIG_CRYPTO_SHA1 - if (!strncmp(tmp, "sha1", 4)) { - net->sctp.sctp_hmac_alg = "sha1"; - changed = true; - } -#endif - if (!strncmp(tmp, "none", 4)) { - net->sctp.sctp_hmac_alg = NULL; - changed = true; - } - if (!changed) - ret = -EINVAL; - } - - return ret; + if (net->sctp.cookie_auth_enable) + tbl.data = (char *)"sha256"; + else + tbl.data = (char *)"none"; + tbl.maxlen = strlen(tbl.data); + return proc_dostring(&tbl, 0, buffer, lenp, ppos); } static int proc_sctp_do_rto_min(const struct ctl_table *ctl, int write, From d5a253702add0da3e1e19252ae2a251ee24b486d Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 18 Aug 2025 13:54:26 -0700 Subject: [PATCH 01527/11391] sctp: Stop accepting md5 and sha1 for net.sctp.cookie_hmac_alg The upgrade of the cookie authentication algorithm to HMAC-SHA256 kept some backwards compatibility for the net.sctp.cookie_hmac_alg sysctl by still accepting the values 'md5' and 'sha1'. Those algorithms are no longer actually used, but rather those values were just treated as requests to enable cookie authentication. As requested at https://lore.kernel.org/netdev/CADvbK_fmCRARc8VznH8cQa-QKaCOQZ6yFbF=1-VDK=zRqv_cXw@mail.gmail.com/ and https://lore.kernel.org/netdev/20250818084345.708ac796@kernel.org/ , go further and start rejecting 'md5' and 'sha1' completely. Signed-off-by: Eric Biggers Link: https://patch.msgid.link/20250818205426.30222-6-ebiggers@kernel.org Signed-off-by: Jakub Kicinski --- Documentation/networking/ip-sysctl.rst | 3 --- net/sctp/sysctl.c | 4 +--- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst index 3d6782683eee..43badb338d22 100644 --- a/Documentation/networking/ip-sysctl.rst +++ b/Documentation/networking/ip-sysctl.rst @@ -3511,9 +3511,6 @@ cookie_hmac_alg - STRING * sha256 * none - md5 and sha1 are also accepted for backwards compatibility, but cause - sha256 to be selected. - Default: sha256 rcvbuf_policy - INTEGER diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index 19acc57c3ed9..15e7db9a3ab2 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c @@ -401,9 +401,7 @@ static int proc_sctp_do_hmac_alg(const struct ctl_table *ctl, int write, ret = proc_dostring(&tbl, 1, buffer, lenp, ppos); if (ret) return ret; - if (!strcmp(tmp, "sha256") || - /* for backwards compatibility */ - !strcmp(tmp, "md5") || !strcmp(tmp, "sha1")) { + if (!strcmp(tmp, "sha256")) { net->sctp.cookie_auth_enable = 1; return 0; } From 566c269873c642856bceced2add800d2ce8b8c94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Goran=20Ra=C4=91enovi=C4=87?= Date: Wed, 16 Jul 2025 17:48:05 +0200 Subject: [PATCH 01528/11391] dt-bindings: arm: imx8mp: Add Ultratronik Ultra-MACH SBC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document the Ultratronik Ultra-MACH SBC, based on the NXP i.MX8MP SoC. This board is manufactured by Ultratronik GmbH and uses the compatible string "ux,imx8mp-ultra-mach-sbc". Acked-by: Krzysztof Kozlowski Signed-off-by: Goran Rađenović Signed-off-by: Shawn Guo --- Documentation/devicetree/bindings/arm/fsl.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml index a3e9f9e0735a..839f428c9f75 100644 --- a/Documentation/devicetree/bindings/arm/fsl.yaml +++ b/Documentation/devicetree/bindings/arm/fsl.yaml @@ -1112,6 +1112,7 @@ properties: - skov,imx8mp-skov-revb-mi1010ait-1cp1 # SKOV i.MX8MP climate control with 10.1" panel - skov,imx8mp-skov-revc-bd500 # SKOV i.MX8MP climate control with LED frontplate - skov,imx8mp-skov-revc-tian-g07017 # SKOV i.MX8MP climate control with 7" panel + - ultratronik,imx8mp-ultra-mach-sbc # Ultratronik SBC i.MX8MP based board - ysoft,imx8mp-iota2-lumpy # Y Soft i.MX8MP IOTA2 Lumpy Board - const: fsl,imx8mp From e0a4a651f7c8f274be0a937e8ac31c782c4af7ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Goran=20Ra=C4=91enovi=C4=87?= Date: Wed, 16 Jul 2025 17:48:04 +0200 Subject: [PATCH 01529/11391] MAINTAINERS: Add i.MX8MP Ultra-MACH SBC to ULTRATRONIK BOARD SUPPORT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The i.MX8MP-based Ultra-MACH SBC is supported by Ultratronik, and its device tree has been added under arch/arm64/boot/dts/freescale/. To ensure proper maintainer coverage and notification of relevant changes, add the imx8mp-ultra-mach-sbc.dts file to the existing ULTRATRONIK BOARD SUPPORT section. This follows the established pattern already used for the STM32MP157C- based Ultra-FLY SBC. Signed-off-by: Goran Rađenović Signed-off-by: Shawn Guo --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index fe168477caa4..e8ab36b47967 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -25825,6 +25825,7 @@ M: Goran Rađenović M: Börge Strümpfel S: Maintained F: arch/arm/boot/dts/st/stm32mp157c-ultra-fly-sbc.dts +F: arch/arm64/boot/dts/freescale/imx8mp-ultra-mach-sbc.dts UNICODE SUBSYSTEM M: Gabriel Krisman Bertazi From d1c1400bd3b8b436df3bc49d6b420b3184f7dda4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Goran=20Ra=C4=91enovi=C4=87?= Date: Wed, 16 Jul 2025 17:48:06 +0200 Subject: [PATCH 01530/11391] arm64: dts: imx8mp: Add initial support for Ultratronik imx8mp-ultra-mach-sbc board MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add initial device tree support for the Ultratronik Ultra-MACH SBC based on the NXP i.MX8M Plus SoC with 2GB LPDDR4. The board features: - 1 x USB 2.0 Host - 1 x USB 2.0 via USB-C - Debug UART + 1 x UART + 1 x USART - SD card and eMMC support - 2 x Ethernet (RJ45) - HDMI This initial DTS enables basic board support for booting via SD card or eMMC. Signed-off-by: Goran Rađenović Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/Makefile | 1 + .../dts/freescale/imx8mp-ultra-mach-sbc.dts | 907 ++++++++++++++++++ 2 files changed, 908 insertions(+) create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-ultra-mach-sbc.dts diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile index 23535ed47631..6ee4bd67802c 100644 --- a/arch/arm64/boot/dts/freescale/Makefile +++ b/arch/arm64/boot/dts/freescale/Makefile @@ -237,6 +237,7 @@ imx8mp-tx8p-ml81-moduline-display-106-av123z7m-n17-dtbs += imx8mp-tx8p-ml81-modu dtb-$(CONFIG_ARCH_MXC) += imx8mp-tx8p-ml81-moduline-display-106-av101hdt-a10.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-tx8p-ml81-moduline-display-106-av123z7m-n17.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mp-ultra-mach-sbc.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-var-som-symphony.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-venice-gw71xx-2x.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-venice-gw72xx-2x.dtb diff --git a/arch/arm64/boot/dts/freescale/imx8mp-ultra-mach-sbc.dts b/arch/arm64/boot/dts/freescale/imx8mp-ultra-mach-sbc.dts new file mode 100644 index 000000000000..9ecec1a41878 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-ultra-mach-sbc.dts @@ -0,0 +1,907 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2025 Ultratronik + */ + +/dts-v1/; + +#include +#include "imx8mp.dtsi" + +/ { + model = "NXP i.MX8MPlus Ultratronik MMI_A53 board"; + compatible = "ultratronik,imx8mp-ultra-mach-sbc", "fsl,imx8mp"; + + aliases { + ethernet0 = &fec; + ethernet1 = &eqos; + rtc0 = &hwrtc; + rtc1 = &snvs_rtc; + }; + + chosen { + stdout-path = &uart2; + }; + + gpio-sbu-mux { + compatible = "nxp,cbdtu02043", "gpio-sbu-mux"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sbu_mux>; + select-gpios = <&gpio4 20 GPIO_ACTIVE_HIGH>; + enable-gpios = <&gpio2 20 GPIO_ACTIVE_HIGH>; + orientation-switch; + + port { + usb3_data_ss: endpoint { + remote-endpoint = <&typec_con_ss>; + }; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + button-0 { + gpios = <&gpio4 27 GPIO_ACTIVE_LOW>; /* Wakeup */ + label = "Wakeup"; + linux,code = ; + pinctrl-0 = <&pinctrl_gpio_key_wakeup>; + pinctrl-names = "default"; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_leds>; + + led1 { + label = "red"; + gpios = <&gpio4 24 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led2 { + label = "green"; + gpios = <&gpio4 25 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led3 { + label = "yellow"; + gpios = <&gpio4 26 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + }; + + reg_usba_vbus: regulator-usba-vbus { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb1>; + regulator-name = "usb-A-vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio1 12 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_usdhc2_vmmc: regulator-usdhc2 { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>; + regulator-name = "VSD_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; +}; + +&A53_0 { + cpu-supply = <&buck2>; +}; + +&A53_1 { + cpu-supply = <&buck2>; +}; + +&A53_2 { + cpu-supply = <&buck2>; +}; + +&A53_3 { + cpu-supply = <&buck2>; +}; + +&ecspi1 { + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi1 &pinctrl_ecspi1_cs>; + cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>; + status = "okay"; + + slb9670: tpm@0 { + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; + reg = <0>; + spi-max-frequency = <32000000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_slb9670>; + interrupt-parent = <&gpio1>; + interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + }; +}; + +&ecspi2 { + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi2 &pinctrl_ecspi2_cs>; + cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>, + <&gpio1 8 GPIO_ACTIVE_LOW>, + <&gpio1 9 GPIO_ACTIVE_LOW>; + status = "okay"; + + nfc-transceiver@1 { + compatible = "st,st95hf"; + reg = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_nfc>; + spi-max-frequency = <100000>; + interrupt-parent = <&gpio1>; + interrupts = <7 IRQ_TYPE_EDGE_FALLING>; + enable-gpio = <&gpio1 6 GPIO_ACTIVE_HIGH>; + }; +}; + +&eqos { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_eqos>; + phy-mode = "rgmii-id"; + phy-handle = <ðphy0>; + status = "okay"; + + mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + ethphy0: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0x1>; + interrupt-parent = <&gpio4>; + interrupts = <18 IRQ_TYPE_LEVEL_LOW>; + }; + }; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fec>; + phy-mode = "rgmii-id"; + phy-handle = <ðphy1>; + fsl,magic-packet; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethphy1: ethernet-phy@2 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0x2>; + interrupt-parent = <&gpio4>; + interrupts = <1 IRQ_TYPE_LEVEL_LOW>; + }; + }; +}; + +&flexcan1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan1>; + status = "okay"; +}; + +&gpio1 { + gpio-line-names = + "#TPM_IRQ", "GPIO1", "", "#PMIC_INT", + "SD2_VSEL", "#TOUCH_IRQ", "#NFC_INT_I", "#NFC_INT", + "#SPI2_CS2", "#SPI2_CS3", "#RTS4", "", + "USB_PWR", "GPIO2", "GPIO3", ""; +}; + +&gpio2 { + gpio-line-names = + "", "", "", "", "", "", "", "", + "", "", "", "", "#SD2_CD", "", "", "", + "", "", "", "", "#USB-C_EN", "", "", "", + "", "", "", "", "", "", "", ""; +}; + +&gpio3 { + gpio-line-names = + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "DISP_POW", "GPIO4", + "#", "", "", "", "", "", "", ""; +}; + +&gpio4 { + gpio-line-names = + "BKL_POW", "#ETH1_INT", "#TPM_RES", "#PCAP_RES", + "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "#ETH0_INT", "#USB-C_ALERT", + "#USB-C_SEL", "", "", "", + "LED_RED", "LED_GREEN", "LED_YELLOW", "#WAKEUP", + "", "", "", ""; +}; + +&gpio5 { + gpio-line-names = + "", "", "", "", "", "", "", "", + "", "#SPI1_CS", "", "", "", "#SPI2_CS1", "", "", + "", "", "", "", "ENA_KAM", "ENA_LED", "", "", + "", "", "", "", "", "", "", ""; +}; + +&hdmi_pvi { + status = "okay"; +}; + +&hdmi_tx { + ddc-i2c-bus = <&i2c5>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hdmi>; + status = "okay"; +}; + +&hdmi_tx_phy { + status = "okay"; +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default", "gpio"; + pinctrl-0 = <&pinctrl_i2c1>; + pinctrl-1 = <&pinctrl_i2c1_gpio>; + scl-gpios = <&gpio5 14 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + sda-gpios = <&gpio5 15 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "okay"; + + pmic@25 { + compatible = "nxp,pca9450c"; + reg = <0x25>; + pinctrl-0 = <&pinctrl_pmic>; + interrupt-parent = <&gpio1>; + interrupts = <3 GPIO_ACTIVE_LOW>; + + /* + * i.MX 8M Plus Data Sheet for Consumer Products + * 3.1.4 Operating ranges + * MIMX8ML8DVNLZAB + */ + regulators { + buck1: BUCK1 { /* VDD_SOC (dual-phase with BUCK3) */ + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <1050000>; + regulator-always-on; + regulator-boot-on; + regulator-ramp-delay = <3125>; + }; + + buck2: BUCK2 { /* VDD_ARM */ + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + regulator-boot-on; + regulator-ramp-delay = <3125>; + nxp,dvs-run-voltage = <950000>; + nxp,dvs-standby-voltage = <850000>; + }; + + buck4: BUCK4 { /* +3V3 */ + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + }; + + buck5: BUCK5 { /* +1V8 */ + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + buck6: BUCK6 { /* DRAM_1V1 */ + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-always-on; + regulator-boot-on; + }; + + ldo1: LDO1 { /* NVCC_SNVS_1V8 */ + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + ldo3: LDO3 { /* VDDA_1P8 */ + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + ldo4: LDO4 { /* ENET_2V5 */ + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + regulator-always-on; + regulator-boot-on; + }; + + ldo5: LDO5 { /* NVCC_SD2 */ + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + }; + }; + }; + + crypto@35 { + compatible = "atmel,atecc508a"; + reg = <0x35>; + }; + + eeprom@50 { + compatible = "atmel,24c16"; + reg = <0x50>; + pagesize = <16>; + }; +}; + +&i2c2 { + clock-frequency = <100000>; + pinctrl-names = "default", "gpio"; + pinctrl-0 = <&pinctrl_i2c2>; + pinctrl-1 = <&pinctrl_i2c2_gpio>; + scl-gpios = <&gpio5 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + sda-gpios = <&gpio5 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "okay"; + + hwrtc: rtc@32 { + compatible = "epson,rx8900"; + reg = <0x32>; + epson,vdet-disable; + trickle-diode-disable; + }; + + tcpc@52 { + compatible = "nxp,ptn5110", "tcpci"; + reg = <0x52>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ptn5110>; + interrupt-parent = <&gpio4>; + interrupts = <19 IRQ_TYPE_LEVEL_LOW>; + + usb_con: connector { + compatible = "usb-c-connector"; + label = "USB-C"; + power-role = "dual"; + data-role = "dual"; + try-power-role = "sink"; + source-pdos = ; + sink-pdos = ; + op-sink-microwatt = <15000000>; + self-powered; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + typec_dr_sw: endpoint { + remote-endpoint = <&usb3_drd_sw>; + }; + }; + + port@1 { + reg = <1>; + + typec_con_ss: endpoint { + remote-endpoint = <&usb3_data_ss>; + }; + }; + }; + }; + }; +}; + +&i2c3 { + clock-frequency = <100000>; + pinctrl-names = "default", "gpio"; + pinctrl-0 = <&pinctrl_i2c3>; + pinctrl-1 = <&pinctrl_i2c3_gpio>; + scl-gpios = <&gpio5 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + sda-gpios = <&gpio5 19 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "okay"; +}; + +&i2c5 { /* HDMI EDID bus */ + clock-frequency = <100000>; + pinctrl-names = "default", "gpio"; + pinctrl-0 = <&pinctrl_i2c5>; + pinctrl-1 = <&pinctrl_i2c5_gpio>; + scl-gpios = <&gpio3 26 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + sda-gpios = <&gpio3 27 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "okay"; +}; + +&lcdif3 { + status = "okay"; +}; + +&pwm1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm1>; + status = "okay"; +}; + +&pwm2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm2>; + status = "okay"; +}; + +&snvs_pwrkey { + status = "okay"; +}; + +&uart2 { + /* system console */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + status = "okay"; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart3>; + status = "okay"; +}; + +&uart4 { + /* expansion port serial connection */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart4>; + status = "okay"; +}; + +&usb3_phy0 { + status = "okay"; +}; + +&usb3_0 { + status = "okay"; +}; + +&usb_dwc3_0 { + dr_mode = "otg"; + hnp-disable; + srp-disable; + adp-disable; + usb-role-switch; + status = "okay"; + + port { + usb3_drd_sw: endpoint { + remote-endpoint = <&typec_dr_sw>; + }; + }; +}; + +&usb3_phy1 { + vbus-supply = <®_usba_vbus>; + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&usb_dwc3_1 { + dr_mode = "host"; + snps,hsphy_interface = "utmi"; + status = "okay"; +}; + +&usdhc2 { + assigned-clocks = <&clk IMX8MP_CLK_USDHC2>; + assigned-clock-rates = <400000000>; + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>; + pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>; + pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>; + cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>; + bus-width = <4>; + vmmc-supply = <®_usdhc2_vmmc>; + vqmmc-supply = <&ldo5>; + status = "okay"; +}; + +&usdhc3 { + assigned-clocks = <&clk IMX8MP_CLK_USDHC3>; + assigned-clock-rates = <400000000>; + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc3>; + pinctrl-1 = <&pinctrl_usdhc3_100mhz>; + pinctrl-2 = <&pinctrl_usdhc3_200mhz>; + vmmc-supply = <&buck4>; + vqmmc-supply = <&buck5>; + bus-width = <8>; + no-sd; + no-sdio; + non-removable; + status = "okay"; +}; + +&wdog1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wdog>; + fsl,ext-reset-output; + status = "okay"; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + + pinctrl_ecspi1_cs: ecspi1-cs-grp { + fsl,pins = < + MX8MP_IOMUXC_ECSPI1_SS0__GPIO5_IO09 0x40 /* #SPI1_CS */ + >; + }; + + pinctrl_ecspi1: ecspi1-grp { + fsl,pins = < + MX8MP_IOMUXC_ECSPI1_SCLK__ECSPI1_SCLK 0x82 + MX8MP_IOMUXC_ECSPI1_MOSI__ECSPI1_MOSI 0x82 + MX8MP_IOMUXC_ECSPI1_MISO__ECSPI1_MISO 0x82 + >; + }; + + pinctrl_ecspi2_cs: ecspi2-cs-grp { + fsl,pins = < + MX8MP_IOMUXC_ECSPI2_SS0__GPIO5_IO13 0x40 /* #SPI2_CS */ + MX8MP_IOMUXC_GPIO1_IO08__GPIO1_IO08 0x40 /* #SPI2_CS2 */ + MX8MP_IOMUXC_GPIO1_IO09__GPIO1_IO09 0x40 /* #SPI2_CS3 */ + >; + }; + + pinctrl_ecspi2: ecspi2-grp { + fsl,pins = < + MX8MP_IOMUXC_ECSPI2_SCLK__ECSPI2_SCLK 0x82 + MX8MP_IOMUXC_ECSPI2_MOSI__ECSPI2_MOSI 0x82 + MX8MP_IOMUXC_ECSPI2_MISO__ECSPI2_MISO 0x82 + >; + }; + + pinctrl_eqos: eqos-grp { + fsl,pins = < + MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC 0x0 + MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO 0x0 + MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0 0x90 + MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1 0x90 + MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2 0x90 + MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3 0x90 + MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK 0x90 + MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL 0x90 + MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0 0x16 + MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1 0x16 + MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2 0x16 + MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3 0x16 + MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL 0x16 + MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK 0x16 + MX8MP_IOMUXC_SAI1_TXD6__GPIO4_IO18 0x10 /* #ETH0_INT */ + >; + }; + + pinctrl_fec: fec-grp { + fsl,pins = < + MX8MP_IOMUXC_SAI1_RXD2__ENET1_MDC 0x0 + MX8MP_IOMUXC_SAI1_RXD3__ENET1_MDIO 0x0 + MX8MP_IOMUXC_SAI1_RXD4__ENET1_RGMII_RD0 0x90 + MX8MP_IOMUXC_SAI1_RXD5__ENET1_RGMII_RD1 0x90 + MX8MP_IOMUXC_SAI1_RXD6__ENET1_RGMII_RD2 0x90 + MX8MP_IOMUXC_SAI1_RXD7__ENET1_RGMII_RD3 0x90 + MX8MP_IOMUXC_SAI1_TXC__ENET1_RGMII_RXC 0x90 + MX8MP_IOMUXC_SAI1_TXFS__ENET1_RGMII_RX_CTL 0x90 + MX8MP_IOMUXC_SAI1_TXD0__ENET1_RGMII_TD0 0x16 + MX8MP_IOMUXC_SAI1_TXD1__ENET1_RGMII_TD1 0x16 + MX8MP_IOMUXC_SAI1_TXD2__ENET1_RGMII_TD2 0x16 + MX8MP_IOMUXC_SAI1_TXD3__ENET1_RGMII_TD3 0x16 + MX8MP_IOMUXC_SAI1_TXD4__ENET1_RGMII_TX_CTL 0x16 + MX8MP_IOMUXC_SAI1_TXD5__ENET1_RGMII_TXC 0x16 + MX8MP_IOMUXC_SAI1_RXC__GPIO4_IO01 0x10 /* #ETH1_INT */ + >; + }; + + pinctrl_flexcan1: flexcan1-grp { + fsl,pins = < + MX8MP_IOMUXC_SPDIF_RX__CAN1_RX 0x154 + MX8MP_IOMUXC_SPDIF_TX__CAN1_TX 0x154 + >; + }; + + pinctrl_gpio_key_wakeup: gpio-key-wakeup-grp { + fsl,pins = < + MX8MP_IOMUXC_SAI2_MCLK__GPIO4_IO27 0x40 /* #WAKEUP */ + >; + }; + + pinctrl_gpio_leds: gpio-leds-grp { + fsl,pins = < + MX8MP_IOMUXC_SAI2_TXFS__GPIO4_IO24 0x40 /* LED_RED */ + MX8MP_IOMUXC_SAI2_TXC__GPIO4_IO25 0x40 /* LED_GREEN */ + MX8MP_IOMUXC_SAI2_TXD0__GPIO4_IO26 0x40 /* LED_YELLOW */ + >; + }; + + pinctrl_hdmi: hdmi-grp { + fsl,pins = < + MX8MP_IOMUXC_HDMI_CEC__HDMIMIX_HDMI_CEC 0x154 + MX8MP_IOMUXC_HDMI_HPD__HDMIMIX_HDMI_HPD 0x154 + >; + }; + + pinctrl_hog: hog-grp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO01__GPIO1_IO01 0x40 /* GPIO1 */ + MX8MP_IOMUXC_GPIO1_IO13__GPIO1_IO13 0x40 /* GPIO2 */ + MX8MP_IOMUXC_GPIO1_IO14__GPIO1_IO14 0x40 /* GPIO3 */ + MX8MP_IOMUXC_SAI5_RXD2__GPIO3_IO23 0x40 /* GPIO4 */ + MX8MP_IOMUXC_I2C4_SCL__GPIO5_IO20 0x40 /* ENA_KAM */ + MX8MP_IOMUXC_I2C4_SDA__GPIO5_IO21 0x40 /* ENA_LED */ + MX8MP_IOMUXC_SAI1_RXD1__GPIO4_IO03 0x40 /* #PCAP_RES */ + MX8MP_IOMUXC_GPIO1_IO10__GPIO1_IO10 0x40 /* #RTS4 */ + >; + }; + + pinctrl_i2c1: i2c1-grp { + fsl,pins = < + MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL 0x400001c0 + MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA 0x400001c0 + >; + }; + + pinctrl_i2c1_gpio: i2c1-gpio-grp { + fsl,pins = < + MX8MP_IOMUXC_I2C1_SCL__GPIO5_IO14 0xc0 + MX8MP_IOMUXC_I2C1_SDA__GPIO5_IO15 0xc0 + >; + }; + + pinctrl_i2c2: i2c2-grp { + fsl,pins = < + MX8MP_IOMUXC_I2C2_SCL__I2C2_SCL 0x400001c0 + MX8MP_IOMUXC_I2C2_SDA__I2C2_SDA 0x400001c0 + >; + }; + + pinctrl_i2c2_gpio: i2c2-gpio-grp { + fsl,pins = < + MX8MP_IOMUXC_I2C2_SCL__GPIO5_IO16 0xc0 + MX8MP_IOMUXC_I2C2_SDA__GPIO5_IO17 0xc0 + >; + }; + + pinctrl_i2c3: i2c3-grp { + fsl,pins = < + MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL 0x400001c2 + MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA 0x400001c2 + >; + }; + + pinctrl_i2c3_gpio: i2c3-gpio-grp { + fsl,pins = < + MX8MP_IOMUXC_I2C3_SCL__GPIO5_IO18 0xc2 + MX8MP_IOMUXC_I2C3_SDA__GPIO5_IO19 0xc2 + >; + }; + + pinctrl_i2c5: i2c5-grp { + fsl,pins = < + MX8MP_IOMUXC_HDMI_DDC_SCL__I2C5_SCL 0x400000c4 + MX8MP_IOMUXC_HDMI_DDC_SDA__I2C5_SDA 0x400000c4 + >; + }; + + pinctrl_i2c5_gpio: i2c5-gpio-grp { + fsl,pins = < + MX8MP_IOMUXC_HDMI_DDC_SCL__GPIO3_IO26 0xc4 + MX8MP_IOMUXC_HDMI_DDC_SDA__GPIO3_IO27 0xc4 + >; + }; + + pinctrl_nfc: nfc-grp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO06__GPIO1_IO06 0x40 /* NFC_INT_I */ + MX8MP_IOMUXC_GPIO1_IO07__GPIO1_IO07 0x40 /* NFC_INT */ + >; + }; + + pinctrl_pmic: pmic-grp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x40 /* #PMIC_INT */ + >; + }; + + pinctrl_ptn5110: ptn5110-grp { + fsl,pins = < + MX8MP_IOMUXC_SAI1_TXD7__GPIO4_IO19 0x1c4 /* #USB-C_ALERT */ + >; + }; + + pinctrl_pwm1: pwm1-grp { + fsl,pins = < + MX8MP_IOMUXC_SPDIF_EXT_CLK__PWM1_OUT 0x116 + >; + }; + + pinctrl_pwm2: pwm2-grp { + fsl,pins = < + MX8MP_IOMUXC_SAI5_RXD0__PWM2_OUT 0x116 /* EXT_PWM */ + >; + }; + + pinctrl_reg_usdhc2_vmmc: reg-usdhc2-vmmc-grp { + fsl,pins = < + MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19 0x40 + >; + }; + + pinctrl_sbu_mux: sbu-mux-grp { + fsl,pins = < + MX8MP_IOMUXC_SAI1_MCLK__GPIO4_IO20 0x16 /* #USB-C_SEL */ + MX8MP_IOMUXC_SD2_WP__GPIO2_IO20 0x16 /* #USB-C_EN */ + >; + }; + + pinctrl_slb9670: slb9670-grp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO00__GPIO1_IO00 0x40 /* #TPM_IRQ */ + MX8MP_IOMUXC_SAI1_RXD0__GPIO4_IO02 0x40 /* #TPM_RES */ + >; + }; + + pinctrl_uart2: uart2-grp { + fsl,pins = < + MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX 0x40 + MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX 0x40 + >; + }; + + pinctrl_uart3: uart3-grp { + fsl,pins = < + MX8MP_IOMUXC_UART3_RXD__UART3_DCE_RX 0x40 + MX8MP_IOMUXC_UART3_TXD__UART3_DCE_TX 0x40 + >; + }; + + pinctrl_uart4: uart4-grp { + fsl,pins = < + MX8MP_IOMUXC_UART4_RXD__UART4_DCE_RX 0x40 + MX8MP_IOMUXC_UART4_TXD__UART4_DCE_TX 0x40 + >; + }; + + pinctrl_usb1: usb1-grp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO12__GPIO1_IO12 0x40 /* USB_PWR */ + >; + }; + + pinctrl_usdhc2: usdhc2-grp { + fsl,pins = < + MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK 0x190 + MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD 0x1d0 + MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0 0x1d0 + MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1 0x1d0 + MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2 0x1d0 + MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3 0x1d0 + MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0 /* SD2_VSEL */ + >; + }; + + pinctrl_usdhc2_100mhz: usdhc2-100mhz-grp { + fsl,pins = < + MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK 0x194 + MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD 0x1d4 + MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0 0x1d4 + MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1 0x1d4 + MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2 0x1d4 + MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3 0x1d4 + MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0 /* SD2_VSEL */ + >; + }; + + pinctrl_usdhc2_200mhz: usdhc2-200mhz-grp { + fsl,pins = < + MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK 0x196 + MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD 0x1d6 + MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0 0x1d6 + MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1 0x1d6 + MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2 0x1d6 + MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3 0x1d6 + MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0 /* SD2_VSEL */ + >; + }; + + pinctrl_usdhc2_gpio: usdhc2-gpio-grp { + fsl,pins = < + MX8MP_IOMUXC_SD2_CD_B__GPIO2_IO12 0x1c4 + >; + }; + + pinctrl_usdhc3: usdhc3-grp { + fsl,pins = < + MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK 0x190 + MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD 0x1d0 + MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0 0x1d0 + MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1 0x1d0 + MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2 0x1d0 + MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3 0x1d0 + MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4 0x1d0 + MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5 0x1d0 + MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6 0x1d0 + MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7 0x1d0 + MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE 0x190 + MX8MP_IOMUXC_NAND_READY_B__USDHC3_RESET_B 0x40 /* #SD3_RESET */ + >; + }; + + pinctrl_usdhc3_100mhz: usdhc3-100mhz-grp { + fsl,pins = < + MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK 0x194 + MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD 0x1d4 + MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0 0x1d4 + MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1 0x1d4 + MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2 0x1d4 + MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3 0x1d4 + MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4 0x1d4 + MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5 0x1d4 + MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6 0x1d4 + MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7 0x1d4 + MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE 0x194 + >; + }; + + pinctrl_usdhc3_200mhz: usdhc3-200mhz-grp { + fsl,pins = < + MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK 0x192 + MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD 0x1d2 + MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0 0x1d2 + MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1 0x1d2 + MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2 0x1d2 + MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3 0x1d2 + MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4 0x1d2 + MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5 0x1d2 + MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6 0x1d2 + MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7 0x1d2 + MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE 0x192 + >; + }; + + pinctrl_wdog: wdog-grp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO02__WDOG1_WDOG_B 0xc6 /* #WDOG */ + >; + }; +}; From 21179eae56de418ea360e31f1b69f66fc16aa4e3 Mon Sep 17 00:00:00 2001 From: Primoz Fiser Date: Mon, 14 Jul 2025 12:36:24 +0200 Subject: [PATCH 01531/11391] arm64: dts: freescale: imx93-phyboard-nash: Add current sense amplifier There is a current sensing circuitry on the phyBOARD-Nash-i.MX93 capable of measuring input current consumption of the phyCORE-i.MX93 SoM @ 3.3V. Circuity consists of MAX4372 current-sense amplifier (50V/V) with two 70 mOhm shunts resistors in parallel configuration (effective R = 35 mOhm) connected to the SoC internal 12-bit ADC channel #1 (Vref = 1.8V) via voltage divider with ratio of 1/2. This results in a current scaling factor of 0.502232142 mA/LSB. Signed-off-by: Primoz Fiser Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx93-phyboard-nash.dts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/imx93-phyboard-nash.dts b/arch/arm64/boot/dts/freescale/imx93-phyboard-nash.dts index 475913cf0cb9..71a0e9f270af 100644 --- a/arch/arm64/boot/dts/freescale/imx93-phyboard-nash.dts +++ b/arch/arm64/boot/dts/freescale/imx93-phyboard-nash.dts @@ -27,6 +27,14 @@ chosen { stdout-path = &lpuart1; }; + current-sense { + compatible = "current-sense-amplifier"; + io-channels = <&adc1 1>; + sense-gain-div = <2>; + sense-gain-mult = <50>; + sense-resistor-micro-ohms = <35000>; + }; + flexcan1_tc: can-phy0 { compatible = "ti,tcan1042"; #phy-cells = <0>; From bc9dc8de130e3fd208cf489788ecb998069ce6bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bence=20Cs=C3=B3k=C3=A1s?= Date: Wed, 9 Jul 2025 09:32:44 +0200 Subject: [PATCH 01532/11391] ARM: dts: imx6-display5: Replace license text comment with SPDX identifier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace verbatim license text with a `SPDX-License-Identifier`. The comment header mis-attributes this license to be "X11", but the license text does not include the last line "Except as contained in this notice, the name of the X Consortium shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the X Consortium.". Therefore, this license is actually equivalent to the SPDX "MIT" license (confirmed by text diffing). Cc: Lukasz Majewski Signed-off-by: Bence Csókás Acked-by: Lukasz Majewski Signed-off-by: Shawn Guo --- .../imx6q-display5-tianma-tm070-1280x768.dts | 33 +------------------ arch/arm/boot/dts/nxp/imx/imx6q-display5.dtsi | 33 +------------------ 2 files changed, 2 insertions(+), 64 deletions(-) diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-display5-tianma-tm070-1280x768.dts b/arch/arm/boot/dts/nxp/imx/imx6q-display5-tianma-tm070-1280x768.dts index 16658b76fc4e..059750270fc4 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6q-display5-tianma-tm070-1280x768.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6q-display5-tianma-tm070-1280x768.dts @@ -1,38 +1,7 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR MIT) /* * Copyright 2017 * Lukasz Majewski, DENX Software Engineering, lukma@denx.de - * - * This file is dual-licensed: you can use it either under the terms - * of the GPL or the X11 license, at your option. Note that this dual - * licensing only applies to this file, and not this project as a - * whole. - * - * a) 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. - * - * Or, alternatively, - * - * b) Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. */ /dts-v1/; diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-display5.dtsi b/arch/arm/boot/dts/nxp/imx/imx6q-display5.dtsi index 4ab31f2217cd..4e448b4810f2 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6q-display5.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6q-display5.dtsi @@ -1,38 +1,7 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR MIT) /* * Copyright 2017 * Lukasz Majewski, DENX Software Engineering, lukma@denx.de - * - * This file is dual-licensed: you can use it either under the terms - * of the GPL or the X11 license, at your option. Note that this dual - * licensing only applies to this file, and not this project as a - * whole. - * - * a) 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. - * - * Or, alternatively, - * - * b) Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. */ /dts-v1/; From 72907ea795e0bf261def10595d19ded441b90d9f Mon Sep 17 00:00:00 2001 From: Nicolas Frattaroli Date: Tue, 19 Aug 2025 13:21:42 +0200 Subject: [PATCH 01533/11391] cpufreq: mediatek-hw: don't use error path on NULL fdvfs The IS_ERR_OR_NULL check for priv->fdvfs is inappropriate, and should be an IS_ERR check instead, as a NULL value here would propagate it to PTR_ERR. In practice, there is no problem here, as devm_of_iomap cannot return NULL in any circumstance. However, it causes a Smatch static checker warning. Fix the warning by changing the check from IS_ERR_OR_NULL to IS_ERR. Fixes: 32e0d669f3ac ("cpufreq: mediatek-hw: Add support for MT8196") Reported-by: Dan Carpenter Closes: https://lore.kernel.org/linux-pm/aKQubSEXH1TXQpnR@stanley.mountain/ Signed-off-by: Nicolas Frattaroli Signed-off-by: Viresh Kumar --- drivers/cpufreq/mediatek-cpufreq-hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpufreq/mediatek-cpufreq-hw.c b/drivers/cpufreq/mediatek-cpufreq-hw.c index e4eadce6f937..fce5aa5ceea0 100644 --- a/drivers/cpufreq/mediatek-cpufreq-hw.c +++ b/drivers/cpufreq/mediatek-cpufreq-hw.c @@ -72,7 +72,7 @@ static const struct mtk_cpufreq_variant cpufreq_mtk_base_variant = { static int mtk_cpufreq_hw_mt8196_init(struct mtk_cpufreq_priv *priv) { priv->fdvfs = devm_of_iomap(priv->dev, priv->dev->of_node, 0, NULL); - if (IS_ERR_OR_NULL(priv->fdvfs)) + if (IS_ERR(priv->fdvfs)) return dev_err_probe(priv->dev, PTR_ERR(priv->fdvfs), "failed to get fdvfs iomem\n"); From e88ef677623eaf7a4c30b5fe905e7138838d13d2 Mon Sep 17 00:00:00 2001 From: Shankari Anand Date: Fri, 15 Aug 2025 23:15:21 +0530 Subject: [PATCH 01534/11391] rust: opp: update ARef and AlwaysRefCounted imports from sync::aref Update call sites in `opp.rs` to import ARef and AlwaysRefCounted from sync::aref instead of types. This aligns with the ongoing effort to move ARef and AlwaysRefCounted to sync. Suggested-by: Benno Lossin Link: https://github.com/Rust-for-Linux/linux/issues/1173 Signed-off-by: Shankari Anand Reviewed-by: Benno Lossin Signed-off-by: Viresh Kumar --- rust/kernel/opp.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/rust/kernel/opp.rs b/rust/kernel/opp.rs index 08126035d2c6..29be7d14025e 100644 --- a/rust/kernel/opp.rs +++ b/rust/kernel/opp.rs @@ -16,7 +16,8 @@ ffi::c_ulong, prelude::*, str::CString, - types::{ARef, AlwaysRefCounted, Opaque}, + sync::aref::{ARef, AlwaysRefCounted}, + types::Opaque, }; #[cfg(CONFIG_CPU_FREQ)] @@ -162,7 +163,7 @@ fn from(power: MicroWatt) -> Self { /// use kernel::device::Device; /// use kernel::error::Result; /// use kernel::opp::{Data, MicroVolt, Token}; -/// use kernel::types::ARef; +/// use kernel::sync::aref::ARef; /// /// fn create_opp(dev: &ARef, freq: Hertz, volt: MicroVolt, level: u32) -> Result { /// let data = Data::new(freq, volt, level, false); @@ -211,7 +212,7 @@ fn drop(&mut self) { /// use kernel::device::Device; /// use kernel::error::Result; /// use kernel::opp::{Data, MicroVolt, Token}; -/// use kernel::types::ARef; +/// use kernel::sync::aref::ARef; /// /// fn create_opp(dev: &ARef, freq: Hertz, volt: MicroVolt, level: u32) -> Result { /// let data = Data::new(freq, volt, level, false); @@ -262,7 +263,7 @@ fn freq(&self) -> Hertz { /// use kernel::clk::Hertz; /// use kernel::error::Result; /// use kernel::opp::{OPP, SearchType, Table}; -/// use kernel::types::ARef; +/// use kernel::sync::aref::ARef; /// /// fn find_opp(table: &Table, freq: Hertz) -> Result> { /// let opp = table.opp_from_freq(freq, Some(true), None, SearchType::Exact)?; @@ -335,7 +336,7 @@ fn drop(&mut self) { /// use kernel::error::Result; /// use kernel::opp::{Config, ConfigOps, ConfigToken}; /// use kernel::str::CString; -/// use kernel::types::ARef; +/// use kernel::sync::aref::ARef; /// use kernel::macros::vtable; /// /// #[derive(Default)] @@ -581,7 +582,7 @@ extern "C" fn config_regulators( /// use kernel::device::Device; /// use kernel::error::Result; /// use kernel::opp::Table; -/// use kernel::types::ARef; +/// use kernel::sync::aref::ARef; /// /// fn get_table(dev: &ARef, mask: &mut Cpumask, freq: Hertz) -> Result { /// let mut opp_table = Table::from_of_cpumask(dev, mask)?; From 0c5e2ae204eca74e4ccbaffc8125c3b41de9c9b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0erif=20Rami?= Date: Tue, 19 Aug 2025 20:51:33 +0200 Subject: [PATCH 01535/11391] ALSA: usb-audio: us144mkii: Fix null-deref in tascam_midi_in_urb_complete() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The smatch tool reported a potential null pointer dereference in tascam_midi_in_urb_complete(). The 'tascam' variable, derived from 'urb->context', was checked for nullity in one place, but dereferenced without a check in several other places. This patch fixes the issue by adding a null check at the beginning of the function. If 'tascam' is null, the function now safely exits. This prevents any potential crashes from null pointer dereferences. It also fixes a latent bug where 'usb_put_urb()' could be called twice for the same URB on submission failure, which would lead to a use-after-free error. Fixes: 67afec157fe6 ("ALSA: usb-audio: us144mkii: Add MIDI support and mixer controls") Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/202508192109.lcMrINK1-lkp@intel.com/ Signed-off-by: Šerif Rami Link: https://patch.msgid.link/20250819185133.10464-1-ramiserifpersia@gmail.com Signed-off-by: Takashi Iwai --- sound/usb/usx2y/us144mkii_midi.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/usb/usx2y/us144mkii_midi.c b/sound/usb/usx2y/us144mkii_midi.c index 5759f601007f..08b04aa39278 100644 --- a/sound/usb/usx2y/us144mkii_midi.c +++ b/sound/usb/usx2y/us144mkii_midi.c @@ -41,6 +41,9 @@ void tascam_midi_in_urb_complete(struct urb *urb) struct tascam_card *tascam = urb->context; int ret; + if (!tascam) + goto out; + if (urb->status) { if (urb->status != -ENOENT && urb->status != -ECONNRESET && urb->status != -ESHUTDOWN && urb->status != -EPROTO) { @@ -51,7 +54,7 @@ void tascam_midi_in_urb_complete(struct urb *urb) goto out; } - if (tascam && atomic_read(&tascam->midi_in_active) && + if (atomic_read(&tascam->midi_in_active) && urb->actual_length > 0) { kfifo_in_spinlocked(&tascam->midi_in_fifo, urb->transfer_buffer, urb->actual_length, &tascam->midi_in_lock); @@ -65,8 +68,9 @@ void tascam_midi_in_urb_complete(struct urb *urb) dev_err(tascam->card->dev, "Failed to resubmit MIDI IN URB: error %d\n", ret); usb_unanchor_urb(urb); - usb_put_urb(urb); + goto out; } + out: usb_put_urb(urb); } From 2da2740fb9c8e26b6b5e20d74f2ed1d49824236d Mon Sep 17 00:00:00 2001 From: John Madieu Date: Mon, 18 Aug 2025 18:28:47 +0200 Subject: [PATCH 01536/11391] soc: renesas: rz-sysc: Add syscon/regmap support The RZ/G3E system controller has various registers that control or report some properties specific to individual IPs. The regmap is registered as a syscon device to allow these IP drivers to access the registers through the regmap API. As other RZ SoCs might have custom read/write callbacks or max-offsets, register a custom regmap configuration. [claudiu.beznea: - do not check the match->data validity in rz_sysc_probe() as it is always valid - dinamically allocate regmap_cfg] Signed-off-by: John Madieu Signed-off-by: Claudiu Beznea Reviewed-by: Claudiu Beznea Tested-by: Claudiu Beznea # on RZ/G3S Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250818162859.9661-2-john.madieu.xa@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/soc/renesas/Kconfig | 1 + drivers/soc/renesas/r9a08g045-sysc.c | 1 + drivers/soc/renesas/r9a09g047-sys.c | 1 + drivers/soc/renesas/r9a09g057-sys.c | 1 + drivers/soc/renesas/rz-sysc.c | 30 +++++++++++++++++++++++++++- drivers/soc/renesas/rz-sysc.h | 2 ++ 6 files changed, 35 insertions(+), 1 deletion(-) diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig index 719b7f4f376f..c97e2a183388 100644 --- a/drivers/soc/renesas/Kconfig +++ b/drivers/soc/renesas/Kconfig @@ -449,6 +449,7 @@ config RST_RCAR config SYSC_RZ bool "System controller for RZ SoCs" if COMPILE_TEST + select MFD_SYSCON config SYSC_R9A08G045 bool "Renesas System controller support for R9A08G045 (RZ/G3S)" if COMPILE_TEST diff --git a/drivers/soc/renesas/r9a08g045-sysc.c b/drivers/soc/renesas/r9a08g045-sysc.c index f4db1431e036..0504d4e68761 100644 --- a/drivers/soc/renesas/r9a08g045-sysc.c +++ b/drivers/soc/renesas/r9a08g045-sysc.c @@ -20,4 +20,5 @@ static const struct rz_sysc_soc_id_init_data rzg3s_sysc_soc_id_init_data __initc const struct rz_sysc_init_data rzg3s_sysc_init_data __initconst = { .soc_id_init_data = &rzg3s_sysc_soc_id_init_data, + .max_register = 0xe20, }; diff --git a/drivers/soc/renesas/r9a09g047-sys.c b/drivers/soc/renesas/r9a09g047-sys.c index cd2eb7782cfe..2e8426c03050 100644 --- a/drivers/soc/renesas/r9a09g047-sys.c +++ b/drivers/soc/renesas/r9a09g047-sys.c @@ -64,4 +64,5 @@ static const struct rz_sysc_soc_id_init_data rzg3e_sys_soc_id_init_data __initco const struct rz_sysc_init_data rzg3e_sys_init_data = { .soc_id_init_data = &rzg3e_sys_soc_id_init_data, + .max_register = 0x170c, }; diff --git a/drivers/soc/renesas/r9a09g057-sys.c b/drivers/soc/renesas/r9a09g057-sys.c index 4c21cc29edbc..e3390e7c7fe5 100644 --- a/drivers/soc/renesas/r9a09g057-sys.c +++ b/drivers/soc/renesas/r9a09g057-sys.c @@ -64,4 +64,5 @@ static const struct rz_sysc_soc_id_init_data rzv2h_sys_soc_id_init_data __initco const struct rz_sysc_init_data rzv2h_sys_init_data = { .soc_id_init_data = &rzv2h_sys_soc_id_init_data, + .max_register = 0x170c, }; diff --git a/drivers/soc/renesas/rz-sysc.c b/drivers/soc/renesas/rz-sysc.c index ffa65fb4dade..9f79e299e6f4 100644 --- a/drivers/soc/renesas/rz-sysc.c +++ b/drivers/soc/renesas/rz-sysc.c @@ -5,9 +5,13 @@ * Copyright (C) 2024 Renesas Electronics Corp. */ +#include #include +#include #include #include +#include +#include #include #include "rz-sysc.h" @@ -100,14 +104,23 @@ MODULE_DEVICE_TABLE(of, rz_sysc_match); static int rz_sysc_probe(struct platform_device *pdev) { + const struct rz_sysc_init_data *data; const struct of_device_id *match; struct device *dev = &pdev->dev; + struct regmap *regmap; struct rz_sysc *sysc; + int ret; + + struct regmap_config *regmap_cfg __free(kfree) = kzalloc(sizeof(*regmap_cfg), GFP_KERNEL); + if (!regmap_cfg) + return -ENOMEM; match = of_match_node(rz_sysc_match, dev->of_node); if (!match) return -ENODEV; + data = match->data; + sysc = devm_kzalloc(dev, sizeof(*sysc), GFP_KERNEL); if (!sysc) return -ENOMEM; @@ -117,7 +130,22 @@ static int rz_sysc_probe(struct platform_device *pdev) return PTR_ERR(sysc->base); sysc->dev = dev; - return rz_sysc_soc_init(sysc, match); + ret = rz_sysc_soc_init(sysc, match); + if (ret) + return ret; + + regmap_cfg->name = "rz_sysc_regs"; + regmap_cfg->reg_bits = 32; + regmap_cfg->reg_stride = 4; + regmap_cfg->val_bits = 32; + regmap_cfg->fast_io = true; + regmap_cfg->max_register = data->max_register; + + regmap = devm_regmap_init_mmio(dev, sysc->base, regmap_cfg); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return of_syscon_register_regmap(dev->of_node, regmap); } static struct platform_driver rz_sysc_driver = { diff --git a/drivers/soc/renesas/rz-sysc.h b/drivers/soc/renesas/rz-sysc.h index 56bc047a1bff..8eec355d5d56 100644 --- a/drivers/soc/renesas/rz-sysc.h +++ b/drivers/soc/renesas/rz-sysc.h @@ -34,9 +34,11 @@ struct rz_sysc_soc_id_init_data { /** * struct rz_sysc_init_data - RZ SYSC initialization data * @soc_id_init_data: RZ SYSC SoC ID initialization data + * @max_register: Maximum SYSC register offset to be used by the regmap config */ struct rz_sysc_init_data { const struct rz_sysc_soc_id_init_data *soc_id_init_data; + u32 max_register; }; extern const struct rz_sysc_init_data rzg3e_sys_init_data; From 34d4d093077a5c60d452a2f42d0c1a08e55b8614 Mon Sep 17 00:00:00 2001 From: Thierry Bultel Date: Fri, 8 Aug 2025 14:30:16 +0100 Subject: [PATCH 01537/11391] pinctrl: renesas: Add support for RZ/T2H Add a pin control and GPIO driver for the Renesas RZ/T2H (R9A09G077) SoC. Signed-off-by: Thierry Bultel Co-developed-by: Lad Prabhakar Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250808133017.2053637-3-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/renesas/Kconfig | 12 + drivers/pinctrl/renesas/Makefile | 1 + drivers/pinctrl/renesas/pinctrl-rzt2h.c | 797 ++++++++++++++++++++++++ 3 files changed, 810 insertions(+) create mode 100644 drivers/pinctrl/renesas/pinctrl-rzt2h.c diff --git a/drivers/pinctrl/renesas/Kconfig b/drivers/pinctrl/renesas/Kconfig index 99ae34a56871..c8b84c158e86 100644 --- a/drivers/pinctrl/renesas/Kconfig +++ b/drivers/pinctrl/renesas/Kconfig @@ -44,6 +44,7 @@ config PINCTRL_RENESAS select PINCTRL_RZG2L if ARCH_R9A09G047 select PINCTRL_RZG2L if ARCH_R9A09G056 select PINCTRL_RZG2L if ARCH_R9A09G057 + select PINCTRL_RZT2H if ARCH_R9A09G077 select PINCTRL_PFC_SH7203 if CPU_SUBTYPE_SH7203 select PINCTRL_PFC_SH7264 if CPU_SUBTYPE_SH7264 select PINCTRL_PFC_SH7269 if CPU_SUBTYPE_SH7269 @@ -302,6 +303,17 @@ config PINCTRL_RZN1 help This selects pinctrl driver for Renesas RZ/N1 devices. +config PINCTRL_RZT2H + bool "pin control support for RZ/N2H and RZ/T2H" if COMPILE_TEST + depends on 64BIT && OF + select GPIOLIB + select GENERIC_PINCTRL_GROUPS + select GENERIC_PINMUX_FUNCTIONS + select GENERIC_PINCONF + help + This selects GPIO and pinctrl driver for Renesas RZ/T2H + platforms. + config PINCTRL_RZV2M bool "pin control support for RZ/V2M" if COMPILE_TEST depends on OF diff --git a/drivers/pinctrl/renesas/Makefile b/drivers/pinctrl/renesas/Makefile index 2ba623e04bf8..1c5144a1c4b8 100644 --- a/drivers/pinctrl/renesas/Makefile +++ b/drivers/pinctrl/renesas/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_PINCTRL_RZA1) += pinctrl-rza1.o obj-$(CONFIG_PINCTRL_RZA2) += pinctrl-rza2.o obj-$(CONFIG_PINCTRL_RZG2L) += pinctrl-rzg2l.o obj-$(CONFIG_PINCTRL_RZN1) += pinctrl-rzn1.o +obj-$(CONFIG_PINCTRL_RZT2H) += pinctrl-rzt2h.o obj-$(CONFIG_PINCTRL_RZV2M) += pinctrl-rzv2m.o ifeq ($(CONFIG_COMPILE_TEST),y) diff --git a/drivers/pinctrl/renesas/pinctrl-rzt2h.c b/drivers/pinctrl/renesas/pinctrl-rzt2h.c new file mode 100644 index 000000000000..28f5d48e33db --- /dev/null +++ b/drivers/pinctrl/renesas/pinctrl-rzt2h.c @@ -0,0 +1,797 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas RZ/T2H Pin Control and GPIO driver core + * + * Based on drivers/pinctrl/renesas/pinctrl-rzg2l.c + * + * Copyright (C) 2025 Renesas Electronics Corporation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "../core.h" +#include "../pinconf.h" +#include "../pinmux.h" + +#define DRV_NAME "pinctrl-rzt2h" + +#define P(m) (0x001 * (m)) +#define PM(m) (0x200 + 2 * (m)) +#define PMC(m) (0x400 + (m)) +#define PFC(m) (0x600 + 8 * (m)) +#define PIN(m) (0x800 + (m)) +#define RSELP(m) (0xc00 + (m)) + +#define PM_MASK GENMASK(1, 0) +#define PM_PIN_MASK(pin) (PM_MASK << ((pin) * 2)) +#define PM_INPUT BIT(0) +#define PM_OUTPUT BIT(1) + +#define PFC_MASK GENMASK_ULL(5, 0) +#define PFC_PIN_MASK(pin) (PFC_MASK << ((pin) * 8)) + +/* + * Use 16 lower bits [15:0] for pin identifier + * Use 8 higher bits [23:16] for pin mux function + */ +#define MUX_PIN_ID_MASK GENMASK(15, 0) +#define MUX_FUNC_MASK GENMASK(23, 16) + +#define RZT2H_PIN_ID_TO_PORT(id) ((id) / RZT2H_PINS_PER_PORT) +#define RZT2H_PIN_ID_TO_PIN(id) ((id) % RZT2H_PINS_PER_PORT) + +#define RZT2H_MAX_SAFETY_PORTS 12 + +struct rzt2h_pinctrl_data { + unsigned int n_port_pins; + const u8 *port_pin_configs; + unsigned int n_ports; +}; + +struct rzt2h_pinctrl { + struct pinctrl_dev *pctl; + struct pinctrl_desc desc; + struct pinctrl_pin_desc *pins; + const struct rzt2h_pinctrl_data *data; + void __iomem *base0, *base1; + struct device *dev; + struct gpio_chip gpio_chip; + struct pinctrl_gpio_range gpio_range; + spinlock_t lock; /* lock read/write registers */ + struct mutex mutex; /* serialize adding groups and functions */ + bool safety_port_enabled; +}; + +#define RZT2H_GET_BASE(pctrl, port) \ + ((port) > RZT2H_MAX_SAFETY_PORTS ? (pctrl)->base0 : (pctrl)->base1) + +#define RZT2H_PINCTRL_REG_ACCESS(size, type) \ +static inline void rzt2h_pinctrl_write##size(struct rzt2h_pinctrl *pctrl, u8 port, \ + type val, unsigned int offset) \ +{ \ + write##size(val, RZT2H_GET_BASE(pctrl, port) + offset); \ +} \ +static inline type rzt2h_pinctrl_read##size(struct rzt2h_pinctrl *pctrl, u8 port, \ + unsigned int offset) \ +{ \ + return read##size(RZT2H_GET_BASE(pctrl, port) + offset); \ +} + +RZT2H_PINCTRL_REG_ACCESS(b, u8) +RZT2H_PINCTRL_REG_ACCESS(w, u16) +RZT2H_PINCTRL_REG_ACCESS(q, u64) + +static int rzt2h_validate_pin(struct rzt2h_pinctrl *pctrl, unsigned int offset) +{ + u8 port = RZT2H_PIN_ID_TO_PORT(offset); + u8 pin = RZT2H_PIN_ID_TO_PIN(offset); + u8 pincfg; + + if (offset >= pctrl->data->n_port_pins || port >= pctrl->data->n_ports) + return -EINVAL; + + if (!pctrl->safety_port_enabled && port <= RZT2H_MAX_SAFETY_PORTS) + return -EINVAL; + + pincfg = pctrl->data->port_pin_configs[port]; + return (pincfg & BIT(pin)) ? 0 : -EINVAL; +} + +static void rzt2h_pinctrl_set_pfc_mode(struct rzt2h_pinctrl *pctrl, + u8 port, u8 pin, u8 func) +{ + u64 reg64; + u16 reg16; + + guard(spinlock_irqsave)(&pctrl->lock); + + /* Set pin to 'Non-use (Hi-Z input protection)' */ + reg16 = rzt2h_pinctrl_readw(pctrl, port, PM(port)); + reg16 &= ~PM_PIN_MASK(pin); + rzt2h_pinctrl_writew(pctrl, port, reg16, PM(port)); + + /* Temporarily switch to GPIO mode with PMC register */ + reg16 = rzt2h_pinctrl_readb(pctrl, port, PMC(port)); + rzt2h_pinctrl_writeb(pctrl, port, reg16 & ~BIT(pin), PMC(port)); + + /* Select Pin function mode with PFC register */ + reg64 = rzt2h_pinctrl_readq(pctrl, port, PFC(port)); + reg64 &= ~PFC_PIN_MASK(pin); + rzt2h_pinctrl_writeq(pctrl, port, reg64 | ((u64)func << (pin * 8)), PFC(port)); + + /* Switch to Peripheral pin function with PMC register */ + reg16 = rzt2h_pinctrl_readb(pctrl, port, PMC(port)); + rzt2h_pinctrl_writeb(pctrl, port, reg16 | BIT(pin), PMC(port)); +}; + +static int rzt2h_pinctrl_set_mux(struct pinctrl_dev *pctldev, + unsigned int func_selector, + unsigned int group_selector) +{ + struct rzt2h_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + const struct function_desc *func; + struct group_desc *group; + const unsigned int *pins; + unsigned int i; + u8 *psel_val; + int ret; + + func = pinmux_generic_get_function(pctldev, func_selector); + if (!func) + return -EINVAL; + + group = pinctrl_generic_get_group(pctldev, group_selector); + if (!group) + return -EINVAL; + + psel_val = func->data; + pins = group->grp.pins; + + for (i = 0; i < group->grp.npins; i++) { + dev_dbg(pctrl->dev, "port:%u pin:%u PSEL:%u\n", + RZT2H_PIN_ID_TO_PORT(pins[i]), RZT2H_PIN_ID_TO_PIN(pins[i]), + psel_val[i]); + ret = rzt2h_validate_pin(pctrl, pins[i]); + if (ret) + return ret; + + rzt2h_pinctrl_set_pfc_mode(pctrl, RZT2H_PIN_ID_TO_PORT(pins[i]), + RZT2H_PIN_ID_TO_PIN(pins[i]), psel_val[i]); + } + + return 0; +}; + +static int rzt2h_map_add_config(struct pinctrl_map *map, + const char *group_or_pin, + enum pinctrl_map_type type, + unsigned long *configs, + unsigned int num_configs) +{ + unsigned long *cfgs; + + cfgs = kmemdup_array(configs, num_configs, sizeof(*cfgs), GFP_KERNEL); + if (!cfgs) + return -ENOMEM; + + map->type = type; + map->data.configs.group_or_pin = group_or_pin; + map->data.configs.configs = cfgs; + map->data.configs.num_configs = num_configs; + + return 0; +} + +static int rzt2h_dt_subnode_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct device_node *parent, + struct pinctrl_map **map, + unsigned int *num_maps, + unsigned int *index) +{ + struct rzt2h_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct pinctrl_map *maps = *map; + unsigned int nmaps = *num_maps; + unsigned long *configs = NULL; + unsigned int num_pinmux = 0; + unsigned int idx = *index; + unsigned int num_pins, i; + unsigned int num_configs; + struct property *pinmux; + struct property *prop; + int ret, gsel, fsel; + const char **pin_fn; + unsigned int *pins; + const char *name; + const char *pin; + u8 *psel_val; + + pinmux = of_find_property(np, "pinmux", NULL); + if (pinmux) + num_pinmux = pinmux->length / sizeof(u32); + + ret = of_property_count_strings(np, "pins"); + if (ret == -EINVAL) { + num_pins = 0; + } else if (ret < 0) { + dev_err(pctrl->dev, "Invalid pins list in DT\n"); + return ret; + } else { + num_pins = ret; + } + + if (!num_pinmux && !num_pins) + return 0; + + if (num_pinmux && num_pins) { + dev_err(pctrl->dev, + "DT node must contain either a pinmux or pins and not both\n"); + return -EINVAL; + } + + ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, &num_configs); + if (ret < 0) + return ret; + + if (num_pins && !num_configs) { + dev_err(pctrl->dev, "DT node must contain a config\n"); + ret = -ENODEV; + goto done; + } + + if (num_pinmux) { + nmaps += 1; + if (num_configs) + nmaps += 1; + } + + if (num_pins) + nmaps += num_pins; + + maps = krealloc_array(maps, nmaps, sizeof(*maps), GFP_KERNEL); + if (!maps) { + ret = -ENOMEM; + goto done; + } + + *map = maps; + *num_maps = nmaps; + if (num_pins) { + of_property_for_each_string(np, "pins", prop, pin) { + ret = rzt2h_map_add_config(&maps[idx], pin, + PIN_MAP_TYPE_CONFIGS_PIN, + configs, num_configs); + if (ret < 0) + goto done; + + idx++; + } + ret = 0; + goto done; + } + + pins = devm_kcalloc(pctrl->dev, num_pinmux, sizeof(*pins), GFP_KERNEL); + psel_val = devm_kcalloc(pctrl->dev, num_pinmux, sizeof(*psel_val), + GFP_KERNEL); + pin_fn = devm_kzalloc(pctrl->dev, sizeof(*pin_fn), GFP_KERNEL); + if (!pins || !psel_val || !pin_fn) { + ret = -ENOMEM; + goto done; + } + + /* Collect pin locations and mux settings from DT properties */ + for (i = 0; i < num_pinmux; ++i) { + u32 value; + + ret = of_property_read_u32_index(np, "pinmux", i, &value); + if (ret) + goto done; + pins[i] = FIELD_GET(MUX_PIN_ID_MASK, value); + psel_val[i] = FIELD_GET(MUX_FUNC_MASK, value); + } + + if (parent) { + name = devm_kasprintf(pctrl->dev, GFP_KERNEL, "%pOFn.%pOFn", + parent, np); + if (!name) { + ret = -ENOMEM; + goto done; + } + } else { + name = np->name; + } + + if (num_configs) { + ret = rzt2h_map_add_config(&maps[idx], name, + PIN_MAP_TYPE_CONFIGS_GROUP, + configs, num_configs); + if (ret < 0) + goto done; + + idx++; + } + + scoped_guard(mutex, &pctrl->mutex) { + /* Register a single pin group listing all the pins we read from DT */ + gsel = pinctrl_generic_add_group(pctldev, name, pins, num_pinmux, NULL); + if (gsel < 0) { + ret = gsel; + goto done; + } + + /* + * Register a single group function where the 'data' is an array PSEL + * register values read from DT. + */ + pin_fn[0] = name; + fsel = pinmux_generic_add_function(pctldev, name, pin_fn, 1, psel_val); + if (fsel < 0) { + ret = fsel; + goto remove_group; + } + } + + maps[idx].type = PIN_MAP_TYPE_MUX_GROUP; + maps[idx].data.mux.group = name; + maps[idx].data.mux.function = name; + idx++; + + dev_dbg(pctrl->dev, "Parsed %pOF with %d pins\n", np, num_pinmux); + ret = 0; + goto done; + +remove_group: + pinctrl_generic_remove_group(pctldev, gsel); +done: + *index = idx; + kfree(configs); + return ret; +} + +static void rzt2h_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, + unsigned int num_maps) +{ + unsigned int i; + + if (!map) + return; + + for (i = 0; i < num_maps; ++i) { + if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP || + map[i].type == PIN_MAP_TYPE_CONFIGS_PIN) + kfree(map[i].data.configs.configs); + } + kfree(map); +} + +static int rzt2h_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, + unsigned int *num_maps) +{ + struct rzt2h_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + unsigned int index; + int ret; + + *map = NULL; + *num_maps = 0; + index = 0; + + for_each_child_of_node_scoped(np, child) { + ret = rzt2h_dt_subnode_to_map(pctldev, child, np, map, + num_maps, &index); + if (ret < 0) + goto done; + } + + if (*num_maps == 0) { + ret = rzt2h_dt_subnode_to_map(pctldev, np, NULL, map, + num_maps, &index); + if (ret < 0) + goto done; + } + + if (*num_maps) + return 0; + + dev_err(pctrl->dev, "no mapping found in node %pOF\n", np); + ret = -EINVAL; + +done: + rzt2h_dt_free_map(pctldev, *map, *num_maps); + return ret; +} + +static const struct pinctrl_ops rzt2h_pinctrl_pctlops = { + .get_groups_count = pinctrl_generic_get_group_count, + .get_group_name = pinctrl_generic_get_group_name, + .get_group_pins = pinctrl_generic_get_group_pins, + .dt_node_to_map = rzt2h_dt_node_to_map, + .dt_free_map = rzt2h_dt_free_map, +}; + +static const struct pinmux_ops rzt2h_pinctrl_pmxops = { + .get_functions_count = pinmux_generic_get_function_count, + .get_function_name = pinmux_generic_get_function_name, + .get_function_groups = pinmux_generic_get_function_groups, + .set_mux = rzt2h_pinctrl_set_mux, + .strict = true, +}; + +static int rzt2h_gpio_request(struct gpio_chip *chip, unsigned int offset) +{ + struct rzt2h_pinctrl *pctrl = gpiochip_get_data(chip); + u8 port = RZT2H_PIN_ID_TO_PORT(offset); + u8 bit = RZT2H_PIN_ID_TO_PIN(offset); + int ret; + u8 reg; + + ret = rzt2h_validate_pin(pctrl, offset); + if (ret) + return ret; + + ret = pinctrl_gpio_request(chip, offset); + if (ret) + return ret; + + guard(spinlock_irqsave)(&pctrl->lock); + + /* Select GPIO mode in PMC Register */ + reg = rzt2h_pinctrl_readb(pctrl, port, PMC(port)); + reg &= ~BIT(bit); + rzt2h_pinctrl_writeb(pctrl, port, reg, PMC(port)); + + return 0; +} + +static void rzt2h_gpio_set_direction(struct rzt2h_pinctrl *pctrl, u32 port, + u8 bit, bool output) +{ + u16 reg; + + guard(spinlock_irqsave)(&pctrl->lock); + + reg = rzt2h_pinctrl_readw(pctrl, port, PM(port)); + reg &= ~PM_PIN_MASK(bit); + + reg |= (output ? PM_OUTPUT : PM_INPUT) << (bit * 2); + rzt2h_pinctrl_writew(pctrl, port, reg, PM(port)); +} + +static int rzt2h_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) +{ + struct rzt2h_pinctrl *pctrl = gpiochip_get_data(chip); + u8 port = RZT2H_PIN_ID_TO_PORT(offset); + u8 bit = RZT2H_PIN_ID_TO_PIN(offset); + u16 reg; + int ret; + + ret = rzt2h_validate_pin(pctrl, offset); + if (ret) + return ret; + + if (rzt2h_pinctrl_readb(pctrl, port, PMC(port)) & BIT(bit)) + return -EINVAL; + + reg = rzt2h_pinctrl_readw(pctrl, port, PM(port)); + reg = (reg >> (bit * 2)) & PM_MASK; + if (reg & PM_OUTPUT) + return GPIO_LINE_DIRECTION_OUT; + if (reg & PM_INPUT) + return GPIO_LINE_DIRECTION_IN; + + return -EINVAL; +} + +static int rzt2h_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + struct rzt2h_pinctrl *pctrl = gpiochip_get_data(chip); + u8 port = RZT2H_PIN_ID_TO_PORT(offset); + u8 bit = RZT2H_PIN_ID_TO_PIN(offset); + u8 reg; + + guard(spinlock_irqsave)(&pctrl->lock); + + reg = rzt2h_pinctrl_readb(pctrl, port, P(port)); + if (value) + rzt2h_pinctrl_writeb(pctrl, port, reg | BIT(bit), P(port)); + else + rzt2h_pinctrl_writeb(pctrl, port, reg & ~BIT(bit), P(port)); + + return 0; +} + +static int rzt2h_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct rzt2h_pinctrl *pctrl = gpiochip_get_data(chip); + u8 port = RZT2H_PIN_ID_TO_PORT(offset); + u8 bit = RZT2H_PIN_ID_TO_PIN(offset); + u16 reg; + + reg = rzt2h_pinctrl_readw(pctrl, port, PM(port)); + reg = (reg >> (bit * 2)) & PM_MASK; + if (reg & PM_INPUT) + return !!(rzt2h_pinctrl_readb(pctrl, port, PIN(port)) & BIT(bit)); + if (reg & PM_OUTPUT) + return !!(rzt2h_pinctrl_readb(pctrl, port, P(port)) & BIT(bit)); + + return -EINVAL; +} + +static int rzt2h_gpio_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + struct rzt2h_pinctrl *pctrl = gpiochip_get_data(chip); + u8 port = RZT2H_PIN_ID_TO_PORT(offset); + u8 bit = RZT2H_PIN_ID_TO_PIN(offset); + + rzt2h_gpio_set_direction(pctrl, port, bit, false); + + return 0; +} + +static int rzt2h_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct rzt2h_pinctrl *pctrl = gpiochip_get_data(chip); + u8 port = RZT2H_PIN_ID_TO_PORT(offset); + u8 bit = RZT2H_PIN_ID_TO_PIN(offset); + + rzt2h_gpio_set(chip, offset, value); + rzt2h_gpio_set_direction(pctrl, port, bit, true); + + return 0; +} + +static void rzt2h_gpio_free(struct gpio_chip *chip, unsigned int offset) +{ + pinctrl_gpio_free(chip, offset); + + /* + * Set the GPIO as an input to ensure that the next GPIO request won't + * drive the GPIO pin as an output. + */ + rzt2h_gpio_direction_input(chip, offset); +} + +static const char * const rzt2h_gpio_names[] = { + "P00_0", "P00_1", "P00_2", "P00_3", "P00_4", "P00_5", "P00_6", "P00_7", + "P01_0", "P01_1", "P01_2", "P01_3", "P01_4", "P01_5", "P01_6", "P01_7", + "P02_0", "P02_1", "P02_2", "P02_3", "P02_4", "P02_5", "P02_6", "P02_7", + "P03_0", "P03_1", "P03_2", "P03_3", "P03_4", "P03_5", "P03_6", "P03_7", + "P04_0", "P04_1", "P04_2", "P04_3", "P04_4", "P04_5", "P04_6", "P04_7", + "P05_0", "P05_1", "P05_2", "P05_3", "P05_4", "P05_5", "P05_6", "P05_7", + "P06_0", "P06_1", "P06_2", "P06_3", "P06_4", "P06_5", "P06_6", "P06_7", + "P07_0", "P07_1", "P07_2", "P07_3", "P07_4", "P07_5", "P07_6", "P07_7", + "P08_0", "P08_1", "P08_2", "P08_3", "P08_4", "P08_5", "P08_6", "P08_7", + "P09_0", "P09_1", "P09_2", "P09_3", "P09_4", "P09_5", "P09_6", "P09_7", + "P10_0", "P10_1", "P10_2", "P10_3", "P10_4", "P10_5", "P10_6", "P10_7", + "P11_0", "P11_1", "P11_2", "P11_3", "P11_4", "P11_5", "P11_6", "P11_7", + "P12_0", "P12_1", "P12_2", "P12_3", "P12_4", "P12_5", "P12_6", "P12_7", + "P13_0", "P13_1", "P13_2", "P13_3", "P13_4", "P13_5", "P13_6", "P13_7", + "P14_0", "P14_1", "P14_2", "P14_3", "P14_4", "P14_5", "P14_6", "P14_7", + "P15_0", "P15_1", "P15_2", "P15_3", "P15_4", "P15_5", "P15_6", "P15_7", + "P16_0", "P16_1", "P16_2", "P16_3", "P16_4", "P16_5", "P16_6", "P16_7", + "P17_0", "P17_1", "P17_2", "P17_3", "P17_4", "P17_5", "P17_6", "P17_7", + "P18_0", "P18_1", "P18_2", "P18_3", "P18_4", "P18_5", "P18_6", "P18_7", + "P19_0", "P19_1", "P19_2", "P19_3", "P19_4", "P19_5", "P19_6", "P19_7", + "P20_0", "P20_1", "P20_2", "P20_3", "P20_4", "P20_5", "P20_6", "P20_7", + "P21_0", "P21_1", "P21_2", "P21_3", "P21_4", "P21_5", "P21_6", "P21_7", + "P22_0", "P22_1", "P22_2", "P22_3", "P22_4", "P22_5", "P22_6", "P22_7", + "P23_0", "P23_1", "P23_2", "P23_3", "P23_4", "P23_5", "P23_6", "P23_7", + "P24_0", "P24_1", "P24_2", "P24_3", "P24_4", "P24_5", "P24_6", "P24_7", + "P25_0", "P25_1", "P25_2", "P25_3", "P25_4", "P25_5", "P25_6", "P25_7", + "P26_0", "P26_1", "P26_2", "P26_3", "P26_4", "P26_5", "P26_6", "P26_7", + "P27_0", "P27_1", "P27_2", "P27_3", "P27_4", "P27_5", "P27_6", "P27_7", + "P28_0", "P28_1", "P28_2", "P28_3", "P28_4", "P28_5", "P28_6", "P28_7", + "P29_0", "P29_1", "P29_2", "P29_3", "P29_4", "P29_5", "P29_6", "P29_7", + "P30_0", "P30_1", "P30_2", "P30_3", "P30_4", "P30_5", "P30_6", "P30_7", + "P31_0", "P31_1", "P31_2", "P31_3", "P31_4", "P31_5", "P31_6", "P31_7", + "P32_0", "P32_1", "P32_2", "P32_3", "P32_4", "P32_5", "P32_6", "P32_7", + "P33_0", "P33_1", "P33_2", "P33_3", "P33_4", "P33_5", "P33_6", "P33_7", + "P34_0", "P34_1", "P34_2", "P34_3", "P34_4", "P34_5", "P34_6", "P34_7", + "P35_0", "P35_1", "P35_2", "P35_3", "P35_4", "P35_5", "P35_6", "P35_7", +}; + +static int rzt2h_gpio_register(struct rzt2h_pinctrl *pctrl) +{ + struct pinctrl_gpio_range *range = &pctrl->gpio_range; + struct gpio_chip *chip = &pctrl->gpio_chip; + struct device *dev = pctrl->dev; + struct of_phandle_args of_args; + int ret; + + ret = of_parse_phandle_with_fixed_args(dev->of_node, "gpio-ranges", 3, 0, &of_args); + if (ret) + return dev_err_probe(dev, ret, "Unable to parse gpio-ranges\n"); + + if (of_args.args[0] != 0 || of_args.args[1] != 0 || + of_args.args[2] != pctrl->data->n_port_pins) + return dev_err_probe(dev, -EINVAL, + "gpio-ranges does not match selected SOC\n"); + + chip->base = -1; + chip->parent = dev; + chip->owner = THIS_MODULE; + chip->ngpio = of_args.args[2]; + chip->names = rzt2h_gpio_names; + chip->request = rzt2h_gpio_request; + chip->free = rzt2h_gpio_free; + chip->get_direction = rzt2h_gpio_get_direction; + chip->direction_input = rzt2h_gpio_direction_input; + chip->direction_output = rzt2h_gpio_direction_output; + chip->get = rzt2h_gpio_get; + chip->set = rzt2h_gpio_set; + chip->label = dev_name(dev); + + range->id = 0; + range->pin_base = 0; + range->base = 0; + range->npins = chip->ngpio; + range->name = chip->label; + range->gc = chip; + + ret = devm_gpiochip_add_data(dev, chip, pctrl); + if (ret) + return dev_err_probe(dev, ret, "gpiochip registration failed\n"); + + return ret; +} + +static int rzt2h_pinctrl_register(struct rzt2h_pinctrl *pctrl) +{ + struct pinctrl_desc *desc = &pctrl->desc; + struct device *dev = pctrl->dev; + struct pinctrl_pin_desc *pins; + unsigned int i, j; + int ret; + + desc->name = DRV_NAME; + desc->npins = pctrl->data->n_port_pins; + desc->pctlops = &rzt2h_pinctrl_pctlops; + desc->pmxops = &rzt2h_pinctrl_pmxops; + desc->owner = THIS_MODULE; + + pins = devm_kcalloc(dev, desc->npins, sizeof(*pins), GFP_KERNEL); + if (!pins) + return -ENOMEM; + + pctrl->pins = pins; + desc->pins = pins; + + for (i = 0, j = 0; i < pctrl->data->n_port_pins; i++) { + pins[i].number = i; + pins[i].name = rzt2h_gpio_names[i]; + if (i && !(i % RZT2H_PINS_PER_PORT)) + j++; + } + + ret = devm_pinctrl_register_and_init(dev, desc, pctrl, &pctrl->pctl); + if (ret) + return dev_err_probe(dev, ret, "pinctrl registration failed\n"); + + ret = pinctrl_enable(pctrl->pctl); + if (ret) + return dev_err_probe(dev, ret, "pinctrl enable failed\n"); + + return rzt2h_gpio_register(pctrl); +} + +static int rzt2h_pinctrl_cfg_regions(struct platform_device *pdev, + struct rzt2h_pinctrl *pctrl) +{ + struct resource *res; + + pctrl->base0 = devm_platform_ioremap_resource_byname(pdev, "nsr"); + if (IS_ERR(pctrl->base0)) + return PTR_ERR(pctrl->base0); + + /* + * Open-coded instead of using devm_platform_ioremap_resource_byname() + * because the "srs" region is optional. + */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "srs"); + if (res) { + u8 port; + + pctrl->base1 = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pctrl->base1)) + return PTR_ERR(pctrl->base1); + + pctrl->safety_port_enabled = true; + + /* Configure to select safety region 0x812c0xxx */ + for (port = 0; port <= RZT2H_MAX_SAFETY_PORTS; port++) + writeb(0x0, pctrl->base1 + RSELP(port)); + } + + return 0; +} + +static int rzt2h_pinctrl_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rzt2h_pinctrl *pctrl; + int ret; + + pctrl = devm_kzalloc(dev, sizeof(*pctrl), GFP_KERNEL); + if (!pctrl) + return -ENOMEM; + + pctrl->dev = dev; + pctrl->data = of_device_get_match_data(dev); + + ret = rzt2h_pinctrl_cfg_regions(pdev, pctrl); + if (ret) + return ret; + + spin_lock_init(&pctrl->lock); + mutex_init(&pctrl->mutex); + platform_set_drvdata(pdev, pctrl); + + return rzt2h_pinctrl_register(pctrl); +} + +static const u8 r9a09g077_gpio_configs[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, +}; + +static struct rzt2h_pinctrl_data r9a09g077_data = { + .n_port_pins = ARRAY_SIZE(r9a09g077_gpio_configs) * RZT2H_PINS_PER_PORT, + .port_pin_configs = r9a09g077_gpio_configs, + .n_ports = ARRAY_SIZE(r9a09g077_gpio_configs), +}; + +static const struct of_device_id rzt2h_pinctrl_of_table[] = { + { + .compatible = "renesas,r9a09g077-pinctrl", + .data = &r9a09g077_data, + }, + { /* sentinel */ } +}; + +static struct platform_driver rzt2h_pinctrl_driver = { + .driver = { + .name = DRV_NAME, + .of_match_table = of_match_ptr(rzt2h_pinctrl_of_table), + .suppress_bind_attrs = true, + }, + .probe = rzt2h_pinctrl_probe, +}; + +static int __init rzt2h_pinctrl_init(void) +{ + return platform_driver_register(&rzt2h_pinctrl_driver); +} +core_initcall(rzt2h_pinctrl_init); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Thierry Bultel "); +MODULE_AUTHOR("Lad Prabhakar "); +MODULE_DESCRIPTION("Pin and gpio controller driver for the RZ/T2H family"); From d1d31e2739ff063da1e85cd9b44316ca5cccdba8 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Fri, 8 Aug 2025 14:30:17 +0100 Subject: [PATCH 01538/11391] pinctrl: renesas: rzt2h: Add support for RZ/N2H The Renesas RZ/N2H (R9A09G087) SoC shares a similar pin controller architecture with the RZ/T2H (R9A09G077) SoC, differing primarily in the number of supported pins: 576 on RZ/N2H versus 729 on RZ/T2H. Add the necessary pin configuration data and compatible string to enable support for the RZ/N2H SoC in the RZ/T2H pinctrl driver. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250808133017.2053637-4-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/renesas/Kconfig | 1 + drivers/pinctrl/renesas/pinctrl-rzt2h.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/drivers/pinctrl/renesas/Kconfig b/drivers/pinctrl/renesas/Kconfig index c8b84c158e86..8cbd79a13414 100644 --- a/drivers/pinctrl/renesas/Kconfig +++ b/drivers/pinctrl/renesas/Kconfig @@ -45,6 +45,7 @@ config PINCTRL_RENESAS select PINCTRL_RZG2L if ARCH_R9A09G056 select PINCTRL_RZG2L if ARCH_R9A09G057 select PINCTRL_RZT2H if ARCH_R9A09G077 + select PINCTRL_RZT2H if ARCH_R9A09G087 select PINCTRL_PFC_SH7203 if CPU_SUBTYPE_SH7203 select PINCTRL_PFC_SH7264 if CPU_SUBTYPE_SH7264 select PINCTRL_PFC_SH7269 if CPU_SUBTYPE_SH7269 diff --git a/drivers/pinctrl/renesas/pinctrl-rzt2h.c b/drivers/pinctrl/renesas/pinctrl-rzt2h.c index 28f5d48e33db..3872638f5ebb 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzt2h.c +++ b/drivers/pinctrl/renesas/pinctrl-rzt2h.c @@ -762,17 +762,33 @@ static const u8 r9a09g077_gpio_configs[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, }; +static const u8 r9a09g087_gpio_configs[] = { + 0x1f, 0xff, 0xff, 0x1f, 0x00, 0xfe, 0xff, 0x00, 0x7e, 0xf0, 0xff, 0x01, + 0xff, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x01, + 0xe0, 0xff, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfc, 0x7f, +}; + static struct rzt2h_pinctrl_data r9a09g077_data = { .n_port_pins = ARRAY_SIZE(r9a09g077_gpio_configs) * RZT2H_PINS_PER_PORT, .port_pin_configs = r9a09g077_gpio_configs, .n_ports = ARRAY_SIZE(r9a09g077_gpio_configs), }; +static struct rzt2h_pinctrl_data r9a09g087_data = { + .n_port_pins = ARRAY_SIZE(r9a09g087_gpio_configs) * RZT2H_PINS_PER_PORT, + .port_pin_configs = r9a09g087_gpio_configs, + .n_ports = ARRAY_SIZE(r9a09g087_gpio_configs), +}; + static const struct of_device_id rzt2h_pinctrl_of_table[] = { { .compatible = "renesas,r9a09g077-pinctrl", .data = &r9a09g077_data, }, + { + .compatible = "renesas,r9a09g087-pinctrl", + .data = &r9a09g087_data, + }, { /* sentinel */ } }; From ae95807b00e1639b3f6ab94eb2cd887266e4f766 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 28 Jul 2025 01:58:11 +0200 Subject: [PATCH 01539/11391] arm64: dts: renesas: sparrow-hawk: Invert microSD voltage selector on EVTB1 Invert the polarity of microSD voltage selector on Retronix R-Car V4H Sparrow Hawk board. The voltage selector was not populated on prototype EVTA1 boards, and is implemented slightly different on EVTB1 boards. As the EVTA1 boards are from a limited run and generally not available, update the DT to make it compatible with EVTB1 microSD voltage selector. Fixes: a719915e76f2 ("arm64: dts: renesas: r8a779g3: Add Retronix R-Car V4H Sparrow Hawk board support") Signed-off-by: Marek Vasut Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250727235905.290427-1-marek.vasut+renesas@mailbox.org Signed-off-by: Geert Uytterhoeven --- arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts b/arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts index 75b1b789ae1d..33c6c2a5c2c5 100644 --- a/arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts +++ b/arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts @@ -186,7 +186,7 @@ vcc_sdhi: regulator-vcc-sdhi { regulator-max-microvolt = <3300000>; gpios = <&gpio8 13 GPIO_ACTIVE_HIGH>; gpios-states = <1>; - states = <3300000 0>, <1800000 1>; + states = <1800000 0>, <3300000 1>; }; }; From 7d1e3aa2826a22f68f1850c31ac96348272fa356 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 6 Aug 2025 21:28:04 +0200 Subject: [PATCH 01540/11391] arm64: dts: renesas: sparrow-hawk: Set VDDQ18_25_AVB voltage on EVTB1 The Retronix R-Car V4H Sparrow Hawk EVTB1 uses 1V8 IO voltage supply for VDDQ18_25_AVB power rail. Update the AVB0 pinmux to reflect the change in IO voltage. Since the VDDQ18_25_AVB power rail is shared, all four AVB0, AVB1, AVB2, TSN0 PFC/GPIO POC[7..4] registers have to be configured the same way. As the EVTA1 boards are from a limited run and generally not available, update the DT to make it compatible with EVTB1 IO voltage settings. Fixes: a719915e76f2 ("arm64: dts: renesas: r8a779g3: Add Retronix R-Car V4H Sparrow Hawk board support") Signed-off-by: Marek Vasut Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250806192821.133302-1-marek.vasut+renesas@mailbox.org Signed-off-by: Geert Uytterhoeven --- arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts b/arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts index 33c6c2a5c2c5..1da8e476b219 100644 --- a/arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts +++ b/arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts @@ -592,6 +592,10 @@ pins-mii { drive-strength = <21>; }; + pins-vddq18-25-avb { + pins = "PIN_VDDQ_AVB0", "PIN_VDDQ_AVB1", "PIN_VDDQ_AVB2", "PIN_VDDQ_TSN0"; + power-source = <1800>; + }; }; /* Page 28 / CANFD_IF */ From 115b557b6f61ca279a4754b20b8686039fdb5234 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 19 Aug 2025 15:16:20 +0200 Subject: [PATCH 01541/11391] arm64: dts: renesas: Minor whitespace cleanup The DTS code coding style expects exactly one space around '=' character. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250819131619.86396-2-krzysztof.kozlowski@linaro.org Signed-off-by: Geert Uytterhoeven --- arch/arm64/boot/dts/renesas/r9a09g056.dtsi | 16 ++++++++-------- .../boot/dts/renesas/r9a09g056n48-rzv2n-evk.dts | 2 +- arch/arm64/boot/dts/renesas/r9a09g057.dtsi | 16 ++++++++-------- .../boot/dts/renesas/r9a09g057h44-rzv2h-evk.dts | 2 +- .../boot/dts/renesas/r9a09g057h48-kakip.dts | 2 +- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/arch/arm64/boot/dts/renesas/r9a09g056.dtsi b/arch/arm64/boot/dts/renesas/r9a09g056.dtsi index 10d3b9727ea5..50a3d42d192c 100644 --- a/arch/arm64/boot/dts/renesas/r9a09g056.dtsi +++ b/arch/arm64/boot/dts/renesas/r9a09g056.dtsi @@ -735,10 +735,10 @@ eth0: ethernet@15c30000 { "rx-queue-0", "rx-queue-1", "rx-queue-2", "rx-queue-3", "tx-queue-0", "tx-queue-1", "tx-queue-2", "tx-queue-3"; - clocks = <&cpg CPG_MOD 0xbd>, <&cpg CPG_MOD 0xbc>, - <&cpg CPG_CORE R9A09G056_GBETH_0_CLK_PTP_REF_I>, - <&cpg CPG_MOD 0xb8>, <&cpg CPG_MOD 0xb9>, - <&cpg CPG_MOD 0xba>, <&cpg CPG_MOD 0xbb>; + clocks = <&cpg CPG_MOD 0xbd>, <&cpg CPG_MOD 0xbc>, + <&cpg CPG_CORE R9A09G056_GBETH_0_CLK_PTP_REF_I>, + <&cpg CPG_MOD 0xb8>, <&cpg CPG_MOD 0xb9>, + <&cpg CPG_MOD 0xba>, <&cpg CPG_MOD 0xbb>; clock-names = "stmmaceth", "pclk", "ptp_ref", "tx", "rx", "tx-180", "rx-180"; resets = <&cpg 0xb0>; @@ -836,10 +836,10 @@ eth1: ethernet@15c40000 { "rx-queue-0", "rx-queue-1", "rx-queue-2", "rx-queue-3", "tx-queue-0", "tx-queue-1", "tx-queue-2", "tx-queue-3"; - clocks = <&cpg CPG_MOD 0xc3>, <&cpg CPG_MOD 0xc2>, - <&cpg CPG_CORE R9A09G056_GBETH_1_CLK_PTP_REF_I>, - <&cpg CPG_MOD 0xbe>, <&cpg CPG_MOD 0xbf>, - <&cpg CPG_MOD 0xc0>, <&cpg CPG_MOD 0xc1>; + clocks = <&cpg CPG_MOD 0xc3>, <&cpg CPG_MOD 0xc2>, + <&cpg CPG_CORE R9A09G056_GBETH_1_CLK_PTP_REF_I>, + <&cpg CPG_MOD 0xbe>, <&cpg CPG_MOD 0xbf>, + <&cpg CPG_MOD 0xc0>, <&cpg CPG_MOD 0xc1>; clock-names = "stmmaceth", "pclk", "ptp_ref", "tx", "rx", "tx-180", "rx-180"; resets = <&cpg 0xb1>; diff --git a/arch/arm64/boot/dts/renesas/r9a09g056n48-rzv2n-evk.dts b/arch/arm64/boot/dts/renesas/r9a09g056n48-rzv2n-evk.dts index 03aeea781186..066e66b5d51a 100644 --- a/arch/arm64/boot/dts/renesas/r9a09g056n48-rzv2n-evk.dts +++ b/arch/arm64/boot/dts/renesas/r9a09g056n48-rzv2n-evk.dts @@ -334,7 +334,7 @@ sd1-dat-cmd { usb20_pins: usb20 { ovc { - pinmux = ; /* OVC */ + pinmux = ; /* OVC */ }; vbus { diff --git a/arch/arm64/boot/dts/renesas/r9a09g057.dtsi b/arch/arm64/boot/dts/renesas/r9a09g057.dtsi index 6d0c6449b9ff..e66f5654f2ab 100644 --- a/arch/arm64/boot/dts/renesas/r9a09g057.dtsi +++ b/arch/arm64/boot/dts/renesas/r9a09g057.dtsi @@ -1083,10 +1083,10 @@ eth0: ethernet@15c30000 { "rx-queue-0", "rx-queue-1", "rx-queue-2", "rx-queue-3", "tx-queue-0", "tx-queue-1", "tx-queue-2", "tx-queue-3"; - clocks = <&cpg CPG_MOD 0xbd>, <&cpg CPG_MOD 0xbc>, - <&cpg CPG_CORE R9A09G057_GBETH_0_CLK_PTP_REF_I>, - <&cpg CPG_MOD 0xb8>, <&cpg CPG_MOD 0xb9>, - <&cpg CPG_MOD 0xba>, <&cpg CPG_MOD 0xbb>; + clocks = <&cpg CPG_MOD 0xbd>, <&cpg CPG_MOD 0xbc>, + <&cpg CPG_CORE R9A09G057_GBETH_0_CLK_PTP_REF_I>, + <&cpg CPG_MOD 0xb8>, <&cpg CPG_MOD 0xb9>, + <&cpg CPG_MOD 0xba>, <&cpg CPG_MOD 0xbb>; clock-names = "stmmaceth", "pclk", "ptp_ref", "tx", "rx", "tx-180", "rx-180"; resets = <&cpg 0xb0>; @@ -1184,10 +1184,10 @@ eth1: ethernet@15c40000 { "rx-queue-0", "rx-queue-1", "rx-queue-2", "rx-queue-3", "tx-queue-0", "tx-queue-1", "tx-queue-2", "tx-queue-3"; - clocks = <&cpg CPG_MOD 0xc3>, <&cpg CPG_MOD 0xc2>, - <&cpg CPG_CORE R9A09G057_GBETH_1_CLK_PTP_REF_I>, - <&cpg CPG_MOD 0xbe>, <&cpg CPG_MOD 0xbf>, - <&cpg CPG_MOD 0xc0>, <&cpg CPG_MOD 0xc1>; + clocks = <&cpg CPG_MOD 0xc3>, <&cpg CPG_MOD 0xc2>, + <&cpg CPG_CORE R9A09G057_GBETH_1_CLK_PTP_REF_I>, + <&cpg CPG_MOD 0xbe>, <&cpg CPG_MOD 0xbf>, + <&cpg CPG_MOD 0xc0>, <&cpg CPG_MOD 0xc1>; clock-names = "stmmaceth", "pclk", "ptp_ref", "tx", "rx", "tx-180", "rx-180"; resets = <&cpg 0xb1>; diff --git a/arch/arm64/boot/dts/renesas/r9a09g057h44-rzv2h-evk.dts b/arch/arm64/boot/dts/renesas/r9a09g057h44-rzv2h-evk.dts index 5c3f4e471e3d..5c06bce3d5b4 100644 --- a/arch/arm64/boot/dts/renesas/r9a09g057h44-rzv2h-evk.dts +++ b/arch/arm64/boot/dts/renesas/r9a09g057h44-rzv2h-evk.dts @@ -353,7 +353,7 @@ sd1_cd { usb20_pins: usb20 { ovc { - pinmux = ; /* OVC */ + pinmux = ; /* OVC */ }; vbus { diff --git a/arch/arm64/boot/dts/renesas/r9a09g057h48-kakip.dts b/arch/arm64/boot/dts/renesas/r9a09g057h48-kakip.dts index f6f2cb7d2d25..adf3ab8aef2b 100644 --- a/arch/arm64/boot/dts/renesas/r9a09g057h48-kakip.dts +++ b/arch/arm64/boot/dts/renesas/r9a09g057h48-kakip.dts @@ -84,7 +84,7 @@ &ostm7 { &pinctrl { scif_pins: scif { - pins = "SCIF_RXD", "SCIF_TXD"; + pins = "SCIF_RXD", "SCIF_TXD"; }; sd0-pwr-en-hog { From b8dc2302544b66367bedec19ee16477ff5a25a92 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 18 Aug 2025 16:24:03 +0200 Subject: [PATCH 01542/11391] pinctrl: stm32: Constify static 'pinctrl_desc' The local static 'struct pinctrl_desc' is not modified, so can be made const for code safety. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/20250818142402.132008-2-krzysztof.kozlowski@linaro.org Signed-off-by: Linus Walleij --- drivers/pinctrl/stm32/pinctrl-stm32-hdp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/stm32/pinctrl-stm32-hdp.c b/drivers/pinctrl/stm32/pinctrl-stm32-hdp.c index dea49b9aabf2..a8a4c2eee837 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32-hdp.c +++ b/drivers/pinctrl/stm32/pinctrl-stm32-hdp.c @@ -576,7 +576,7 @@ static const struct pinmux_ops stm32_hdp_pinmux_ops = { .gpio_set_direction = NULL, }; -static struct pinctrl_desc stm32_hdp_pdesc = { +static const struct pinctrl_desc stm32_hdp_pdesc = { .name = DRIVER_NAME, .pins = stm32_hdp_pins, .npins = ARRAY_SIZE(stm32_hdp_pins), From 148bda0cfeae913b1212c4c683e6d3f6ae1a5e69 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 30 Jun 2025 21:21:31 +0200 Subject: [PATCH 01543/11391] 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 01544/11391] 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 01545/11391] 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 01546/11391] 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 01547/11391] 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 01548/11391] 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 01549/11391] 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 01550/11391] 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 01551/11391] 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 01552/11391] 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 @@ static int rzv2h_ddiv_set_rate(struct clk_hw *hw, unsigned long rate, 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 01553/11391] 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 fa40cbe1c86b6626d548cf2eb555bee4eea7566c Mon Sep 17 00:00:00 2001 From: Paresh Bhagat Date: Wed, 20 Aug 2025 14:03:30 +0530 Subject: [PATCH 01554/11391] cpufreq: dt-platdev: Blacklist ti,am62d2 SoC Add ti,am62d2 SoC to the blacklist as the ti-cpufreq driver will handle creating the cpufreq-dt platform device after it completes and ensure it is not created twice. Signed-off-by: Paresh Bhagat Signed-off-by: Viresh Kumar --- drivers/cpufreq/cpufreq-dt-platdev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c index 1a9d9d008002..cd1816a12bb9 100644 --- a/drivers/cpufreq/cpufreq-dt-platdev.c +++ b/drivers/cpufreq/cpufreq-dt-platdev.c @@ -189,6 +189,7 @@ static const struct of_device_id blocklist[] __initconst = { { .compatible = "ti,omap3", }, { .compatible = "ti,am625", }, { .compatible = "ti,am62a7", }, + { .compatible = "ti,am62d2", }, { .compatible = "ti,am62p5", }, { .compatible = "qcom,ipq5332", }, From b5af45302ebc141662b2b60c713c9202e88c943c Mon Sep 17 00:00:00 2001 From: Paresh Bhagat Date: Wed, 20 Aug 2025 14:03:31 +0530 Subject: [PATCH 01555/11391] cpufreq: ti: Add support for AM62D2 Add support for TI K3 AM62D2 SoC to read speed and revision values from hardware and pass to OPP layer. AM62D shares the same configuations as AM62A so use existing am62a7_soc_data. Signed-off-by: Paresh Bhagat Signed-off-by: Viresh Kumar --- drivers/cpufreq/ti-cpufreq.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/cpufreq/ti-cpufreq.c b/drivers/cpufreq/ti-cpufreq.c index 5a5147277cd0..9a912d309315 100644 --- a/drivers/cpufreq/ti-cpufreq.c +++ b/drivers/cpufreq/ti-cpufreq.c @@ -310,6 +310,7 @@ static const struct soc_device_attribute k3_cpufreq_soc[] = { { .family = "AM62X", .revision = "SR1.0" }, { .family = "AM62AX", .revision = "SR1.0" }, { .family = "AM62PX", .revision = "SR1.0" }, + { .family = "AM62DX", .revision = "SR1.0" }, { /* sentinel */ } }; @@ -457,6 +458,7 @@ static const struct of_device_id ti_cpufreq_of_match[] __maybe_unused = { { .compatible = "ti,omap36xx", .data = &omap36xx_soc_data, }, { .compatible = "ti,am625", .data = &am625_soc_data, }, { .compatible = "ti,am62a7", .data = &am62a7_soc_data, }, + { .compatible = "ti,am62d2", .data = &am62a7_soc_data, }, { .compatible = "ti,am62p5", .data = &am62p5_soc_data, }, /* legacy */ { .compatible = "ti,omap3430", .data = &omap34xx_soc_data, }, From 08d07f25fd5e2ca3d32444f8c41e9e6e59e8a54e Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 15 Aug 2025 14:55:49 +0200 Subject: [PATCH 01556/11391] netfilter: ctnetlink: remove refcounting in dying list dumping There is no need to keep the object alive via refcount, use a cookie and then use that as the skip hint for dump resumption. Unlike the two earlier, similar patches in this file, this is a cleanup without intended side effects. Signed-off-by: Florian Westphal --- net/netfilter/nf_conntrack_netlink.c | 39 +++++++--------------------- 1 file changed, 10 insertions(+), 29 deletions(-) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 50fd6809380f..3a04665adf99 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -60,7 +60,7 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("List and change connection tracking table"); struct ctnetlink_list_dump_ctx { - struct nf_conn *last; + unsigned long last_id; unsigned int cpu; bool done; }; @@ -1733,16 +1733,6 @@ static int ctnetlink_get_conntrack(struct sk_buff *skb, return nfnetlink_unicast(skb2, info->net, NETLINK_CB(skb).portid); } -static int ctnetlink_done_list(struct netlink_callback *cb) -{ - struct ctnetlink_list_dump_ctx *ctx = (void *)cb->ctx; - - if (ctx->last) - nf_ct_put(ctx->last); - - return 0; -} - #ifdef CONFIG_NF_CONNTRACK_EVENTS static int ctnetlink_dump_one_entry(struct sk_buff *skb, struct netlink_callback *cb, @@ -1757,11 +1747,11 @@ static int ctnetlink_dump_one_entry(struct sk_buff *skb, if (l3proto && nf_ct_l3num(ct) != l3proto) return 0; - if (ctx->last) { - if (ct != ctx->last) + if (ctx->last_id) { + if (ctnetlink_get_id(ct) != ctx->last_id) return 0; - ctx->last = NULL; + ctx->last_id = 0; } /* We can't dump extension info for the unconfirmed @@ -1775,12 +1765,8 @@ static int ctnetlink_dump_one_entry(struct sk_buff *skb, cb->nlh->nlmsg_seq, NFNL_MSG_TYPE(cb->nlh->nlmsg_type), ct, dying, 0); - if (res < 0) { - if (!refcount_inc_not_zero(&ct->ct_general.use)) - return 0; - - ctx->last = ct; - } + if (res < 0) + ctx->last_id = ctnetlink_get_id(ct); return res; } @@ -1796,10 +1782,10 @@ static int ctnetlink_dump_dying(struct sk_buff *skb, struct netlink_callback *cb) { struct ctnetlink_list_dump_ctx *ctx = (void *)cb->ctx; - struct nf_conn *last = ctx->last; #ifdef CONFIG_NF_CONNTRACK_EVENTS const struct net *net = sock_net(skb->sk); struct nf_conntrack_net_ecache *ecache_net; + unsigned long last_id = ctx->last_id; struct nf_conntrack_tuple_hash *h; struct hlist_nulls_node *n; #endif @@ -1807,7 +1793,7 @@ ctnetlink_dump_dying(struct sk_buff *skb, struct netlink_callback *cb) if (ctx->done) return 0; - ctx->last = NULL; + ctx->last_id = 0; #ifdef CONFIG_NF_CONNTRACK_EVENTS ecache_net = nf_conn_pernet_ecache(net); @@ -1818,24 +1804,21 @@ ctnetlink_dump_dying(struct sk_buff *skb, struct netlink_callback *cb) int res; ct = nf_ct_tuplehash_to_ctrack(h); - if (last && last != ct) + if (last_id && last_id != ctnetlink_get_id(ct)) continue; res = ctnetlink_dump_one_entry(skb, cb, ct, true); if (res < 0) { spin_unlock_bh(&ecache_net->dying_lock); - nf_ct_put(last); return skb->len; } - nf_ct_put(last); - last = NULL; + last_id = 0; } spin_unlock_bh(&ecache_net->dying_lock); #endif ctx->done = true; - nf_ct_put(last); return skb->len; } @@ -1847,7 +1830,6 @@ static int ctnetlink_get_ct_dying(struct sk_buff *skb, if (info->nlh->nlmsg_flags & NLM_F_DUMP) { struct netlink_dump_control c = { .dump = ctnetlink_dump_dying, - .done = ctnetlink_done_list, }; return netlink_dump_start(info->sk, skb, info->nlh, &c); } @@ -1862,7 +1844,6 @@ static int ctnetlink_get_ct_unconfirmed(struct sk_buff *skb, if (info->nlh->nlmsg_flags & NLM_F_DUMP) { struct netlink_dump_control c = { .dump = ctnetlink_dump_unconfirmed, - .done = ctnetlink_done_list, }; return netlink_dump_start(info->sk, skb, info->nlh, &c); } From d11b26402a33f5c45389e0a288430c457434c9cd Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 15 Aug 2025 18:09:36 +0200 Subject: [PATCH 01557/11391] netfilter: nft_set_pipapo_avx2: Drop the comment regarding protection The comment claims that the kernel_fpu_begin_mask() below protects access to the scratch map. This is not true because the access is only protected by local_bh_disable() above. Remove the misleading comment. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Florian Westphal --- net/netfilter/nft_set_pipapo_avx2.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/netfilter/nft_set_pipapo_avx2.c b/net/netfilter/nft_set_pipapo_avx2.c index 2f090e253caf..fc734a8545b4 100644 --- a/net/netfilter/nft_set_pipapo_avx2.c +++ b/net/netfilter/nft_set_pipapo_avx2.c @@ -1171,9 +1171,7 @@ nft_pipapo_avx2_lookup(const struct net *net, const struct nft_set *set, m = rcu_dereference(priv->match); - /* This also protects access to all data related to scratch maps. - * - * Note that we don't need a valid MXCSR state for any of the + /* Note that we don't need a valid MXCSR state for any of the * operations we use here, so pass 0 as mask and spare a LDMXCSR * instruction. */ From 416e53e39516714057d7d06d561e49d1a89fa524 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 15 Aug 2025 16:36:57 +0200 Subject: [PATCH 01558/11391] netfilter: nft_set_pipapo_avx2: split lookup function in two parts Split the main avx2 lookup function into a helper. This is a preparation patch: followup change will use the new helper from the insertion path if possible. This greatly improves insertion performance when avx2 is supported. Reviewed-by: Stefano Brivio Signed-off-by: Florian Westphal --- net/netfilter/nft_set_pipapo_avx2.c | 136 +++++++++++++++++----------- 1 file changed, 82 insertions(+), 54 deletions(-) diff --git a/net/netfilter/nft_set_pipapo_avx2.c b/net/netfilter/nft_set_pipapo_avx2.c index fc734a8545b4..994a2ad2d9b1 100644 --- a/net/netfilter/nft_set_pipapo_avx2.c +++ b/net/netfilter/nft_set_pipapo_avx2.c @@ -1133,56 +1133,35 @@ static inline void pipapo_resmap_init_avx2(const struct nft_pipapo_match *m, uns } /** - * nft_pipapo_avx2_lookup() - Lookup function for AVX2 implementation - * @net: Network namespace - * @set: nftables API set representation - * @key: nftables API element representation containing key data + * pipapo_get_avx2() - Lookup function for AVX2 implementation + * @m: Storage containing the set elements + * @data: Key data to be matched against existing elements + * @genmask: If set, check that element is active in given genmask + * @tstamp: Timestamp to check for expired elements * * For more details, see DOC: Theory of Operation in nft_set_pipapo.c. * * This implementation exploits the repetitive characteristic of the algorithm * to provide a fast, vectorised version using the AVX2 SIMD instruction set. * - * Return: true on match, false otherwise. + * The caller must check that the FPU is usable. + * This function must be called with BH disabled. + * + * Return: pointer to &struct nft_pipapo_elem on match, NULL otherwise. */ -const struct nft_set_ext * -nft_pipapo_avx2_lookup(const struct net *net, const struct nft_set *set, - const u32 *key) +static struct nft_pipapo_elem *pipapo_get_avx2(const struct nft_pipapo_match *m, + const u8 *data, u8 genmask, + u64 tstamp) { - struct nft_pipapo *priv = nft_set_priv(set); - const struct nft_set_ext *ext = NULL; struct nft_pipapo_scratch *scratch; - u8 genmask = nft_genmask_cur(net); - const struct nft_pipapo_match *m; const struct nft_pipapo_field *f; - const u8 *rp = (const u8 *)key; unsigned long *res, *fill; bool map_index; int i; - local_bh_disable(); - - if (unlikely(!irq_fpu_usable())) { - ext = nft_pipapo_lookup(net, set, key); - - local_bh_enable(); - return ext; - } - - m = rcu_dereference(priv->match); - - /* Note that we don't need a valid MXCSR state for any of the - * operations we use here, so pass 0 as mask and spare a LDMXCSR - * instruction. - */ - kernel_fpu_begin_mask(0); - scratch = *raw_cpu_ptr(m->scratch); - if (unlikely(!scratch)) { - kernel_fpu_end(); - local_bh_enable(); + if (unlikely(!scratch)) return NULL; - } map_index = scratch->map_index; @@ -1191,6 +1170,12 @@ nft_pipapo_avx2_lookup(const struct net *net, const struct nft_set *set, pipapo_resmap_init_avx2(m, res); + /* Note that we don't need a valid MXCSR state for any of the + * operations we use here, so pass 0 as mask and spare a LDMXCSR + * instruction. + */ + kernel_fpu_begin_mask(0); + nft_pipapo_avx2_prepare(); next_match: @@ -1200,7 +1185,7 @@ nft_pipapo_avx2_lookup(const struct net *net, const struct nft_set *set, #define NFT_SET_PIPAPO_AVX2_LOOKUP(b, n) \ (ret = nft_pipapo_avx2_lookup_##b##b_##n(res, fill, f, \ - ret, rp, \ + ret, data, \ first, last)) if (likely(f->bb == 8)) { @@ -1216,7 +1201,7 @@ nft_pipapo_avx2_lookup(const struct net *net, const struct nft_set *set, NFT_SET_PIPAPO_AVX2_LOOKUP(8, 16); } else { ret = nft_pipapo_avx2_lookup_slow(m, res, fill, f, - ret, rp, + ret, data, first, last); } } else { @@ -1232,7 +1217,7 @@ nft_pipapo_avx2_lookup(const struct net *net, const struct nft_set *set, NFT_SET_PIPAPO_AVX2_LOOKUP(4, 32); } else { ret = nft_pipapo_avx2_lookup_slow(m, res, fill, f, - ret, rp, + ret, data, first, last); } } @@ -1240,29 +1225,72 @@ nft_pipapo_avx2_lookup(const struct net *net, const struct nft_set *set, #undef NFT_SET_PIPAPO_AVX2_LOOKUP - if (ret < 0) - goto out; - - if (last) { - const struct nft_set_ext *e = &f->mt[ret].e->ext; - - if (unlikely(nft_set_elem_expired(e) || - !nft_set_elem_active(e, genmask))) - goto next_match; - - ext = e; - goto out; + if (ret < 0) { + scratch->map_index = map_index; + kernel_fpu_end(); + return NULL; } + if (last) { + struct nft_pipapo_elem *e; + + e = f->mt[ret].e; + if (unlikely(__nft_set_elem_expired(&e->ext, tstamp) || + !nft_set_elem_active(&e->ext, genmask))) + goto next_match; + + scratch->map_index = map_index; + kernel_fpu_end(); + return e; + } + + map_index = !map_index; swap(res, fill); - rp += NFT_PIPAPO_GROUPS_PADDED_SIZE(f); + data += NFT_PIPAPO_GROUPS_PADDED_SIZE(f); } -out: - if (i % 2) - scratch->map_index = !map_index; kernel_fpu_end(); + return NULL; +} + +/** + * nft_pipapo_avx2_lookup() - Dataplane frontend for AVX2 implementation + * @net: Network namespace + * @set: nftables API set representation + * @key: nftables API element representation containing key data + * + * This function is called from the data path. It will search for + * an element matching the given key in the current active copy using + * the AVX2 routines if the fpu is usable or fall back to the generic + * implementation of the algorithm otherwise. + * + * Return: nftables API extension pointer or NULL if no match. + */ +const struct nft_set_ext * +nft_pipapo_avx2_lookup(const struct net *net, const struct nft_set *set, + const u32 *key) +{ + struct nft_pipapo *priv = nft_set_priv(set); + u8 genmask = nft_genmask_cur(net); + const struct nft_pipapo_match *m; + const u8 *rp = (const u8 *)key; + const struct nft_pipapo_elem *e; + + local_bh_disable(); + + if (unlikely(!irq_fpu_usable())) { + const struct nft_set_ext *ext; + + ext = nft_pipapo_lookup(net, set, key); + + local_bh_enable(); + return ext; + } + + m = rcu_dereference(priv->match); + + e = pipapo_get_avx2(m, rp, genmask, get_jiffies_64()); local_bh_enable(); - return ext; + return e ? &e->ext : NULL; } From 84c1da7b38d9ad8fadd5b0b76034a41f7761e404 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 15 Aug 2025 16:36:58 +0200 Subject: [PATCH 01559/11391] netfilter: nft_set_pipapo: use avx2 algorithm for insertions too Always prefer the avx2 implementation if its available. This greatly improves insertion performance (each insertion checks if the new element would overlap with an existing one): time nft -f - < Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Florian Westphal --- net/netfilter/nft_set_pipapo.c | 45 +++++++++++++++++++++++++---- net/netfilter/nft_set_pipapo_avx2.c | 8 ++--- net/netfilter/nft_set_pipapo_avx2.h | 4 +++ 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c index 9a10251228fd..7ed9c5f0e233 100644 --- a/net/netfilter/nft_set_pipapo.c +++ b/net/netfilter/nft_set_pipapo.c @@ -397,7 +397,7 @@ int pipapo_refill(unsigned long *map, unsigned int len, unsigned int rules, } /** - * pipapo_get() - Get matching element reference given key data + * pipapo_get_slow() - Get matching element reference given key data * @m: storage containing the set elements * @data: Key data to be matched against existing elements * @genmask: If set, check that element is active in given genmask @@ -414,9 +414,9 @@ int pipapo_refill(unsigned long *map, unsigned int len, unsigned int rules, * * Return: pointer to &struct nft_pipapo_elem on match, NULL otherwise. */ -static struct nft_pipapo_elem *pipapo_get(const struct nft_pipapo_match *m, - const u8 *data, u8 genmask, - u64 tstamp) +static struct nft_pipapo_elem *pipapo_get_slow(const struct nft_pipapo_match *m, + const u8 *data, u8 genmask, + u64 tstamp) { struct nft_pipapo_scratch *scratch; unsigned long *res_map, *fill_map; @@ -502,6 +502,41 @@ static struct nft_pipapo_elem *pipapo_get(const struct nft_pipapo_match *m, return NULL; } +/** + * pipapo_get() - Get matching element reference given key data + * @m: Storage containing the set elements + * @data: Key data to be matched against existing elements + * @genmask: If set, check that element is active in given genmask + * @tstamp: Timestamp to check for expired elements + * + * This is a dispatcher function, either calling out the generic C + * implementation or, if available, the AVX2 one. + * This helper is only called from the control plane, with either RCU + * read lock or transaction mutex held. + * + * Return: pointer to &struct nft_pipapo_elem on match, NULL otherwise. + */ +static struct nft_pipapo_elem *pipapo_get(const struct nft_pipapo_match *m, + const u8 *data, u8 genmask, + u64 tstamp) +{ + struct nft_pipapo_elem *e; + + local_bh_disable(); + +#if defined(CONFIG_X86_64) && !defined(CONFIG_UML) + if (boot_cpu_has(X86_FEATURE_AVX2) && boot_cpu_has(X86_FEATURE_AVX) && + irq_fpu_usable()) { + e = pipapo_get_avx2(m, data, genmask, tstamp); + local_bh_enable(); + return e; + } +#endif + e = pipapo_get_slow(m, data, genmask, tstamp); + local_bh_enable(); + return e; +} + /** * nft_pipapo_lookup() - Dataplane fronted for main lookup function * @net: Network namespace @@ -523,7 +558,7 @@ nft_pipapo_lookup(const struct net *net, const struct nft_set *set, const struct nft_pipapo_elem *e; m = rcu_dereference(priv->match); - e = pipapo_get(m, (const u8 *)key, genmask, get_jiffies_64()); + e = pipapo_get_slow(m, (const u8 *)key, genmask, get_jiffies_64()); return e ? &e->ext : NULL; } diff --git a/net/netfilter/nft_set_pipapo_avx2.c b/net/netfilter/nft_set_pipapo_avx2.c index 994a2ad2d9b1..028c11724b42 100644 --- a/net/netfilter/nft_set_pipapo_avx2.c +++ b/net/netfilter/nft_set_pipapo_avx2.c @@ -1149,9 +1149,9 @@ static inline void pipapo_resmap_init_avx2(const struct nft_pipapo_match *m, uns * * Return: pointer to &struct nft_pipapo_elem on match, NULL otherwise. */ -static struct nft_pipapo_elem *pipapo_get_avx2(const struct nft_pipapo_match *m, - const u8 *data, u8 genmask, - u64 tstamp) +struct nft_pipapo_elem *pipapo_get_avx2(const struct nft_pipapo_match *m, + const u8 *data, u8 genmask, + u64 tstamp) { struct nft_pipapo_scratch *scratch; const struct nft_pipapo_field *f; @@ -1261,7 +1261,7 @@ static struct nft_pipapo_elem *pipapo_get_avx2(const struct nft_pipapo_match *m, * * This function is called from the data path. It will search for * an element matching the given key in the current active copy using - * the AVX2 routines if the fpu is usable or fall back to the generic + * the AVX2 routines if the FPU is usable or fall back to the generic * implementation of the algorithm otherwise. * * Return: nftables API extension pointer or NULL if no match. diff --git a/net/netfilter/nft_set_pipapo_avx2.h b/net/netfilter/nft_set_pipapo_avx2.h index dbb6aaca8a7a..c2999b63da3f 100644 --- a/net/netfilter/nft_set_pipapo_avx2.h +++ b/net/netfilter/nft_set_pipapo_avx2.h @@ -5,8 +5,12 @@ #include #define NFT_PIPAPO_ALIGN (XSAVE_YMM_SIZE / BITS_PER_BYTE) +struct nft_pipapo_match; bool nft_pipapo_avx2_estimate(const struct nft_set_desc *desc, u32 features, struct nft_set_estimate *est); +struct nft_pipapo_elem *pipapo_get_avx2(const struct nft_pipapo_match *m, + const u8 *data, u8 genmask, + u64 tstamp); #endif /* defined(CONFIG_X86_64) && !defined(CONFIG_UML) */ #endif /* _NFT_SET_PIPAPO_AVX2_H */ From 6aa67d5706f031f24cd486d8df7dc7fddca62b22 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 15 Aug 2025 18:09:35 +0200 Subject: [PATCH 01560/11391] netfilter: nft_set_pipapo: Store real pointer, adjust later. The struct nft_pipapo_scratch is allocated, then aligned to the required alignment and difference (in bytes) is then saved in align_off. The aligned pointer is used later. While this works, it gets complicated with all the extra checks if all member before map are larger than the required alignment. Instead of saving the aligned pointer, just save the returned pointer and align the map pointer in nft_pipapo_lookup() before using it. The alignment later on shouldn't be that expensive. With this change, the align_off can be removed and the pointer can be passed to kfree() as is. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Florian Westphal --- net/netfilter/nft_set_pipapo.c | 40 ++++++----------------------- net/netfilter/nft_set_pipapo.h | 6 ++--- net/netfilter/nft_set_pipapo_avx2.c | 8 +++--- 3 files changed, 14 insertions(+), 40 deletions(-) diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c index 7ed9c5f0e233..96b7539f5506 100644 --- a/net/netfilter/nft_set_pipapo.c +++ b/net/netfilter/nft_set_pipapo.c @@ -418,8 +418,8 @@ static struct nft_pipapo_elem *pipapo_get_slow(const struct nft_pipapo_match *m, const u8 *data, u8 genmask, u64 tstamp) { + unsigned long *res_map, *fill_map, *map; struct nft_pipapo_scratch *scratch; - unsigned long *res_map, *fill_map; const struct nft_pipapo_field *f; bool map_index; int i; @@ -432,8 +432,9 @@ static struct nft_pipapo_elem *pipapo_get_slow(const struct nft_pipapo_match *m, map_index = scratch->map_index; - res_map = scratch->map + (map_index ? m->bsize_max : 0); - fill_map = scratch->map + (map_index ? 0 : m->bsize_max); + map = NFT_PIPAPO_LT_ALIGN(&scratch->__map[0]); + res_map = map + (map_index ? m->bsize_max : 0); + fill_map = map + (map_index ? 0 : m->bsize_max); pipapo_resmap_init(m, res_map); @@ -1171,22 +1172,17 @@ static void pipapo_map(struct nft_pipapo_match *m, } /** - * pipapo_free_scratch() - Free per-CPU map at original (not aligned) address + * pipapo_free_scratch() - Free per-CPU map at original address * @m: Matching data * @cpu: CPU number */ static void pipapo_free_scratch(const struct nft_pipapo_match *m, unsigned int cpu) { struct nft_pipapo_scratch *s; - void *mem; s = *per_cpu_ptr(m->scratch, cpu); - if (!s) - return; - mem = s; - mem -= s->align_off; - kvfree(mem); + kvfree(s); } /** @@ -1203,11 +1199,8 @@ static int pipapo_realloc_scratch(struct nft_pipapo_match *clone, for_each_possible_cpu(i) { struct nft_pipapo_scratch *scratch; -#ifdef NFT_PIPAPO_ALIGN - void *scratch_aligned; - u32 align_off; -#endif - scratch = kvzalloc_node(struct_size(scratch, map, bsize_max * 2) + + + scratch = kvzalloc_node(struct_size(scratch, __map, bsize_max * 2) + NFT_PIPAPO_ALIGN_HEADROOM, GFP_KERNEL_ACCOUNT, cpu_to_node(i)); if (!scratch) { @@ -1222,23 +1215,6 @@ static int pipapo_realloc_scratch(struct nft_pipapo_match *clone, } pipapo_free_scratch(clone, i); - -#ifdef NFT_PIPAPO_ALIGN - /* Align &scratch->map (not the struct itself): the extra - * %NFT_PIPAPO_ALIGN_HEADROOM bytes passed to kzalloc_node() - * above guarantee we can waste up to those bytes in order - * to align the map field regardless of its offset within - * the struct. - */ - BUILD_BUG_ON(offsetof(struct nft_pipapo_scratch, map) > NFT_PIPAPO_ALIGN_HEADROOM); - - scratch_aligned = NFT_PIPAPO_LT_ALIGN(&scratch->map); - scratch_aligned -= offsetof(struct nft_pipapo_scratch, map); - align_off = scratch_aligned - (void *)scratch; - - scratch = scratch_aligned; - scratch->align_off = align_off; -#endif *per_cpu_ptr(clone->scratch, i) = scratch; } diff --git a/net/netfilter/nft_set_pipapo.h b/net/netfilter/nft_set_pipapo.h index 4a2ff85ce1c4..e10cdbaa65d8 100644 --- a/net/netfilter/nft_set_pipapo.h +++ b/net/netfilter/nft_set_pipapo.h @@ -125,13 +125,11 @@ struct nft_pipapo_field { /** * struct nft_pipapo_scratch - percpu data used for lookup and matching * @map_index: Current working bitmap index, toggled between field matches - * @align_off: Offset to get the originally allocated address - * @map: store partial matching results during lookup + * @__map: store partial matching results during lookup */ struct nft_pipapo_scratch { u8 map_index; - u32 align_off; - unsigned long map[]; + unsigned long __map[]; }; /** diff --git a/net/netfilter/nft_set_pipapo_avx2.c b/net/netfilter/nft_set_pipapo_avx2.c index 028c11724b42..f0d8c796d731 100644 --- a/net/netfilter/nft_set_pipapo_avx2.c +++ b/net/netfilter/nft_set_pipapo_avx2.c @@ -1155,7 +1155,7 @@ struct nft_pipapo_elem *pipapo_get_avx2(const struct nft_pipapo_match *m, { struct nft_pipapo_scratch *scratch; const struct nft_pipapo_field *f; - unsigned long *res, *fill; + unsigned long *res, *fill, *map; bool map_index; int i; @@ -1164,9 +1164,9 @@ struct nft_pipapo_elem *pipapo_get_avx2(const struct nft_pipapo_match *m, return NULL; map_index = scratch->map_index; - - res = scratch->map + (map_index ? m->bsize_max : 0); - fill = scratch->map + (map_index ? 0 : m->bsize_max); + map = NFT_PIPAPO_LT_ALIGN(&scratch->__map[0]); + res = map + (map_index ? m->bsize_max : 0); + fill = map + (map_index ? 0 : m->bsize_max); pipapo_resmap_init_avx2(m, res); From 456010c8b99e65231160d4c706122ac5502fbcff Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 18 Aug 2025 13:02:13 +0200 Subject: [PATCH 01561/11391] netfilter: nft_set_pipapo: Use nested-BH locking for nft_pipapo_scratch nft_pipapo_scratch is a per-CPU variable and relies on disabled BH for its locking. Without per-CPU locking in local_bh_disable() on PREEMPT_RT this data structure requires explicit locking. Add a local_lock_t to the data structure and use local_lock_nested_bh() for locking. This change adds only lockdep coverage and does not alter the functional behaviour for !PREEMPT_RT. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Florian Westphal --- net/netfilter/nft_set_pipapo.c | 5 +++++ net/netfilter/nft_set_pipapo.h | 2 ++ net/netfilter/nft_set_pipapo_avx2.c | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c index 96b7539f5506..b385cfcf886f 100644 --- a/net/netfilter/nft_set_pipapo.c +++ b/net/netfilter/nft_set_pipapo.c @@ -429,6 +429,7 @@ static struct nft_pipapo_elem *pipapo_get_slow(const struct nft_pipapo_match *m, scratch = *raw_cpu_ptr(m->scratch); if (unlikely(!scratch)) goto out; + __local_lock_nested_bh(&scratch->bh_lock); map_index = scratch->map_index; @@ -465,6 +466,7 @@ static struct nft_pipapo_elem *pipapo_get_slow(const struct nft_pipapo_match *m, last); if (b < 0) { scratch->map_index = map_index; + __local_unlock_nested_bh(&scratch->bh_lock); local_bh_enable(); return NULL; @@ -484,6 +486,7 @@ static struct nft_pipapo_elem *pipapo_get_slow(const struct nft_pipapo_match *m, * *next* bitmap (not initial) for the next packet. */ scratch->map_index = map_index; + __local_unlock_nested_bh(&scratch->bh_lock); local_bh_enable(); return e; } @@ -498,6 +501,7 @@ static struct nft_pipapo_elem *pipapo_get_slow(const struct nft_pipapo_match *m, data += NFT_PIPAPO_GROUPS_PADDING(f); } + __local_unlock_nested_bh(&scratch->bh_lock); out: local_bh_enable(); return NULL; @@ -1215,6 +1219,7 @@ static int pipapo_realloc_scratch(struct nft_pipapo_match *clone, } pipapo_free_scratch(clone, i); + local_lock_init(&scratch->bh_lock); *per_cpu_ptr(clone->scratch, i) = scratch; } diff --git a/net/netfilter/nft_set_pipapo.h b/net/netfilter/nft_set_pipapo.h index e10cdbaa65d8..eaab422aa56a 100644 --- a/net/netfilter/nft_set_pipapo.h +++ b/net/netfilter/nft_set_pipapo.h @@ -124,10 +124,12 @@ struct nft_pipapo_field { /** * struct nft_pipapo_scratch - percpu data used for lookup and matching + * @bh_lock: PREEMPT_RT local spinlock * @map_index: Current working bitmap index, toggled between field matches * @__map: store partial matching results during lookup */ struct nft_pipapo_scratch { + local_lock_t bh_lock; u8 map_index; unsigned long __map[]; }; diff --git a/net/netfilter/nft_set_pipapo_avx2.c b/net/netfilter/nft_set_pipapo_avx2.c index f0d8c796d731..29326f3fcaf3 100644 --- a/net/netfilter/nft_set_pipapo_avx2.c +++ b/net/netfilter/nft_set_pipapo_avx2.c @@ -1163,6 +1163,7 @@ struct nft_pipapo_elem *pipapo_get_avx2(const struct nft_pipapo_match *m, if (unlikely(!scratch)) return NULL; + __local_lock_nested_bh(&scratch->bh_lock); map_index = scratch->map_index; map = NFT_PIPAPO_LT_ALIGN(&scratch->__map[0]); res = map + (map_index ? m->bsize_max : 0); @@ -1228,6 +1229,7 @@ struct nft_pipapo_elem *pipapo_get_avx2(const struct nft_pipapo_match *m, if (ret < 0) { scratch->map_index = map_index; kernel_fpu_end(); + __local_unlock_nested_bh(&scratch->bh_lock); return NULL; } @@ -1241,6 +1243,7 @@ struct nft_pipapo_elem *pipapo_get_avx2(const struct nft_pipapo_match *m, scratch->map_index = map_index; kernel_fpu_end(); + __local_unlock_nested_bh(&scratch->bh_lock); return e; } @@ -1250,6 +1253,7 @@ struct nft_pipapo_elem *pipapo_get_avx2(const struct nft_pipapo_match *m, } kernel_fpu_end(); + __local_unlock_nested_bh(&scratch->bh_lock); return NULL; } From b5bbbb70e5f5e1b14b2d5e3d88b8e18cd99f986d Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Tue, 19 Aug 2025 12:20:38 +0200 Subject: [PATCH 01562/11391] s390/bpf: Use direct calls and jumps where possible After the V!=R rework (commit c98d2ecae08f ("s390/mm: Uncouple physical vs virtual address spaces")), all kernel code and related data are allocated within a 4G region, making it possible to use relative addressing in BPF code more extensively. Convert as many indirect calls and jumps to direct calls as possible, namely: * BPF_CALL * __bpf_tramp_enter() * __bpf_tramp_exit() * __bpf_prog_enter() * __bpf_prog_exit() * fentry * fmod_ret * fexit * BPF_TRAMP_F_CALL_ORIG without BPF_TRAMP_F_ORIG_STACK * Trampoline returns without BPF_TRAMP_F_SKIP_FRAME and BPF_TRAMP_F_ORIG_STACK The following indirect calls and jumps remain: * Prog returns * Trampoline returns with BPF_TRAMP_F_SKIP_FRAME or BPF_TRAMP_F_ORIG_STACK * BPF_TAIL_CALL * BPF_TRAMP_F_CALL_ORIG with BPF_TRAMP_F_ORIG_STACK As a result, only one usage of call_r1() remains, so inline it. Signed-off-by: Ilya Leoshkevich Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20250819102116.252203-1-iii@linux.ibm.com --- arch/s390/net/bpf_jit_comp.c | 80 +++++++++++++++--------------------- 1 file changed, 32 insertions(+), 48 deletions(-) diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c index b2b8eb62b82e..fd45f03a213c 100644 --- a/arch/s390/net/bpf_jit_comp.c +++ b/arch/s390/net/bpf_jit_comp.c @@ -674,20 +674,6 @@ static void bpf_jit_prologue(struct bpf_jit *jit, struct bpf_prog *fp) _EMIT2(0x07f0 | reg); \ } while (0) -/* - * Call r1 either directly or via __s390_indirect_jump_r1 thunk - */ -static void call_r1(struct bpf_jit *jit) -{ - if (nospec_uses_trampoline()) - /* brasl %r14,__s390_indirect_jump_r1 */ - EMIT6_PCREL_RILB_PTR(0xc0050000, REG_14, - __s390_indirect_jump_r1); - else - /* basr %r14,%r1 */ - EMIT2(0x0d00, REG_14, REG_1); -} - /* * Function epilogue */ @@ -1820,10 +1806,8 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, } } - /* lgrl %w1,func */ - EMIT6_PCREL_RILB(0xc4080000, REG_W1, _EMIT_CONST_U64(func)); - /* %r1() */ - call_r1(jit); + /* brasl %r14,func */ + EMIT6_PCREL_RILB_PTR(0xc0050000, REG_14, (void *)func); /* lgr %b0,%r2: load return value into %b0 */ EMIT4(0xb9040000, BPF_REG_0, REG_2); @@ -2534,14 +2518,12 @@ static int invoke_bpf_prog(struct bpf_tramp_jit *tjit, * goto skip; */ - /* %r1 = __bpf_prog_enter */ - load_imm64(jit, REG_1, (u64)bpf_trampoline_enter(p)); /* %r2 = p */ load_imm64(jit, REG_2, (u64)p); /* la %r3,run_ctx_off(%r15) */ EMIT4_DISP(0x41000000, REG_3, REG_15, tjit->run_ctx_off); - /* %r1() */ - call_r1(jit); + /* brasl %r14,__bpf_prog_enter */ + EMIT6_PCREL_RILB_PTR(0xc0050000, REG_14, bpf_trampoline_enter(p)); /* ltgr %r7,%r2 */ EMIT4(0xb9020000, REG_7, REG_2); /* brcl 8,skip */ @@ -2552,15 +2534,13 @@ static int invoke_bpf_prog(struct bpf_tramp_jit *tjit, * retval = bpf_func(args, p->insnsi); */ - /* %r1 = p->bpf_func */ - load_imm64(jit, REG_1, (u64)p->bpf_func); /* la %r2,bpf_args_off(%r15) */ EMIT4_DISP(0x41000000, REG_2, REG_15, tjit->bpf_args_off); /* %r3 = p->insnsi */ if (!p->jited) load_imm64(jit, REG_3, (u64)p->insnsi); - /* %r1() */ - call_r1(jit); + /* brasl %r14,p->bpf_func */ + EMIT6_PCREL_RILB_PTR(0xc0050000, REG_14, p->bpf_func); /* stg %r2,retval_off(%r15) */ if (save_ret) { if (sign_extend(jit, REG_2, m->ret_size, m->ret_flags)) @@ -2577,16 +2557,14 @@ static int invoke_bpf_prog(struct bpf_tramp_jit *tjit, * __bpf_prog_exit(p, start, &run_ctx); */ - /* %r1 = __bpf_prog_exit */ - load_imm64(jit, REG_1, (u64)bpf_trampoline_exit(p)); /* %r2 = p */ load_imm64(jit, REG_2, (u64)p); /* lgr %r3,%r7 */ EMIT4(0xb9040000, REG_3, REG_7); /* la %r4,run_ctx_off(%r15) */ EMIT4_DISP(0x41000000, REG_4, REG_15, tjit->run_ctx_off); - /* %r1() */ - call_r1(jit); + /* brasl %r14,__bpf_prog_exit */ + EMIT6_PCREL_RILB_PTR(0xc0050000, REG_14, bpf_trampoline_exit(p)); return 0; } @@ -2746,9 +2724,6 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, /* lgr %r8,%r0 */ EMIT4(0xb9040000, REG_8, REG_0); - } else { - /* %r8 = func_addr + S390X_PATCH_SIZE */ - load_imm64(jit, REG_8, (u64)func_addr + S390X_PATCH_SIZE); } /* @@ -2774,12 +2749,10 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, * __bpf_tramp_enter(im); */ - /* %r1 = __bpf_tramp_enter */ - load_imm64(jit, REG_1, (u64)__bpf_tramp_enter); /* %r2 = im */ load_imm64(jit, REG_2, (u64)im); - /* %r1() */ - call_r1(jit); + /* brasl %r14,__bpf_tramp_enter */ + EMIT6_PCREL_RILB_PTR(0xc0050000, REG_14, __bpf_tramp_enter); } for (i = 0; i < fentry->nr_links; i++) @@ -2832,10 +2805,19 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, /* mvc tail_call_cnt(4,%r15),tccnt_off(%r15) */ _EMIT6(0xd203f000 | offsetof(struct prog_frame, tail_call_cnt), 0xf000 | tjit->tccnt_off); - /* lgr %r1,%r8 */ - EMIT4(0xb9040000, REG_1, REG_8); - /* %r1() */ - call_r1(jit); + if (flags & BPF_TRAMP_F_ORIG_STACK) { + if (nospec_uses_trampoline()) + /* brasl %r14,__s390_indirect_jump_r8 */ + EMIT6_PCREL_RILB_PTR(0xc0050000, REG_14, + __s390_indirect_jump_r8); + else + /* basr %r14,%r8 */ + EMIT2(0x0d00, REG_14, REG_8); + } else { + /* brasl %r14,func_addr+S390X_PATCH_SIZE */ + EMIT6_PCREL_RILB_PTR(0xc0050000, REG_14, + func_addr + S390X_PATCH_SIZE); + } /* stg %r2,retval_off(%r15) */ EMIT6_DISP_LH(0xe3000000, 0x0024, REG_2, REG_0, REG_15, tjit->retval_off); @@ -2866,12 +2848,10 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, * __bpf_tramp_exit(im); */ - /* %r1 = __bpf_tramp_exit */ - load_imm64(jit, REG_1, (u64)__bpf_tramp_exit); /* %r2 = im */ load_imm64(jit, REG_2, (u64)im); - /* %r1() */ - call_r1(jit); + /* brasl %r14,__bpf_tramp_exit */ + EMIT6_PCREL_RILB_PTR(0xc0050000, REG_14, __bpf_tramp_exit); } /* lmg %r2,%rN,reg_args_off(%r15) */ @@ -2880,7 +2860,8 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, REG_2 + (nr_reg_args - 1), REG_15, tjit->reg_args_off); /* lgr %r1,%r8 */ - if (!(flags & BPF_TRAMP_F_SKIP_FRAME)) + if (!(flags & BPF_TRAMP_F_SKIP_FRAME) && + (flags & BPF_TRAMP_F_ORIG_STACK)) EMIT4(0xb9040000, REG_1, REG_8); /* lmg %r7,%r8,r7_r8_off(%r15) */ EMIT6_DISP_LH(0xeb000000, 0x0004, REG_7, REG_8, REG_15, @@ -2899,9 +2880,12 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, EMIT4_IMM(0xa70b0000, REG_15, tjit->stack_size); if (flags & BPF_TRAMP_F_SKIP_FRAME) EMIT_JUMP_REG(14); - else + else if (flags & BPF_TRAMP_F_ORIG_STACK) EMIT_JUMP_REG(1); - + else + /* brcl 0xf,func_addr+S390X_PATCH_SIZE */ + EMIT6_PCREL_RILC_PTR(0xc0040000, 0xf, + func_addr + S390X_PATCH_SIZE); return 0; } From 2693227c1150d58bf82ef45a394a554373be5286 Mon Sep 17 00:00:00 2001 From: Mykyta Yatsenko Date: Tue, 19 Aug 2025 22:51:19 +0100 Subject: [PATCH 01563/11391] libbpf: Export bpf_object__prepare symbol Add missing LIBBPF_API macro for bpf_object__prepare function to enable its export. libbpf.map had bpf_object__prepare already listed. Fixes: 1315c28ed809 ("libbpf: Split bpf object load into prepare/load") Signed-off-by: Mykyta Yatsenko Signed-off-by: Daniel Borkmann Acked-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20250819215119.37795-1-mykyta.yatsenko5@gmail.com --- tools/lib/bpf/libbpf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 455a957cb702..2b86e21190d3 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -252,7 +252,7 @@ bpf_object__open_mem(const void *obj_buf, size_t obj_buf_sz, * @return 0, on success; negative error code, otherwise, error code is * stored in errno */ -int bpf_object__prepare(struct bpf_object *obj); +LIBBPF_API int bpf_object__prepare(struct bpf_object *obj); /** * @brief **bpf_object__load()** loads BPF object into kernel. From 45441b933cdfb7a018674049f269d7a1bc1688df Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Wed, 20 Aug 2025 20:34:18 +0800 Subject: [PATCH 01564/11391] ASoC: codecs: Use kcalloc() instead of kzalloc() Use devm_kcalloc() in fs_parse_scene_tables() and pcmdev_gain_ctrl_add() to gain built-in overflow protection, making memory allocation safer when calculating allocation size compared to explicit multiplication. Signed-off-by: Qianfeng Rong Link: https://patch.msgid.link/20250820123423.470486-2-rongqianfeng@vivo.com Signed-off-by: Mark Brown --- sound/soc/codecs/fs-amp-lib.c | 2 +- sound/soc/codecs/pcm6240.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/fs-amp-lib.c b/sound/soc/codecs/fs-amp-lib.c index 75d8d5082e30..c8f56617e370 100644 --- a/sound/soc/codecs/fs-amp-lib.c +++ b/sound/soc/codecs/fs-amp-lib.c @@ -111,7 +111,7 @@ static int fs_parse_scene_tables(struct fs_amp_lib *amp_lib) if (count <= 0) return -EFAULT; - scene = devm_kzalloc(amp_lib->dev, count * sizeof(*scene), GFP_KERNEL); + scene = devm_kcalloc(amp_lib->dev, count, sizeof(*scene), GFP_KERNEL); if (!scene) return -ENOMEM; diff --git a/sound/soc/codecs/pcm6240.c b/sound/soc/codecs/pcm6240.c index 75af12231d1d..08cc52b374a9 100644 --- a/sound/soc/codecs/pcm6240.c +++ b/sound/soc/codecs/pcm6240.c @@ -1353,8 +1353,8 @@ static int pcmdev_gain_ctrl_add(struct pcmdevice_priv *pcm_dev, return 0; } - pcmdev_controls = devm_kzalloc(pcm_dev->dev, - nr_chn * sizeof(struct snd_kcontrol_new), GFP_KERNEL); + pcmdev_controls = devm_kcalloc(pcm_dev->dev, nr_chn, + sizeof(struct snd_kcontrol_new), GFP_KERNEL); if (!pcmdev_controls) return -ENOMEM; From 3b6f4bd6cda2797b0d999a129376c112d41604f4 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Wed, 20 Aug 2025 20:34:19 +0800 Subject: [PATCH 01565/11391] ASoC: fsl: Use kcalloc() instead of kzalloc() Use devm_kcalloc() in fsl_sai_read_dlcfg() and imx_audmux_probe() to gain built-in overflow protection, making memory allocation safer when calculating allocation size compared to explicit multiplication. Signed-off-by: Qianfeng Rong Link: https://patch.msgid.link/20250820123423.470486-3-rongqianfeng@vivo.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 2 +- sound/soc/fsl/imx-audmux.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index cac064a60349..757e7868e322 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -1345,7 +1345,7 @@ static int fsl_sai_read_dlcfg(struct fsl_sai *sai) num_cfg = elems / 3; /* Add one more for default value */ - cfg = devm_kzalloc(&pdev->dev, (num_cfg + 1) * sizeof(*cfg), GFP_KERNEL); + cfg = devm_kcalloc(&pdev->dev, num_cfg + 1, sizeof(*cfg), GFP_KERNEL); if (!cfg) return -ENOMEM; diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c index cc2918ee2cf5..f8335a04595a 100644 --- a/sound/soc/fsl/imx-audmux.c +++ b/sound/soc/fsl/imx-audmux.c @@ -305,7 +305,7 @@ static int imx_audmux_probe(struct platform_device *pdev) return -EINVAL; } - regcache = devm_kzalloc(&pdev->dev, sizeof(u32) * reg_max, GFP_KERNEL); + regcache = devm_kcalloc(&pdev->dev, reg_max, sizeof(u32), GFP_KERNEL); if (!regcache) return -ENOMEM; From 96bcb34df55f7fee99795127c796315950c94fed Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Wed, 20 Aug 2025 20:34:20 +0800 Subject: [PATCH 01566/11391] ASoC: test-component: Use kcalloc() instead of kzalloc() Use devm_kcalloc() in test_driver_probe() to gain built-in overflow protection, making memory allocation safer when calculating allocation size compared to explicit multiplication. Signed-off-by: Qianfeng Rong Link: https://patch.msgid.link/20250820123423.470486-4-rongqianfeng@vivo.com Signed-off-by: Mark Brown --- sound/soc/generic/test-component.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/generic/test-component.c b/sound/soc/generic/test-component.c index 89b995987e2d..2e49066dedd4 100644 --- a/sound/soc/generic/test-component.c +++ b/sound/soc/generic/test-component.c @@ -547,8 +547,8 @@ static int test_driver_probe(struct platform_device *pdev) priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); cdriv = devm_kzalloc(dev, sizeof(*cdriv), GFP_KERNEL); - ddriv = devm_kzalloc(dev, sizeof(*ddriv) * num, GFP_KERNEL); - dname = devm_kzalloc(dev, sizeof(*dname) * num, GFP_KERNEL); + ddriv = devm_kcalloc(dev, num, sizeof(*ddriv), GFP_KERNEL); + dname = devm_kcalloc(dev, num, sizeof(*dname), GFP_KERNEL); if (!priv || !cdriv || !ddriv || !dname || !adata) return -EINVAL; From 04113322406b4763677922f80ba5ab44a8dae7bb Mon Sep 17 00:00:00 2001 From: Jihed Chaibi Date: Tue, 19 Aug 2025 22:13:01 +0200 Subject: [PATCH 01567/11391] ASoC: dt-bindings: ti,twl4030-audio: convert to DT schema Convert the TWL4030 audio module bindings from txt to YAML format and move them to the sound subsystem bindings directory. This patch also refines the schema by adding an enum constraint for ti,enable-vibra and updates the example to remove irrelevant I2C clock-frequency property. Signed-off-by: Jihed Chaibi Reviewed-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250819201302.80712-2-jihed.chaibi.dev@gmail.com Signed-off-by: Mark Brown --- .../devicetree/bindings/mfd/twl4030-audio.txt | 46 ---------- .../bindings/sound/ti,twl4030-audio.yaml | 90 +++++++++++++++++++ 2 files changed, 90 insertions(+), 46 deletions(-) delete mode 100644 Documentation/devicetree/bindings/mfd/twl4030-audio.txt create mode 100644 Documentation/devicetree/bindings/sound/ti,twl4030-audio.yaml diff --git a/Documentation/devicetree/bindings/mfd/twl4030-audio.txt b/Documentation/devicetree/bindings/mfd/twl4030-audio.txt deleted file mode 100644 index 414d2ae0adf6..000000000000 --- a/Documentation/devicetree/bindings/mfd/twl4030-audio.txt +++ /dev/null @@ -1,46 +0,0 @@ -Texas Instruments TWL family (twl4030) audio module - -The audio module inside the TWL family consist of an audio codec and a vibra -driver. - -Required properties: -- compatible : must be "ti,twl4030-audio" - -Optional properties, nodes: - -Audio functionality: -- codec { }: Need to be present if the audio functionality is used. Within this - section the following options can be used: -- ti,digimic_delay: Delay need after enabling the digimic to reduce artifacts - from the start of the recorded sample (in ms) --ti,ramp_delay_value: HS ramp delay configuration to reduce pop noise --ti,hs_extmute: Use external mute for HS pop reduction --ti,hs_extmute_gpio: Use external GPIO to control the external mute --ti,offset_cncl_path: Offset cancellation path selection, refer to TRM for the - valid values. - -Vibra functionality -- ti,enable-vibra: Need to be set to <1> if the vibra functionality is used. if - missing or it is 0, the vibra functionality is disabled. - -Example: -&i2c1 { - clock-frequency = <2600000>; - - twl: twl@48 { - reg = <0x48>; - interrupts = <7>; /* SYS_NIRQ cascaded to intc */ - interrupt-parent = <&intc>; - - twl_audio: audio { - compatible = "ti,twl4030-audio"; - - ti,enable-vibra = <1>; - - codec { - ti,ramp_delay_value = <3>; - }; - - }; - }; -}; diff --git a/Documentation/devicetree/bindings/sound/ti,twl4030-audio.yaml b/Documentation/devicetree/bindings/sound/ti,twl4030-audio.yaml new file mode 100644 index 000000000000..c9c3f7513ad4 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ti,twl4030-audio.yaml @@ -0,0 +1,90 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/ti,twl4030-audio.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments TWL4030-family Audio Module + +maintainers: + - Peter Ujfalusi + +description: + The audio module within the TWL4030-family of companion chips consists + of an audio codec and a vibra driver. This binding describes the parent + node for these functions. + +properties: + compatible: + const: ti,twl4030-audio + + codec: + type: object + description: Node containing properties for the audio codec functionality. + + properties: + ti,digimic_delay: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Delay in milliseconds after enabling digital microphones to reduce + artifacts. + + ti,ramp_delay_value: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Headset ramp delay configuration to reduce pop noise. + + ti,hs_extmute: + type: boolean + description: + Enable the use of an external mute for headset pop reduction. + + ti,hs_extmute_gpio: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: + The GPIO specifier for the external mute control. + maxItems: 1 + + ti,offset_cncl_path: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Offset cancellation path selection. Refer to the Technical + Reference Manual for valid values. + + # The 'codec' node itself is optional, but if it exists, it can be empty. + # We don't require any of its sub-properties. + + ti,enable-vibra: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1] + description: + Enable or disable the vibra functionality. + +additionalProperties: false + +required: + - compatible + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + twl: twl@48 { + reg = <0x48>; + interrupts = <7>; /* SYS_NIRQ cascaded to intc */ + interrupt-parent = <&intc>; + + twl_audio: audio { + compatible = "ti,twl4030-audio"; + + ti,enable-vibra = <1>; + + codec { + ti,ramp_delay_value = <3>; + }; + + }; + }; + }; From c232495d28ca092d0c39b10e35d3d613bd2414ab Mon Sep 17 00:00:00 2001 From: Jihed Chaibi Date: Tue, 19 Aug 2025 22:13:02 +0200 Subject: [PATCH 01568/11391] ASoC: dt-bindings: omap-twl4030: convert to DT schema Convert the legacy TXT binding for the OMAP TWL4030 sound card to the modern YAML DT schema format. This adds formal validation and improves documentation. Acked-by: Mark Brown Signed-off-by: Jihed Chaibi Reviewed-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250819201302.80712-3-jihed.chaibi.dev@gmail.com Signed-off-by: Mark Brown --- .../bindings/sound/omap-twl4030.txt | 62 ------------ .../bindings/sound/ti,omap-twl4030.yaml | 98 +++++++++++++++++++ 2 files changed, 98 insertions(+), 62 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/omap-twl4030.txt create mode 100644 Documentation/devicetree/bindings/sound/ti,omap-twl4030.yaml diff --git a/Documentation/devicetree/bindings/sound/omap-twl4030.txt b/Documentation/devicetree/bindings/sound/omap-twl4030.txt deleted file mode 100644 index f6a715e4ef43..000000000000 --- a/Documentation/devicetree/bindings/sound/omap-twl4030.txt +++ /dev/null @@ -1,62 +0,0 @@ -* Texas Instruments SoC with twl4030 based audio setups - -Required properties: -- compatible: "ti,omap-twl4030" -- ti,model: Name of the sound card (for example "omap3beagle") -- ti,mcbsp: phandle for the McBSP node - -Optional properties: -- ti,codec: phandle for the twl4030 audio node -- ti,mcbsp-voice: phandle for the McBSP node connected to the voice port of twl -- ti, jack-det-gpio: Jack detect GPIO -- ti,audio-routing: List of connections between audio components. - Each entry is a pair of strings, the first being the connection's sink, - the second being the connection's source. - If the routing is not provided all possible connection will be available - -Available audio endpoints for the audio-routing table: - -Board connectors: - * Headset Stereophone - * Earpiece Spk - * Handsfree Spk - * Ext Spk - * Main Mic - * Sub Mic - * Headset Mic - * Carkit Mic - * Digital0 Mic - * Digital1 Mic - * Line In - -twl4030 pins: - * HSOL - * HSOR - * EARPIECE - * HFL - * HFR - * PREDRIVEL - * PREDRIVER - * CARKITL - * CARKITR - * MAINMIC - * SUBMIC - * HSMIC - * DIGIMIC0 - * DIGIMIC1 - * CARKITMIC - * AUXL - * AUXR - - * Headset Mic Bias - * Mic Bias 1 /* Used for Main Mic or Digimic0 */ - * Mic Bias 2 /* Used for Sub Mic or Digimic1 */ - -Example: - -sound { - compatible = "ti,omap-twl4030"; - ti,model = "omap3beagle"; - - ti,mcbsp = <&mcbsp2>; -}; diff --git a/Documentation/devicetree/bindings/sound/ti,omap-twl4030.yaml b/Documentation/devicetree/bindings/sound/ti,omap-twl4030.yaml new file mode 100644 index 000000000000..27c7019bdc85 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ti,omap-twl4030.yaml @@ -0,0 +1,98 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/ti,omap-twl4030.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments SoC with twl4030 based audio setups + +maintainers: + - Peter Ujfalusi + +description: + Audio setups on TI OMAP SoCs using TWL4030-family + audio codec connected via a McBSP port. + +properties: + compatible: + const: ti,omap-twl4030 + + ti,model: + $ref: /schemas/types.yaml#/definitions/string + description: Name of the sound card (for example "omap3beagle"). + + ti,mcbsp: + $ref: /schemas/types.yaml#/definitions/phandle + description: phandle for the McBSP node. + + ti,codec: + $ref: /schemas/types.yaml#/definitions/phandle + description: phandle for the twl4030 audio node. + + ti,mcbsp-voice: + $ref: /schemas/types.yaml#/definitions/phandle + description: phandle to the McBSP node connected to the voice port. + + ti,jack-det-gpio: + description: GPIO specifier for jack detection. + maxItems: 1 + + ti,audio-routing: + description: | + A list of audio routing connections. Each entry is a pair of strings, + with the first being the connection's sink and the second being the + source. If not provided, all possible connections are available. + + $ref: /schemas/types.yaml#/definitions/non-unique-string-array + items: + enum: + # Board Connectors + - Headset Stereophone + - Earpiece Spk + - Handsfree Spk + - Ext Spk + - Main Mic + - Sub Mic + - Headset Mic + - Carkit Mic + - Digital0 Mic + - Digital1 Mic + - Line In + + # CODEC Pins + - HSOL + - HSOR + - EARPIECE + - HFL + - HFR + - PREDRIVEL + - PREDRIVER + - CARKITL + - CARKITR + - MAINMIC + - SUBMIC + - HSMIC + - DIGIMIC0 + - DIGIMIC1 + - CARKITMIC + - AUXL + - AUXR + + # Headset Mic Bias + - Mic Bias 1 # Used for Main Mic or Digimic0 + - Mic Bias 2 # Used for Sub Mic or Digimic1 + +required: + - compatible + - ti,model + - ti,mcbsp + +additionalProperties: false + +examples: + - | + sound { + compatible = "ti,omap-twl4030"; + ti,model = "omap3beagle"; + ti,mcbsp = <&mcbsp2>; + }; From efe89a30f70753d861340a20365812e93d34a0de Mon Sep 17 00:00:00 2001 From: Sumanth Korikkar Date: Fri, 8 Aug 2025 14:46:43 +0200 Subject: [PATCH 01569/11391] s390/sclp: Refactor sclp_cmd.c To improve readability, refactor sclp_cmd.c: * Move defines and structures to the beginning. * Reverse x-mas tree usage. * Remove spaces after casting to eliminate checkpatch warnings. * Remove unnecessary comments. * Reframe certain comments. * Convert all unsigned long long to unsigned long since unsigned long long is a leftover from the 31/32-bit era. * Use correct format specifiers. * Add braces to for loops with bodies containing more than one line. * Sort header files and remove unnecessary ones. * Use __packed and __aligned instead of __attribute((packed, aligned(8))) in structures. Acked-by: Heiko Carstens Signed-off-by: Sumanth Korikkar Signed-off-by: Alexander Gordeev --- drivers/s390/char/sclp_cmd.c | 179 ++++++++++++++++------------------- 1 file changed, 83 insertions(+), 96 deletions(-) diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index 16469678548f..ee0884d99d88 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c @@ -8,31 +8,56 @@ #define KMSG_COMPONENT "sclp_cmd" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt -#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 "sclp.h" -#define SCLP_CMDW_ASSIGN_STORAGE 0x000d0001 -#define SCLP_CMDW_UNASSIGN_STORAGE 0x000c0001 +#define SCLP_CMDW_ASSIGN_STORAGE 0x000d0001 +#define SCLP_CMDW_UNASSIGN_STORAGE 0x000c0001 +/* CPU configuration related functions */ +#define SCLP_CMDW_CONFIGURE_CPU 0x00110001 +#define SCLP_CMDW_DECONFIGURE_CPU 0x00100001 +/* Channel path configuration related functions */ +#define SCLP_CMDW_CONFIGURE_CHPATH 0x000f0001 +#define SCLP_CMDW_DECONFIGURE_CHPATH 0x000e0001 +#define SCLP_CMDW_READ_CHPATH_INFORMATION 0x00030001 + +struct cpu_configure_sccb { + struct sccb_header header; +} __packed __aligned(8); + +struct chp_cfg_sccb { + struct sccb_header header; + u8 ccm; + u8 reserved[6]; + u8 cssid; +} __packed; + +struct chp_info_sccb { + struct sccb_header header; + u8 recognized[SCLP_CHP_INFO_MASK_SIZE]; + u8 standby[SCLP_CHP_INFO_MASK_SIZE]; + u8 configured[SCLP_CHP_INFO_MASK_SIZE]; + u8 ccm; + u8 reserved[6]; + u8 cssid; +} __packed; static void sclp_sync_callback(struct sclp_req *req, void *data) { @@ -64,13 +89,11 @@ int sclp_sync_request_timeout(sclp_cmdw_t cmd, void *sccb, int timeout) request->callback_data = &completion; init_completion(&completion); - /* Perform sclp request. */ rc = sclp_add_request(request); if (rc) goto out; wait_for_completion(&completion); - /* Check response. */ if (request->status != SCLP_REQ_DONE) { pr_warn("sync request failed (cmd=0x%08x, status=0x%02x)\n", cmd, request->status); @@ -81,22 +104,15 @@ int sclp_sync_request_timeout(sclp_cmdw_t cmd, void *sccb, int timeout) return rc; } -/* - * CPU configuration related functions. - */ - -#define SCLP_CMDW_CONFIGURE_CPU 0x00110001 -#define SCLP_CMDW_DECONFIGURE_CPU 0x00100001 - int _sclp_get_core_info(struct sclp_core_info *info) { - int rc; - int length = test_facility(140) ? EXT_SCCB_READ_CPU : PAGE_SIZE; struct read_cpu_info_sccb *sccb; + int rc, length; if (!SCLP_HAS_CPU_INFO) return -EOPNOTSUPP; + length = test_facility(140) ? EXT_SCCB_READ_CPU : PAGE_SIZE; sccb = (void *)__get_free_pages(GFP_KERNEL | GFP_DMA | __GFP_ZERO, get_order(length)); if (!sccb) return -ENOMEM; @@ -114,14 +130,10 @@ int _sclp_get_core_info(struct sclp_core_info *info) } sclp_fill_core_info(info, sccb); out: - free_pages((unsigned long) sccb, get_order(length)); + free_pages((unsigned long)sccb, get_order(length)); return rc; } -struct cpu_configure_sccb { - struct sccb_header header; -} __attribute__((packed, aligned(8))); - static int do_core_configure(sclp_cmdw_t cmd) { struct cpu_configure_sccb *sccb; @@ -130,8 +142,8 @@ static int do_core_configure(sclp_cmdw_t cmd) if (!SCLP_HAS_CPU_RECONFIG) return -EOPNOTSUPP; /* - * This is not going to cross a page boundary since we force - * kmalloc to have a minimum alignment of 8 bytes on s390. + * Use kmalloc to have a minimum alignment of 8 bytes and ensure sccb + * is not going to cross a page boundary. */ sccb = kzalloc(sizeof(*sccb), GFP_KERNEL | GFP_DMA); if (!sccb) @@ -183,6 +195,14 @@ struct assign_storage_sccb { u16 rn; } __packed; +struct attach_storage_sccb { + struct sccb_header header; + u16 :16; + u16 assigned; + u32 :32; + u32 entries[]; +} __packed; + int arch_get_memory_phys_device(unsigned long start_pfn) { if (!sclp.rzm) @@ -190,9 +210,9 @@ int arch_get_memory_phys_device(unsigned long start_pfn) return PFN_PHYS(start_pfn) >> ilog2(sclp.rzm); } -static unsigned long long rn2addr(u16 rn) +static unsigned long rn2addr(u16 rn) { - return (unsigned long long) (rn - 1) * sclp.rzm; + return (unsigned long)(rn - 1) * sclp.rzm; } static int do_assign_storage(sclp_cmdw_t cmd, u16 rn) @@ -200,7 +220,7 @@ static int do_assign_storage(sclp_cmdw_t cmd, u16 rn) struct assign_storage_sccb *sccb; int rc; - sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); + sccb = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!sccb) return -ENOMEM; sccb->header.length = PAGE_SIZE; @@ -219,13 +239,13 @@ static int do_assign_storage(sclp_cmdw_t cmd, u16 rn) break; } out: - free_page((unsigned long) sccb); + free_page((unsigned long)sccb); return rc; } static int sclp_assign_storage(u16 rn) { - unsigned long long start; + unsigned long start; int rc; rc = do_assign_storage(SCLP_CMDW_ASSIGN_STORAGE, rn); @@ -241,21 +261,12 @@ static int sclp_unassign_storage(u16 rn) return do_assign_storage(SCLP_CMDW_UNASSIGN_STORAGE, rn); } -struct attach_storage_sccb { - struct sccb_header header; - u16 :16; - u16 assigned; - u32 :32; - u32 entries[]; -} __packed; - static int sclp_attach_storage(u8 id) { struct attach_storage_sccb *sccb; - int rc; - int i; + int rc, i; - sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); + sccb = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!sccb) return -ENOMEM; sccb->header.length = PAGE_SIZE; @@ -277,7 +288,7 @@ static int sclp_attach_storage(u8 id) break; } out: - free_page((unsigned long) sccb); + free_page((unsigned long)sccb); return rc; } @@ -285,7 +296,7 @@ static int sclp_mem_change_state(unsigned long start, unsigned long size, int online) { struct memory_increment *incr; - unsigned long long istart; + unsigned long istart; int rc = 0; list_for_each_entry(incr, &sclp_mem_list, list) { @@ -338,7 +349,7 @@ static int sclp_mem_notifier(struct notifier_block *nb, switch (action) { case MEM_GOING_OFFLINE: /* - * We do not allow to set memory blocks offline that contain + * Do not allow to set memory blocks offline that contain * standby memory. This is done to simplify the "memory online" * case. */ @@ -390,16 +401,16 @@ static struct notifier_block sclp_mem_nb = { .notifier_call = sclp_mem_notifier, }; -static void __init align_to_block_size(unsigned long long *start, - unsigned long long *size, - unsigned long long alignment) +static void __init align_to_block_size(unsigned long *start, + unsigned long *size, + unsigned long alignment) { - unsigned long long start_align, size_align; + unsigned long start_align, size_align; start_align = roundup(*start, alignment); size_align = rounddown(*start + *size, alignment) - start_align; - pr_info("Standby memory at 0x%llx (%lluM of %lluM usable)\n", + pr_info("Standby memory at 0x%lx (%luM of %luM usable)\n", *start, size_align >> 20, *size >> 20); *start = start_align; *size = size_align; @@ -407,7 +418,7 @@ static void __init align_to_block_size(unsigned long long *start, static void __init add_memory_merged(u16 rn) { - unsigned long long start, size, addr, block_size; + unsigned long start, size, addr, block_size; static u16 first_rn, num; if (rn && first_rn && (first_rn + num == rn)) { @@ -417,7 +428,7 @@ static void __init add_memory_merged(u16 rn) if (!first_rn) goto skip_add; start = rn2addr(first_rn); - size = (unsigned long long) num * sclp.rzm; + size = (unsigned long)num * sclp.rzm; if (start >= ident_map_size) goto skip_add; if (start + size > ident_map_size) @@ -426,10 +437,11 @@ static void __init add_memory_merged(u16 rn) align_to_block_size(&start, &size, block_size); if (!size) goto skip_add; - for (addr = start; addr < start + size; addr += block_size) + for (addr = start; addr < start + size; addr += block_size) { add_memory(0, addr, block_size, cpu_has_edat1() ? MHP_MEMMAP_ON_MEMORY | MHP_OFFLINE_INACCESSIBLE : MHP_NONE); + } skip_add: first_rn = rn; num = 1; @@ -439,9 +451,10 @@ static void __init sclp_add_standby_memory(void) { struct memory_increment *incr; - list_for_each_entry(incr, &sclp_mem_list, list) + list_for_each_entry(incr, &sclp_mem_list, list) { if (incr->standby) add_memory_merged(incr->rn); + } add_memory_merged(0); } @@ -480,12 +493,13 @@ static int __init sclp_detect_standby_memory(void) struct read_storage_sccb *sccb; int i, id, assigned, rc; - if (oldmem_data.start) /* No standby memory in kdump mode */ + /* No standby memory in kdump mode */ + if (oldmem_data.start) return 0; - if ((sclp.facilities & 0xe00000000000ULL) != 0xe00000000000ULL) + if ((sclp.facilities & 0xe00000000000UL) != 0xe00000000000UL) return 0; rc = -ENOMEM; - sccb = (void *) __get_free_page(GFP_KERNEL | GFP_DMA); + sccb = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); if (!sccb) goto out; assigned = 0; @@ -531,28 +545,13 @@ static int __init sclp_detect_standby_memory(void) goto out; sclp_add_standby_memory(); out: - free_page((unsigned long) sccb); + free_page((unsigned long)sccb); return rc; } __initcall(sclp_detect_standby_memory); #endif /* CONFIG_MEMORY_HOTPLUG */ -/* - * Channel path configuration related functions. - */ - -#define SCLP_CMDW_CONFIGURE_CHPATH 0x000f0001 -#define SCLP_CMDW_DECONFIGURE_CHPATH 0x000e0001 -#define SCLP_CMDW_READ_CHPATH_INFORMATION 0x00030001 - -struct chp_cfg_sccb { - struct sccb_header header; - u8 ccm; - u8 reserved[6]; - u8 cssid; -} __attribute__((packed)); - static int do_chp_configure(sclp_cmdw_t cmd) { struct chp_cfg_sccb *sccb; @@ -560,8 +559,7 @@ static int do_chp_configure(sclp_cmdw_t cmd) if (!SCLP_HAS_CHP_RECONFIG) return -EOPNOTSUPP; - /* Prepare sccb. */ - sccb = (struct chp_cfg_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA); + sccb = (struct chp_cfg_sccb *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!sccb) return -ENOMEM; sccb->header.length = sizeof(*sccb); @@ -581,7 +579,7 @@ static int do_chp_configure(sclp_cmdw_t cmd) break; } out: - free_page((unsigned long) sccb); + free_page((unsigned long)sccb); return rc; } @@ -609,16 +607,6 @@ int sclp_chp_deconfigure(struct chp_id chpid) return do_chp_configure(SCLP_CMDW_DECONFIGURE_CHPATH | chpid.id << 8); } -struct chp_info_sccb { - struct sccb_header header; - u8 recognized[SCLP_CHP_INFO_MASK_SIZE]; - u8 standby[SCLP_CHP_INFO_MASK_SIZE]; - u8 configured[SCLP_CHP_INFO_MASK_SIZE]; - u8 ccm; - u8 reserved[6]; - u8 cssid; -} __attribute__((packed)); - /** * sclp_chp_read_info - perform read channel-path information sclp command * @info: resulting channel-path information data @@ -634,8 +622,7 @@ int sclp_chp_read_info(struct sclp_chp_info *info) if (!SCLP_HAS_CHP_INFO) return -EOPNOTSUPP; - /* Prepare sccb. */ - sccb = (struct chp_info_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA); + sccb = (struct chp_info_sccb *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!sccb) return -ENOMEM; sccb->header.length = sizeof(*sccb); @@ -652,6 +639,6 @@ int sclp_chp_read_info(struct sclp_chp_info *info) memcpy(info->standby, sccb->standby, SCLP_CHP_INFO_MASK_SIZE); memcpy(info->configured, sccb->configured, SCLP_CHP_INFO_MASK_SIZE); out: - free_page((unsigned long) sccb); + free_page((unsigned long)sccb); return rc; } From f9de6cdf4cf8c932ee94f6e25cd7434a97c78bf3 Mon Sep 17 00:00:00 2001 From: Sumanth Korikkar Date: Fri, 8 Aug 2025 14:46:44 +0200 Subject: [PATCH 01570/11391] s390/sclp: Move memory hotplug code for better modularity To improve readability and prepare for future extensions, move the memory hotplug code to a separate file. In addtion to it, add required headers in sclp_mem.c and remove unnecessary headers in sclp_cmd.c Acked-by: Heiko Carstens Signed-off-by: Sumanth Korikkar Signed-off-by: Alexander Gordeev --- drivers/s390/char/Makefile | 1 + drivers/s390/char/sclp_cmd.c | 385 --------------------------------- drivers/s390/char/sclp_mem.c | 399 +++++++++++++++++++++++++++++++++++ 3 files changed, 400 insertions(+), 385 deletions(-) create mode 100644 drivers/s390/char/sclp_mem.c diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index 81d6744e1861..dcbd51152ee3 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile @@ -21,6 +21,7 @@ obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o sclp_ctl.o \ sclp_early.o sclp_early_core.o sclp_sd.o +obj-$(CONFIG_MEMORY_HOTPLUG) += sclp_mem.o obj-$(CONFIG_TN3270) += raw3270.o con3270.o obj-$(CONFIG_TN3270_FS) += fs3270.o diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index ee0884d99d88..3480198eac02 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c @@ -9,27 +9,17 @@ #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #include -#include #include #include #include -#include -#include -#include -#include #include #include #include #include -#include -#include -#include #include #include "sclp.h" -#define SCLP_CMDW_ASSIGN_STORAGE 0x000d0001 -#define SCLP_CMDW_UNASSIGN_STORAGE 0x000c0001 /* CPU configuration related functions */ #define SCLP_CMDW_CONFIGURE_CPU 0x00110001 #define SCLP_CMDW_DECONFIGURE_CPU 0x00100001 @@ -177,381 +167,6 @@ int sclp_core_deconfigure(u8 core) return do_core_configure(SCLP_CMDW_DECONFIGURE_CPU | core << 8); } -#ifdef CONFIG_MEMORY_HOTPLUG - -static DEFINE_MUTEX(sclp_mem_mutex); -static LIST_HEAD(sclp_mem_list); -static u8 sclp_max_storage_id; -static DECLARE_BITMAP(sclp_storage_ids, 256); - -struct memory_increment { - struct list_head list; - u16 rn; - int standby; -}; - -struct assign_storage_sccb { - struct sccb_header header; - u16 rn; -} __packed; - -struct attach_storage_sccb { - struct sccb_header header; - u16 :16; - u16 assigned; - u32 :32; - u32 entries[]; -} __packed; - -int arch_get_memory_phys_device(unsigned long start_pfn) -{ - if (!sclp.rzm) - return 0; - return PFN_PHYS(start_pfn) >> ilog2(sclp.rzm); -} - -static unsigned long rn2addr(u16 rn) -{ - return (unsigned long)(rn - 1) * sclp.rzm; -} - -static int do_assign_storage(sclp_cmdw_t cmd, u16 rn) -{ - struct assign_storage_sccb *sccb; - int rc; - - sccb = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!sccb) - return -ENOMEM; - sccb->header.length = PAGE_SIZE; - sccb->rn = rn; - rc = sclp_sync_request_timeout(cmd, sccb, SCLP_QUEUE_INTERVAL); - if (rc) - goto out; - switch (sccb->header.response_code) { - case 0x0020: - case 0x0120: - break; - default: - pr_warn("assign storage failed (cmd=0x%08x, response=0x%04x, rn=0x%04x)\n", - cmd, sccb->header.response_code, rn); - rc = -EIO; - break; - } -out: - free_page((unsigned long)sccb); - return rc; -} - -static int sclp_assign_storage(u16 rn) -{ - unsigned long start; - int rc; - - rc = do_assign_storage(SCLP_CMDW_ASSIGN_STORAGE, rn); - if (rc) - return rc; - start = rn2addr(rn); - storage_key_init_range(start, start + sclp.rzm); - return 0; -} - -static int sclp_unassign_storage(u16 rn) -{ - return do_assign_storage(SCLP_CMDW_UNASSIGN_STORAGE, rn); -} - -static int sclp_attach_storage(u8 id) -{ - struct attach_storage_sccb *sccb; - int rc, i; - - sccb = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!sccb) - return -ENOMEM; - sccb->header.length = PAGE_SIZE; - sccb->header.function_code = 0x40; - rc = sclp_sync_request_timeout(0x00080001 | id << 8, sccb, - SCLP_QUEUE_INTERVAL); - if (rc) - goto out; - switch (sccb->header.response_code) { - case 0x0020: - set_bit(id, sclp_storage_ids); - for (i = 0; i < sccb->assigned; i++) { - if (sccb->entries[i]) - sclp_unassign_storage(sccb->entries[i] >> 16); - } - break; - default: - rc = -EIO; - break; - } -out: - free_page((unsigned long)sccb); - return rc; -} - -static int sclp_mem_change_state(unsigned long start, unsigned long size, - int online) -{ - struct memory_increment *incr; - unsigned long istart; - int rc = 0; - - list_for_each_entry(incr, &sclp_mem_list, list) { - istart = rn2addr(incr->rn); - if (start + size - 1 < istart) - break; - if (start > istart + sclp.rzm - 1) - continue; - if (online) - rc |= sclp_assign_storage(incr->rn); - else - sclp_unassign_storage(incr->rn); - if (rc == 0) - incr->standby = online ? 0 : 1; - } - return rc ? -EIO : 0; -} - -static bool contains_standby_increment(unsigned long start, unsigned long end) -{ - struct memory_increment *incr; - unsigned long istart; - - list_for_each_entry(incr, &sclp_mem_list, list) { - istart = rn2addr(incr->rn); - if (end - 1 < istart) - continue; - if (start > istart + sclp.rzm - 1) - continue; - if (incr->standby) - return true; - } - return false; -} - -static int sclp_mem_notifier(struct notifier_block *nb, - unsigned long action, void *data) -{ - unsigned long start, size; - struct memory_notify *arg; - unsigned char id; - int rc = 0; - - arg = data; - start = arg->start_pfn << PAGE_SHIFT; - size = arg->nr_pages << PAGE_SHIFT; - mutex_lock(&sclp_mem_mutex); - for_each_clear_bit(id, sclp_storage_ids, sclp_max_storage_id + 1) - sclp_attach_storage(id); - switch (action) { - case MEM_GOING_OFFLINE: - /* - * Do not allow to set memory blocks offline that contain - * standby memory. This is done to simplify the "memory online" - * case. - */ - if (contains_standby_increment(start, start + size)) - rc = -EPERM; - break; - case MEM_PREPARE_ONLINE: - /* - * Access the altmap_start_pfn and altmap_nr_pages fields - * within the struct memory_notify specifically when dealing - * with only MEM_PREPARE_ONLINE/MEM_FINISH_OFFLINE notifiers. - * - * When altmap is in use, take the specified memory range - * online, which includes the altmap. - */ - if (arg->altmap_nr_pages) { - start = PFN_PHYS(arg->altmap_start_pfn); - size += PFN_PHYS(arg->altmap_nr_pages); - } - rc = sclp_mem_change_state(start, size, 1); - if (rc || !arg->altmap_nr_pages) - break; - /* - * Set CMMA state to nodat here, since the struct page memory - * at the beginning of the memory block will not go through the - * buddy allocator later. - */ - __arch_set_page_nodat((void *)__va(start), arg->altmap_nr_pages); - break; - case MEM_FINISH_OFFLINE: - /* - * When altmap is in use, take the specified memory range - * offline, which includes the altmap. - */ - if (arg->altmap_nr_pages) { - start = PFN_PHYS(arg->altmap_start_pfn); - size += PFN_PHYS(arg->altmap_nr_pages); - } - sclp_mem_change_state(start, size, 0); - break; - default: - break; - } - mutex_unlock(&sclp_mem_mutex); - return rc ? NOTIFY_BAD : NOTIFY_OK; -} - -static struct notifier_block sclp_mem_nb = { - .notifier_call = sclp_mem_notifier, -}; - -static void __init align_to_block_size(unsigned long *start, - unsigned long *size, - unsigned long alignment) -{ - unsigned long start_align, size_align; - - start_align = roundup(*start, alignment); - size_align = rounddown(*start + *size, alignment) - start_align; - - pr_info("Standby memory at 0x%lx (%luM of %luM usable)\n", - *start, size_align >> 20, *size >> 20); - *start = start_align; - *size = size_align; -} - -static void __init add_memory_merged(u16 rn) -{ - unsigned long start, size, addr, block_size; - static u16 first_rn, num; - - if (rn && first_rn && (first_rn + num == rn)) { - num++; - return; - } - if (!first_rn) - goto skip_add; - start = rn2addr(first_rn); - size = (unsigned long)num * sclp.rzm; - if (start >= ident_map_size) - goto skip_add; - if (start + size > ident_map_size) - size = ident_map_size - start; - block_size = memory_block_size_bytes(); - align_to_block_size(&start, &size, block_size); - if (!size) - goto skip_add; - for (addr = start; addr < start + size; addr += block_size) { - add_memory(0, addr, block_size, - cpu_has_edat1() ? - MHP_MEMMAP_ON_MEMORY | MHP_OFFLINE_INACCESSIBLE : MHP_NONE); - } -skip_add: - first_rn = rn; - num = 1; -} - -static void __init sclp_add_standby_memory(void) -{ - struct memory_increment *incr; - - list_for_each_entry(incr, &sclp_mem_list, list) { - if (incr->standby) - add_memory_merged(incr->rn); - } - add_memory_merged(0); -} - -static void __init insert_increment(u16 rn, int standby, int assigned) -{ - struct memory_increment *incr, *new_incr; - struct list_head *prev; - u16 last_rn; - - new_incr = kzalloc(sizeof(*new_incr), GFP_KERNEL); - if (!new_incr) - return; - new_incr->rn = rn; - new_incr->standby = standby; - last_rn = 0; - prev = &sclp_mem_list; - list_for_each_entry(incr, &sclp_mem_list, list) { - if (assigned && incr->rn > rn) - break; - if (!assigned && incr->rn - last_rn > 1) - break; - last_rn = incr->rn; - prev = &incr->list; - } - if (!assigned) - new_incr->rn = last_rn + 1; - if (new_incr->rn > sclp.rnmax) { - kfree(new_incr); - return; - } - list_add(&new_incr->list, prev); -} - -static int __init sclp_detect_standby_memory(void) -{ - struct read_storage_sccb *sccb; - int i, id, assigned, rc; - - /* No standby memory in kdump mode */ - if (oldmem_data.start) - return 0; - if ((sclp.facilities & 0xe00000000000UL) != 0xe00000000000UL) - return 0; - rc = -ENOMEM; - sccb = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); - if (!sccb) - goto out; - assigned = 0; - for (id = 0; id <= sclp_max_storage_id; id++) { - memset(sccb, 0, PAGE_SIZE); - sccb->header.length = PAGE_SIZE; - rc = sclp_sync_request(SCLP_CMDW_READ_STORAGE_INFO | id << 8, sccb); - if (rc) - goto out; - switch (sccb->header.response_code) { - case 0x0010: - set_bit(id, sclp_storage_ids); - for (i = 0; i < sccb->assigned; i++) { - if (!sccb->entries[i]) - continue; - assigned++; - insert_increment(sccb->entries[i] >> 16, 0, 1); - } - break; - case 0x0310: - break; - case 0x0410: - for (i = 0; i < sccb->assigned; i++) { - if (!sccb->entries[i]) - continue; - assigned++; - insert_increment(sccb->entries[i] >> 16, 1, 1); - } - break; - default: - rc = -EIO; - break; - } - if (!rc) - sclp_max_storage_id = sccb->max_id; - } - if (rc || list_empty(&sclp_mem_list)) - goto out; - for (i = 1; i <= sclp.rnmax - assigned; i++) - insert_increment(0, 1, 0); - rc = register_memory_notifier(&sclp_mem_nb); - if (rc) - goto out; - sclp_add_standby_memory(); -out: - free_page((unsigned long)sccb); - return rc; -} -__initcall(sclp_detect_standby_memory); - -#endif /* CONFIG_MEMORY_HOTPLUG */ - static int do_chp_configure(sclp_cmdw_t cmd) { struct chp_cfg_sccb *sccb; diff --git a/drivers/s390/char/sclp_mem.c b/drivers/s390/char/sclp_mem.c new file mode 100644 index 000000000000..27f49f5fd358 --- /dev/null +++ b/drivers/s390/char/sclp_mem.c @@ -0,0 +1,399 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Memory hotplug support via sclp + * + * Copyright IBM Corp. 2025 + */ + +#define KMSG_COMPONENT "sclp_mem" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sclp.h" + +#define SCLP_CMDW_ASSIGN_STORAGE 0x000d0001 +#define SCLP_CMDW_UNASSIGN_STORAGE 0x000c0001 + +static DEFINE_MUTEX(sclp_mem_mutex); +static LIST_HEAD(sclp_mem_list); +static u8 sclp_max_storage_id; +static DECLARE_BITMAP(sclp_storage_ids, 256); + +struct memory_increment { + struct list_head list; + u16 rn; + int standby; +}; + +struct assign_storage_sccb { + struct sccb_header header; + u16 rn; +} __packed; + +struct attach_storage_sccb { + struct sccb_header header; + u16 :16; + u16 assigned; + u32 :32; + u32 entries[]; +} __packed; + +int arch_get_memory_phys_device(unsigned long start_pfn) +{ + if (!sclp.rzm) + return 0; + return PFN_PHYS(start_pfn) >> ilog2(sclp.rzm); +} + +static unsigned long rn2addr(u16 rn) +{ + return (unsigned long)(rn - 1) * sclp.rzm; +} + +static int do_assign_storage(sclp_cmdw_t cmd, u16 rn) +{ + struct assign_storage_sccb *sccb; + int rc; + + sccb = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (!sccb) + return -ENOMEM; + sccb->header.length = PAGE_SIZE; + sccb->rn = rn; + rc = sclp_sync_request_timeout(cmd, sccb, SCLP_QUEUE_INTERVAL); + if (rc) + goto out; + switch (sccb->header.response_code) { + case 0x0020: + case 0x0120: + break; + default: + pr_warn("assign storage failed (cmd=0x%08x, response=0x%04x, rn=0x%04x)\n", + cmd, sccb->header.response_code, rn); + rc = -EIO; + break; + } +out: + free_page((unsigned long)sccb); + return rc; +} + +static int sclp_assign_storage(u16 rn) +{ + unsigned long start; + int rc; + + rc = do_assign_storage(SCLP_CMDW_ASSIGN_STORAGE, rn); + if (rc) + return rc; + start = rn2addr(rn); + storage_key_init_range(start, start + sclp.rzm); + return 0; +} + +static int sclp_unassign_storage(u16 rn) +{ + return do_assign_storage(SCLP_CMDW_UNASSIGN_STORAGE, rn); +} + +static int sclp_attach_storage(u8 id) +{ + struct attach_storage_sccb *sccb; + int rc, i; + + sccb = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (!sccb) + return -ENOMEM; + sccb->header.length = PAGE_SIZE; + sccb->header.function_code = 0x40; + rc = sclp_sync_request_timeout(0x00080001 | id << 8, sccb, + SCLP_QUEUE_INTERVAL); + if (rc) + goto out; + switch (sccb->header.response_code) { + case 0x0020: + set_bit(id, sclp_storage_ids); + for (i = 0; i < sccb->assigned; i++) { + if (sccb->entries[i]) + sclp_unassign_storage(sccb->entries[i] >> 16); + } + break; + default: + rc = -EIO; + break; + } +out: + free_page((unsigned long)sccb); + return rc; +} + +static int sclp_mem_change_state(unsigned long start, unsigned long size, + int online) +{ + struct memory_increment *incr; + unsigned long istart; + int rc = 0; + + list_for_each_entry(incr, &sclp_mem_list, list) { + istart = rn2addr(incr->rn); + if (start + size - 1 < istart) + break; + if (start > istart + sclp.rzm - 1) + continue; + if (online) + rc |= sclp_assign_storage(incr->rn); + else + sclp_unassign_storage(incr->rn); + if (rc == 0) + incr->standby = online ? 0 : 1; + } + return rc ? -EIO : 0; +} + +static bool contains_standby_increment(unsigned long start, unsigned long end) +{ + struct memory_increment *incr; + unsigned long istart; + + list_for_each_entry(incr, &sclp_mem_list, list) { + istart = rn2addr(incr->rn); + if (end - 1 < istart) + continue; + if (start > istart + sclp.rzm - 1) + continue; + if (incr->standby) + return true; + } + return false; +} + +static int sclp_mem_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + unsigned long start, size; + struct memory_notify *arg; + unsigned char id; + int rc = 0; + + arg = data; + start = arg->start_pfn << PAGE_SHIFT; + size = arg->nr_pages << PAGE_SHIFT; + mutex_lock(&sclp_mem_mutex); + for_each_clear_bit(id, sclp_storage_ids, sclp_max_storage_id + 1) + sclp_attach_storage(id); + switch (action) { + case MEM_GOING_OFFLINE: + /* + * Do not allow to set memory blocks offline that contain + * standby memory. This is done to simplify the "memory online" + * case. + */ + if (contains_standby_increment(start, start + size)) + rc = -EPERM; + break; + case MEM_PREPARE_ONLINE: + /* + * Access the altmap_start_pfn and altmap_nr_pages fields + * within the struct memory_notify specifically when dealing + * with only MEM_PREPARE_ONLINE/MEM_FINISH_OFFLINE notifiers. + * + * When altmap is in use, take the specified memory range + * online, which includes the altmap. + */ + if (arg->altmap_nr_pages) { + start = PFN_PHYS(arg->altmap_start_pfn); + size += PFN_PHYS(arg->altmap_nr_pages); + } + rc = sclp_mem_change_state(start, size, 1); + if (rc || !arg->altmap_nr_pages) + break; + /* + * Set CMMA state to nodat here, since the struct page memory + * at the beginning of the memory block will not go through the + * buddy allocator later. + */ + __arch_set_page_nodat((void *)__va(start), arg->altmap_nr_pages); + break; + case MEM_FINISH_OFFLINE: + /* + * When altmap is in use, take the specified memory range + * offline, which includes the altmap. + */ + if (arg->altmap_nr_pages) { + start = PFN_PHYS(arg->altmap_start_pfn); + size += PFN_PHYS(arg->altmap_nr_pages); + } + sclp_mem_change_state(start, size, 0); + break; + default: + break; + } + mutex_unlock(&sclp_mem_mutex); + return rc ? NOTIFY_BAD : NOTIFY_OK; +} + +static struct notifier_block sclp_mem_nb = { + .notifier_call = sclp_mem_notifier, +}; + +static void __init align_to_block_size(unsigned long *start, + unsigned long *size, + unsigned long alignment) +{ + unsigned long start_align, size_align; + + start_align = roundup(*start, alignment); + size_align = rounddown(*start + *size, alignment) - start_align; + + pr_info("Standby memory at 0x%lx (%luM of %luM usable)\n", + *start, size_align >> 20, *size >> 20); + *start = start_align; + *size = size_align; +} + +static void __init add_memory_merged(u16 rn) +{ + unsigned long start, size, addr, block_size; + static u16 first_rn, num; + + if (rn && first_rn && (first_rn + num == rn)) { + num++; + return; + } + if (!first_rn) + goto skip_add; + start = rn2addr(first_rn); + size = (unsigned long)num * sclp.rzm; + if (start >= ident_map_size) + goto skip_add; + if (start + size > ident_map_size) + size = ident_map_size - start; + block_size = memory_block_size_bytes(); + align_to_block_size(&start, &size, block_size); + if (!size) + goto skip_add; + for (addr = start; addr < start + size; addr += block_size) { + add_memory(0, addr, block_size, + cpu_has_edat1() ? + MHP_MEMMAP_ON_MEMORY | MHP_OFFLINE_INACCESSIBLE : MHP_NONE); + } +skip_add: + first_rn = rn; + num = 1; +} + +static void __init sclp_add_standby_memory(void) +{ + struct memory_increment *incr; + + list_for_each_entry(incr, &sclp_mem_list, list) { + if (incr->standby) + add_memory_merged(incr->rn); + } + add_memory_merged(0); +} + +static void __init insert_increment(u16 rn, int standby, int assigned) +{ + struct memory_increment *incr, *new_incr; + struct list_head *prev; + u16 last_rn; + + new_incr = kzalloc(sizeof(*new_incr), GFP_KERNEL); + if (!new_incr) + return; + new_incr->rn = rn; + new_incr->standby = standby; + last_rn = 0; + prev = &sclp_mem_list; + list_for_each_entry(incr, &sclp_mem_list, list) { + if (assigned && incr->rn > rn) + break; + if (!assigned && incr->rn - last_rn > 1) + break; + last_rn = incr->rn; + prev = &incr->list; + } + if (!assigned) + new_incr->rn = last_rn + 1; + if (new_incr->rn > sclp.rnmax) { + kfree(new_incr); + return; + } + list_add(&new_incr->list, prev); +} + +static int __init sclp_detect_standby_memory(void) +{ + struct read_storage_sccb *sccb; + int i, id, assigned, rc; + + /* No standby memory in kdump mode */ + if (oldmem_data.start) + return 0; + if ((sclp.facilities & 0xe00000000000UL) != 0xe00000000000UL) + return 0; + rc = -ENOMEM; + sccb = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); + if (!sccb) + goto out; + assigned = 0; + for (id = 0; id <= sclp_max_storage_id; id++) { + memset(sccb, 0, PAGE_SIZE); + sccb->header.length = PAGE_SIZE; + rc = sclp_sync_request(SCLP_CMDW_READ_STORAGE_INFO | id << 8, sccb); + if (rc) + goto out; + switch (sccb->header.response_code) { + case 0x0010: + set_bit(id, sclp_storage_ids); + for (i = 0; i < sccb->assigned; i++) { + if (!sccb->entries[i]) + continue; + assigned++; + insert_increment(sccb->entries[i] >> 16, 0, 1); + } + break; + case 0x0310: + break; + case 0x0410: + for (i = 0; i < sccb->assigned; i++) { + if (!sccb->entries[i]) + continue; + assigned++; + insert_increment(sccb->entries[i] >> 16, 1, 1); + } + break; + default: + rc = -EIO; + break; + } + if (!rc) + sclp_max_storage_id = sccb->max_id; + } + if (rc || list_empty(&sclp_mem_list)) + goto out; + for (i = 1; i <= sclp.rnmax - assigned; i++) + insert_increment(0, 1, 0); + rc = register_memory_notifier(&sclp_mem_nb); + if (rc) + goto out; + sclp_add_standby_memory(); +out: + free_page((unsigned long)sccb); + return rc; +} +__initcall(sclp_detect_standby_memory); From de88e74889a30bd9ff4047726021cde857348b4b Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 4 Aug 2025 17:08:54 +0200 Subject: [PATCH 01571/11391] s390/bitops: Slightly optimize ffs() and fls64() Use a simpler algorithm to calculate the result of ffs() and fls64(). This generates slightly better code and increases readability. Kernel image size is reduced by ~3kb (gcc 15.1.0 + defconfig). Suggested-by: Nina Schoetterl-Glausch Signed-off-by: Heiko Carstens Signed-off-by: Alexander Gordeev --- arch/s390/include/asm/bitops.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/arch/s390/include/asm/bitops.h b/arch/s390/include/asm/bitops.h index a5ca0a947691..10d7573d1582 100644 --- a/arch/s390/include/asm/bitops.h +++ b/arch/s390/include/asm/bitops.h @@ -193,10 +193,9 @@ static inline unsigned long __ffs(unsigned long word) */ static inline int ffs(int word) { - unsigned long mask = 2 * BITS_PER_LONG - 1; unsigned int val = (unsigned int)word; - return (1 + (__flogr(-val & val) ^ (BITS_PER_LONG - 1))) & mask; + return BITS_PER_LONG - __flogr(-val & val); } /** @@ -223,9 +222,7 @@ static inline unsigned long __fls(unsigned long word) */ static inline int fls64(unsigned long word) { - unsigned long mask = 2 * BITS_PER_LONG - 1; - - return (1 + (__flogr(word) ^ (BITS_PER_LONG - 1))) & mask; + return BITS_PER_LONG - __flogr(word); } /** From 669bc57e7016cf9d1a9eedb2a984c4fb4fd67f3d Mon Sep 17 00:00:00 2001 From: Juergen Christ Date: Mon, 11 Aug 2025 17:22:53 +0200 Subject: [PATCH 01572/11391] s390/bitops: Optimize inlining GCC inlining heuristics prevent code growth due to inlining into cold paths. This causes GCC to emit a partially specialized version of __flogr for non-constant input for all occurrences on cold paths. This happens since the overhead seen during inlining includes setting up a union register_pair, calling flogr, and extracting and casting the result. This overhead is not removed until the function is lowered into RTL. But this happens after inlining. For -ftrivial-var-auto-init=zero builds, an additional initialization of the union register_pair adds another statement to be inlinined. This is unneeded since the even register is initialized anyway and the odd register is not an input register. It is only marked as such since the whole pair has to be marked as a read/write output register. Mark the union register_pair as uninitialized to get rid of this statement. This, however, does not change the code since the initialization happens when part of the register pair is written. Nevertheless, GCC function size approximation during inlining is reduced by one statement. Force inlining of flogr and also flatten some other functions that should be leaf functions but are called in cold context, like, e.g., __init functions. Acked-by: Heiko Carstens Signed-off-by: Juergen Christ Signed-off-by: Alexander Gordeev --- arch/s390/include/asm/bitops.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/s390/include/asm/bitops.h b/arch/s390/include/asm/bitops.h index 10d7573d1582..9dfb687ba620 100644 --- a/arch/s390/include/asm/bitops.h +++ b/arch/s390/include/asm/bitops.h @@ -130,7 +130,7 @@ static inline bool test_bit_inv(unsigned long nr, * where the most significant bit has bit number 0. * If no bit is set this function returns 64. */ -static inline unsigned char __flogr(unsigned long word) +static __always_inline unsigned char __flogr(unsigned long word) { if (__builtin_constant_p(word)) { unsigned long bit = 0; @@ -163,7 +163,7 @@ static inline unsigned char __flogr(unsigned long word) } return bit; } else { - union register_pair rp; + union register_pair rp __uninitialized; rp.even = word; asm volatile( @@ -179,7 +179,7 @@ static inline unsigned char __flogr(unsigned long word) * * Undefined if no bit exists, so code should check against 0 first. */ -static inline unsigned long __ffs(unsigned long word) +static __always_inline __flatten unsigned long __ffs(unsigned long word) { return __flogr(-word & word) ^ (BITS_PER_LONG - 1); } @@ -191,7 +191,7 @@ static inline unsigned long __ffs(unsigned long word) * This is defined the same way as the libc and * compiler builtin ffs routines (man ffs). */ -static inline int ffs(int word) +static __always_inline __flatten int ffs(int word) { unsigned int val = (unsigned int)word; @@ -204,7 +204,7 @@ static inline int ffs(int word) * * Undefined if no set bit exists, so code should check against 0 first. */ -static inline unsigned long __fls(unsigned long word) +static __always_inline __flatten unsigned long __fls(unsigned long word) { return __flogr(word) ^ (BITS_PER_LONG - 1); } @@ -220,7 +220,7 @@ static inline unsigned long __fls(unsigned long word) * set bit if value is nonzero. The last (most significant) bit is * at position 64. */ -static inline int fls64(unsigned long word) +static __always_inline __flatten int fls64(unsigned long word) { return BITS_PER_LONG - __flogr(word); } @@ -232,7 +232,7 @@ static inline int fls64(unsigned long word) * This is defined the same way as ffs. * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. */ -static inline int fls(unsigned int word) +static __always_inline __flatten int fls(unsigned int word) { return fls64(word); } From 75c21418beb92382dda164fdc2554610b49ed441 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Tue, 19 Aug 2025 01:15:22 +0100 Subject: [PATCH 01573/11391] 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 776cc2ec155cfc066087436a6afc86fe52bd5365 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Wed, 23 Jul 2025 08:26:31 +0200 Subject: [PATCH 01574/11391] EDAC/altera: Use dev_fwnode() irq_domain_create_simple() takes fwnode as the first argument. It can be extracted from the struct device using dev_fwnode() helper instead of using of_node with of_fwnode_handle(). So use the dev_fwnode() helper. Signed-off-by: Jiri Slaby (SUSE) Signed-off-by: Borislav Petkov (AMD) Reviewed-by: Yazen Ghannam Acked-by: Dinh Nguyen Link: https://lore.kernel.org/20250723062631.1830757-1-jirislaby@kernel.org --- drivers/edac/altera_edac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index cae52c654a15..cfd17a8e5865 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -2131,8 +2131,8 @@ static int altr_edac_a10_probe(struct platform_device *pdev) edac->irq_chip.name = pdev->dev.of_node->name; edac->irq_chip.irq_mask = a10_eccmgr_irq_mask; edac->irq_chip.irq_unmask = a10_eccmgr_irq_unmask; - edac->domain = irq_domain_create_linear(of_fwnode_handle(pdev->dev.of_node), - 64, &a10_eccmgr_ic_ops, edac); + edac->domain = irq_domain_create_linear(dev_fwnode(&pdev->dev), 64, &a10_eccmgr_ic_ops, + edac); if (!edac->domain) { dev_err(&pdev->dev, "Error adding IRQ domain\n"); return -ENOMEM; From e1e1e77f7df7cbee959ba024e5475907fe561c98 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 13 Aug 2025 18:14:58 +0200 Subject: [PATCH 01575/11391] 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 01576/11391] 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 dd7ddd082206f675e967c205df2a35b9c4e64949 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 19 Aug 2025 10:28:49 -0700 Subject: [PATCH 01577/11391] mmc: sdhci-cadence: Fix -Wuninitialized in sdhci_cdns_tune_blkgap() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clang warns (or errors with CONFIG_WERROR=y): drivers/mmc/host/sdhci-cadence.c:297:9: error: variable 'hrs37_mode' is uninitialized when used here [-Werror,-Wuninitialized] 297 | writel(hrs37_mode, hrs37_reg); | ^~~~~~~~~~ drivers/mmc/host/sdhci-cadence.c:291:16: note: initialize the variable 'hrs37_mode' to silence this warning 291 | u32 hrs37_mode; | ^ | = 0 A previous revision assigned SDHCI_CDNS_HRS37_MODE_MMC_HS200 to hrs37_mode in a switch statement but the final revision moved to a simple if statement. Pass that as the value to writel() and remove hrs37_mode, clearing up the warning. Fixes: 60613a8b9b81 ("mmc: sdhci-cadence: implement multi-block read gap tuning") Signed-off-by: Nathan Chancellor Tested-by: Benoît Monin Link: https://lore.kernel.org/r/20250819-mmc-sdhci-cadence-fix-uninit-hrs37_mode-v1-1-94aa2d0c438a@kernel.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-cadence.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c index a2a4a5b0ab96..eaa88897a256 100644 --- a/drivers/mmc/host/sdhci-cadence.c +++ b/drivers/mmc/host/sdhci-cadence.c @@ -288,13 +288,12 @@ static int sdhci_cdns_tune_blkgap(struct mmc_host *mmc) void __iomem *hrs38_reg = priv->hrs_addr + SDHCI_CDNS_HRS38; int ret; u32 gap; - u32 hrs37_mode; /* Currently only needed in HS200 mode */ if (host->timing != MMC_TIMING_MMC_HS200) return 0; - writel(hrs37_mode, hrs37_reg); + writel(SDHCI_CDNS_HRS37_MODE_MMC_HS200, hrs37_reg); for (gap = 0; gap <= SDHCI_CDNS_HRS38_BLKGAP_MAX; gap++) { writel(gap, hrs38_reg); From 5d0702dc9c2f6700140b7366dd9ec6c78cde3aa1 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Wed, 20 Aug 2025 11:48:01 +0100 Subject: [PATCH 01578/11391] mmc: renesas_sdhi: Replace magic number '0xff' in renesas_sdhi_set_clock() Replace the magic number '0xff' with CLK_CTL_DIV_MASK macro for finding actual clock in renesas_sdhi_set_clock(). Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20250820104808.94562-1-biju.das.jz@bp.renesas.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/renesas_sdhi_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index a41291a28e9b..f56fa2cd208d 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -223,7 +223,7 @@ static void renesas_sdhi_set_clock(struct tmio_mmc_host *host, } clock = clk & CLK_CTL_DIV_MASK; - if (clock != 0xff) + if (clock != CLK_CTL_DIV_MASK) host->mmc->actual_clock /= (1 << (ffs(clock) + 1)); sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clock); From a8f9de937dbf7bdabda72bd0c51e201e550129c2 Mon Sep 17 00:00:00 2001 From: Chen Ni Date: Thu, 14 Aug 2025 09:39:43 +0800 Subject: [PATCH 01579/11391] 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 01580/11391] 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 01581/11391] 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 01582/11391] 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 01583/11391] 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 01584/11391] 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 01585/11391] 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 01586/11391] 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 @@ static int rcar_gen3_phy_usb2_init_bus(struct rcar_gen3_chan *channel) 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 01587/11391] 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 01588/11391] 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 01589/11391] 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 01590/11391] 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 01591/11391] 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 4184f0190792aea06553af963741a24cc9b47689 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 13 Aug 2025 01:59:27 +0800 Subject: [PATCH 01592/11391] arm64: dts: allwinner: a527: cubie-a5e: Add LEDs The Radxa Cubie A5E has a 3-color LED. The green and blue LEDs are wired to GPIO pins on the SoC, and the green one is lit by default to serve as a power indicator. The red LED is wired to the M.2 slot. Add device nodes for the green and blue LEDs. A default "heartbeat" trigger is set for the green power LED, though in practice it might be better if it were inverted, i.e. lit most of the time. Acked-by: Jernej Skrabec Link: https://patch.msgid.link/20250812175927.2199219-1-wens@kernel.org Signed-off-by: Chen-Yu Tsai --- .../dts/allwinner/sun55i-a527-cubie-a5e.dts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts b/arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts index 553ad774ed13..70d439bc845c 100644 --- a/arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts +++ b/arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts @@ -6,6 +6,7 @@ #include "sun55i-a523.dtsi" #include +#include / { model = "Radxa Cubie A5E"; @@ -27,6 +28,24 @@ ext_osc32k: ext-osc32k-clk { clock-output-names = "ext_osc32k"; }; + leds { + compatible = "gpio-leds"; + + power-led { + function = LED_FUNCTION_POWER; + color = ; + gpios = <&r_pio 0 4 GPIO_ACTIVE_LOW>; /* PL4 */ + default-state = "on"; + linux,default-trigger = "heartbeat"; + }; + + use-led { + function = LED_FUNCTION_ACTIVITY; + color = ; + gpios = <&r_pio 0 5 GPIO_ACTIVE_LOW>; /* PL5 */ + }; + }; + reg_vcc5v: vcc5v { /* board wide 5V supply from the USB-C connector */ compatible = "regulator-fixed"; From 06ea48beece831a8447758e5432ad1cd60765363 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 19 Aug 2025 15:17:53 +0200 Subject: [PATCH 01593/11391] ARM: dts: allwinner: Minor whitespace cleanup The DTS code coding style expects exactly one space around '=' or '{' characters. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250819131752.86948-2-krzysztof.kozlowski@linaro.org Signed-off-by: Chen-Yu Tsai --- arch/arm/boot/dts/allwinner/sun4i-a10-olinuxino-lime.dts | 2 +- arch/arm/boot/dts/allwinner/sun8i-q8-common.dtsi | 2 +- arch/arm/boot/dts/allwinner/sun8i-r40.dtsi | 2 +- arch/arm/boot/dts/allwinner/sun8i-v3s-netcube-kumquat.dts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/allwinner/sun4i-a10-olinuxino-lime.dts b/arch/arm/boot/dts/allwinner/sun4i-a10-olinuxino-lime.dts index 83d283cf6633..d425d9ee83db 100644 --- a/arch/arm/boot/dts/allwinner/sun4i-a10-olinuxino-lime.dts +++ b/arch/arm/boot/dts/allwinner/sun4i-a10-olinuxino-lime.dts @@ -218,7 +218,7 @@ &usb_otg { &usbphy { usb0_id_det-gpios = <&pio 7 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PH4 */ usb0_vbus_det-gpios = <&pio 7 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PH5 */ - usb0_vbus-supply = <®_usb0_vbus>; + usb0_vbus-supply = <®_usb0_vbus>; usb1_vbus-supply = <®_usb1_vbus>; usb2_vbus-supply = <®_usb2_vbus>; status = "okay"; diff --git a/arch/arm/boot/dts/allwinner/sun8i-q8-common.dtsi b/arch/arm/boot/dts/allwinner/sun8i-q8-common.dtsi index 272584881bb2..a0f787581dd9 100644 --- a/arch/arm/boot/dts/allwinner/sun8i-q8-common.dtsi +++ b/arch/arm/boot/dts/allwinner/sun8i-q8-common.dtsi @@ -82,7 +82,7 @@ &de { }; &ehci0 { - status = "okay"; + status = "okay"; }; &mmc1 { diff --git a/arch/arm/boot/dts/allwinner/sun8i-r40.dtsi b/arch/arm/boot/dts/allwinner/sun8i-r40.dtsi index fa162f7fa9f0..f0ed802a9d08 100644 --- a/arch/arm/boot/dts/allwinner/sun8i-r40.dtsi +++ b/arch/arm/boot/dts/allwinner/sun8i-r40.dtsi @@ -705,7 +705,7 @@ uart2_pi_pins: uart2-pi-pins { }; /omit-if-no-ref/ - uart2_rts_cts_pi_pins: uart2-rts-cts-pi-pins{ + uart2_rts_cts_pi_pins: uart2-rts-cts-pi-pins { pins = "PI16", "PI17"; function = "uart2"; }; diff --git a/arch/arm/boot/dts/allwinner/sun8i-v3s-netcube-kumquat.dts b/arch/arm/boot/dts/allwinner/sun8i-v3s-netcube-kumquat.dts index 5143cb4e7b78..cb6292319f39 100644 --- a/arch/arm/boot/dts/allwinner/sun8i-v3s-netcube-kumquat.dts +++ b/arch/arm/boot/dts/allwinner/sun8i-v3s-netcube-kumquat.dts @@ -29,7 +29,7 @@ chosen { clk_can0: clock-can0 { compatible = "fixed-clock"; #clock-cells = <0>; - clock-frequency = <40000000>; + clock-frequency = <40000000>; }; gpio-keys { From 72dd8b2914b5db1dccf902971c2ea6b541711b28 Mon Sep 17 00:00:00 2001 From: Abin Joseph Date: Tue, 22 Jul 2025 12:32:55 +0530 Subject: [PATCH 01594/11391] 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 01595/11391] 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 01596/11391] 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 01597/11391] 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 01598/11391] 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 2e8f4c2b2bb12fc3d40762f1bb778e95c6ddbc93 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 7 Aug 2025 09:48:35 +0800 Subject: [PATCH 01599/11391] f2fs: fix to clear unusable_cap for checkpoint=enable mount -t f2fs -o checkpoint=disable:10% /dev/vdb /mnt/f2fs/ mount -t f2fs -o remount,checkpoint=enable /dev/vdb /mnt/f2fs/ kernel log: F2FS-fs (vdb): Adjust unusable cap for checkpoint=disable = 204440 / 10% If we has assigned checkpoint=enable mount option, unusable_cap{,_perc} parameters of checkpoint=disable should be reset, then calculation and log print could be avoid in adjust_unusable_cap_perc(). Fixes: 1ae18f71cb52 ("f2fs: fix checkpoint=disable:%u%%") Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/super.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 0638ae9816ac..195ec6e598d2 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -998,6 +998,10 @@ static int f2fs_parse_param(struct fs_context *fc, struct fs_parameter *param) ctx_set_opt(ctx, F2FS_MOUNT_DISABLE_CHECKPOINT); break; case Opt_checkpoint_enable: + F2FS_CTX_INFO(ctx).unusable_cap_perc = 0; + ctx->spec_mask |= F2FS_SPEC_checkpoint_disable_cap_perc; + F2FS_CTX_INFO(ctx).unusable_cap = 0; + ctx->spec_mask |= F2FS_SPEC_checkpoint_disable_cap; ctx_clear_opt(ctx, F2FS_MOUNT_DISABLE_CHECKPOINT); break; default: From 8fc6056dcf79937c46c97fa4996cda65956437a9 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 7 Aug 2025 10:44:31 +0800 Subject: [PATCH 01600/11391] f2fs: fix to detect potential corrupted nid in free_nid_list As reported, on-disk footer.ino and footer.nid is the same and out-of-range, let's add sanity check on f2fs_alloc_nid() to detect any potential corruption in free_nid_list. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/node.c | 17 ++++++++++++++++- include/linux/f2fs_fs.h | 1 + 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 27743b93e186..286e8a53f8e7 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -27,12 +27,17 @@ static struct kmem_cache *free_nid_slab; static struct kmem_cache *nat_entry_set_slab; static struct kmem_cache *fsync_node_entry_slab; +static inline bool is_invalid_nid(struct f2fs_sb_info *sbi, nid_t nid) +{ + return nid < F2FS_ROOT_INO(sbi) || nid >= NM_I(sbi)->max_nid; +} + /* * Check whether the given nid is within node id range. */ int f2fs_check_nid_range(struct f2fs_sb_info *sbi, nid_t nid) { - if (unlikely(nid < F2FS_ROOT_INO(sbi) || nid >= NM_I(sbi)->max_nid)) { + if (unlikely(is_invalid_nid(sbi, nid))) { set_sbi_flag(sbi, SBI_NEED_FSCK); f2fs_warn(sbi, "%s: out-of-range nid=%x, run fsck to fix.", __func__, nid); @@ -2634,6 +2639,16 @@ bool f2fs_alloc_nid(struct f2fs_sb_info *sbi, nid_t *nid) f2fs_bug_on(sbi, list_empty(&nm_i->free_nid_list)); i = list_first_entry(&nm_i->free_nid_list, struct free_nid, list); + + if (unlikely(is_invalid_nid(sbi, i->nid))) { + spin_unlock(&nm_i->nid_list_lock); + f2fs_err(sbi, "Corrupted nid %u in free_nid_list", + i->nid); + f2fs_stop_checkpoint(sbi, false, + STOP_CP_REASON_CORRUPTED_NID); + return false; + } + *nid = i->nid; __move_free_nid(sbi, i, FREE_NID, PREALLOC_NID); diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h index 2f8b8bfc0e73..6afb4a13b81d 100644 --- a/include/linux/f2fs_fs.h +++ b/include/linux/f2fs_fs.h @@ -79,6 +79,7 @@ enum stop_cp_reason { STOP_CP_REASON_FLUSH_FAIL, STOP_CP_REASON_NO_SEGMENT, STOP_CP_REASON_CORRUPTED_FREE_BITMAP, + STOP_CP_REASON_CORRUPTED_NID, STOP_CP_REASON_MAX, }; From 4bc347779698b5e67e1514bab105c2c083e55502 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 7 Aug 2025 12:00:25 +0800 Subject: [PATCH 01601/11391] f2fs: add timeout in f2fs_enable_checkpoint() During f2fs_enable_checkpoint() in remount(), if we flush a large amount of dirty pages into slow device, it may take long time which will block write IO, let's add a timeout machanism during dirty pages flush to avoid long time block in f2fs_enable_checkpoint(). Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/f2fs.h | 2 ++ fs/f2fs/super.c | 21 +++++++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 36d6a6803916..0655c5c20eee 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -267,6 +267,7 @@ enum { #define DEF_CP_INTERVAL 60 /* 60 secs */ #define DEF_IDLE_INTERVAL 5 /* 5 secs */ #define DEF_DISABLE_INTERVAL 5 /* 5 secs */ +#define DEF_ENABLE_INTERVAL 16 /* 16 secs */ #define DEF_DISABLE_QUICK_INTERVAL 1 /* 1 secs */ #define DEF_UMOUNT_DISCARD_TIMEOUT 5 /* 5 secs */ @@ -1397,6 +1398,7 @@ enum { DISCARD_TIME, GC_TIME, DISABLE_TIME, + ENABLE_TIME, UMOUNT_DISCARD_TIMEOUT, MAX_TIME, }; diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 195ec6e598d2..7f5ee1daa5a4 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -2594,16 +2594,24 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi) static void f2fs_enable_checkpoint(struct f2fs_sb_info *sbi) { - int retry = DEFAULT_RETRY_IO_COUNT; + unsigned int nr_pages = get_pages(sbi, F2FS_DIRTY_DATA) / 16; + + f2fs_update_time(sbi, ENABLE_TIME); /* we should flush all the data to keep data consistency */ - do { - sync_inodes_sb(sbi->sb); + while (get_pages(sbi, F2FS_DIRTY_DATA)) { + writeback_inodes_sb_nr(sbi->sb, nr_pages, WB_REASON_SYNC); f2fs_io_schedule_timeout(DEFAULT_IO_TIMEOUT); - } while (get_pages(sbi, F2FS_DIRTY_DATA) && retry--); - if (unlikely(retry < 0)) - f2fs_warn(sbi, "checkpoint=enable has some unwritten data."); + if (f2fs_time_over(sbi, ENABLE_TIME)) + break; + } + + sync_inodes_sb(sbi->sb); + + if (unlikely(get_pages(sbi, F2FS_DIRTY_DATA))) + f2fs_warn(sbi, "checkpoint=enable has some unwritten data: %lld", + get_pages(sbi, F2FS_DIRTY_DATA)); f2fs_down_write(&sbi->gc_lock); f2fs_dirty_to_prefree(sbi); @@ -4200,6 +4208,7 @@ static void init_sb_info(struct f2fs_sb_info *sbi) sbi->interval_time[DISCARD_TIME] = DEF_IDLE_INTERVAL; sbi->interval_time[GC_TIME] = DEF_IDLE_INTERVAL; sbi->interval_time[DISABLE_TIME] = DEF_DISABLE_INTERVAL; + sbi->interval_time[ENABLE_TIME] = DEF_ENABLE_INTERVAL; sbi->interval_time[UMOUNT_DISCARD_TIMEOUT] = DEF_UMOUNT_DISCARD_TIMEOUT; clear_sbi_flag(sbi, SBI_NEED_FSCK); From 80b6d1d2535a343e43d658777a46f1ebce8f3413 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 7 Aug 2025 12:00:26 +0800 Subject: [PATCH 01602/11391] f2fs: dump more information for f2fs_{enable,disable}_checkpoint() Changes as below: - print more logs for f2fs_{enable,disable}_checkpoint() - account and dump time stats for f2fs_enable_checkpoint() Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/super.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 7f5ee1daa5a4..87f6490d9247 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -2589,15 +2589,24 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi) restore_flag: sbi->gc_mode = gc_mode; sbi->sb->s_flags = s_flags; /* Restore SB_RDONLY status */ + f2fs_info(sbi, "f2fs_disable_checkpoint() finish, err:%d", err); return err; } static void f2fs_enable_checkpoint(struct f2fs_sb_info *sbi) { unsigned int nr_pages = get_pages(sbi, F2FS_DIRTY_DATA) / 16; + long long start, writeback, end; + + f2fs_info(sbi, "f2fs_enable_checkpoint() starts, meta: %lld, node: %lld, data: %lld", + get_pages(sbi, F2FS_DIRTY_META), + get_pages(sbi, F2FS_DIRTY_NODES), + get_pages(sbi, F2FS_DIRTY_DATA)); f2fs_update_time(sbi, ENABLE_TIME); + start = ktime_get(); + /* we should flush all the data to keep data consistency */ while (get_pages(sbi, F2FS_DIRTY_DATA)) { writeback_inodes_sb_nr(sbi->sb, nr_pages, WB_REASON_SYNC); @@ -2606,6 +2615,7 @@ static void f2fs_enable_checkpoint(struct f2fs_sb_info *sbi) if (f2fs_time_over(sbi, ENABLE_TIME)) break; } + writeback = ktime_get(); sync_inodes_sb(sbi->sb); @@ -2624,6 +2634,12 @@ static void f2fs_enable_checkpoint(struct f2fs_sb_info *sbi) /* Let's ensure there's no pending checkpoint anymore */ f2fs_flush_ckpt_thread(sbi); + + end = ktime_get(); + + f2fs_info(sbi, "f2fs_enable_checkpoint() finishes, writeback:%llu, sync:%llu", + ktime_ms_delta(writeback, start), + ktime_ms_delta(end, writeback)); } static int __f2fs_remount(struct fs_context *fc, struct super_block *sb) From 00798cd24f014fe55cbcdfeac4bab19ad6cd2bcb Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Fri, 8 Aug 2025 17:48:01 +0800 Subject: [PATCH 01603/11391] f2fs: Add bggc_io_aware to adjust the priority of BG_GC when issuing IO Currently, we have encountered some issues while testing ZUFS. In situations near the storage limit (e.g., 50GB remaining), and after simulating fragmentation by repeatedly writing and deleting data, we found that application installation and startup tests conducted after idling for a few minutes take significantly longer several times that of traditional UFS. Tracing the operations revealed that the majority of I/Os were issued by background GC, which blocks normal I/O operations. Under normal circumstances, ZUFS indeed requires more background GC and employs a more aggressive GC strategy. However, I aim to find a way to minimize the impact on regular I/O operations under these near-limit conditions. To address this, I have introduced a bggc_io_aware feature, which controls the prioritization of background GC in the presence of I/Os. This switch can be adjusted at the framework level to implement different strategies. If set to AWARE_ALL_IO, all background GC operations will be skipped during active I/O issuance. The default option remains consistent with the current strategy, ensuring no change in behavior. Signed-off-by: Liao Yuanhong Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- Documentation/ABI/testing/sysfs-fs-f2fs | 13 +++++++++++++ fs/f2fs/f2fs.h | 18 +++++++++++------- fs/f2fs/super.c | 2 ++ fs/f2fs/sysfs.c | 9 +++++++++ 4 files changed, 35 insertions(+), 7 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs index ce189acd1908..66ee15681983 100644 --- a/Documentation/ABI/testing/sysfs-fs-f2fs +++ b/Documentation/ABI/testing/sysfs-fs-f2fs @@ -898,3 +898,16 @@ Description: - "compat": Hash-based lookup with a linear search fallback enabled - "auto:perf": lookup_mode is auto and fallback is disabled on-disk - "auto:compat": lookup_mode is auto and fallback is enabled on-disk + +What: /sys/fs/f2fs//bggc_io_aware +Date: August 2025 +Contact: "Liao Yuanhong" +Description: Used to adjust the BG_GC priority when pending IO, with a default value + of 0. Specifically, for ZUFS, the default value is 1. + + ================== ====================================================== + value description + bggc_io_aware = 0 skip background GC if there is any kind of pending IO + bggc_io_aware = 1 skip background GC if there is pending read IO + bggc_io_aware = 2 don't aware IO for background GC + ================== ====================================================== diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 0655c5c20eee..dba391b72119 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -155,6 +155,12 @@ enum blkzone_allocation_policy { BLKZONE_ALLOC_PRIOR_CONV, /* Prioritize writing to conventional zones */ }; +enum bggc_io_aware_policy { + AWARE_ALL_IO, /* skip background GC if there is any kind of pending IO */ + AWARE_READ_IO, /* skip background GC if there is pending read IO */ + AWARE_NONE, /* don't aware IO for background GC */ +}; + /* * An implementation of an rwsem that is explicitly unfair to readers. This * prevents priority inversion when a low-priority reader acquires the read lock @@ -1841,6 +1847,7 @@ struct f2fs_sb_info { spinlock_t dev_lock; /* protect dirty_device */ bool aligned_blksize; /* all devices has the same logical blksize */ unsigned int first_seq_zone_segno; /* first segno in sequential zone */ + unsigned int bggc_io_aware; /* For adjust the BG_GC priority when pending IO */ /* For write statistics */ u64 sectors_written_start; @@ -3033,13 +3040,10 @@ static inline bool is_idle(struct f2fs_sb_info *sbi, int type) if (sbi->gc_mode == GC_URGENT_HIGH) return true; - if (zoned_gc) { - if (is_inflight_read_io(sbi)) - return false; - } else { - if (is_inflight_io(sbi, type)) - return false; - } + if (sbi->bggc_io_aware == AWARE_READ_IO && is_inflight_read_io(sbi)) + return false; + if (sbi->bggc_io_aware == AWARE_ALL_IO && is_inflight_io(sbi, type)) + return false; if (sbi->gc_mode == GC_URGENT_MID) return true; diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 87f6490d9247..2000880b7dca 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -4683,9 +4683,11 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi) logical_blksize = bdev_logical_block_size(sbi->sb->s_bdev); sbi->aligned_blksize = true; + sbi->bggc_io_aware = AWARE_ALL_IO; #ifdef CONFIG_BLK_DEV_ZONED sbi->max_open_zones = UINT_MAX; sbi->blkzone_alloc_policy = BLKZONE_ALLOC_PRIOR_SEQ; + sbi->bggc_io_aware = AWARE_READ_IO; #endif for (i = 0; i < max_devices; i++) { diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c index 82489c78aeda..1ffaf9e74ce9 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c @@ -882,6 +882,13 @@ static ssize_t __sbi_store(struct f2fs_attr *a, return count; } + if (!strcmp(a->attr.name, "bggc_io_aware")) { + if (t < AWARE_ALL_IO || t > AWARE_NONE) + return -EINVAL; + sbi->bggc_io_aware = t; + return count; + } + *ui = (unsigned int)t; return count; @@ -1191,6 +1198,7 @@ F2FS_SBI_GENERAL_RW_ATTR(blkzone_alloc_policy); #endif F2FS_SBI_GENERAL_RW_ATTR(carve_out); F2FS_SBI_GENERAL_RW_ATTR(reserved_pin_section); +F2FS_SBI_GENERAL_RW_ATTR(bggc_io_aware); /* STAT_INFO ATTR */ #ifdef CONFIG_F2FS_STAT_FS @@ -1320,6 +1328,7 @@ static struct attribute *f2fs_attrs[] = { ATTR_LIST(discard_idle_interval), ATTR_LIST(gc_idle_interval), ATTR_LIST(umount_discard_timeout), + ATTR_LIST(bggc_io_aware), #ifdef CONFIG_F2FS_IOSTAT ATTR_LIST(iostat_enable), ATTR_LIST(iostat_period_ms), From 2141879369681ff899a6a0857eef8bded785a5b5 Mon Sep 17 00:00:00 2001 From: Chunhai Guo Date: Thu, 7 Aug 2025 21:35:01 +0800 Subject: [PATCH 01604/11391] f2fs: add reserved nodes for privileged users This patch allows privileged users to reserve nodes via the 'reserve_node' mount option, which is similar to the existing 'reserve_root' option. "-o reserve_node=" means nodes are reserved for privileged users only. Signed-off-by: Chunhai Guo Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- Documentation/filesystems/f2fs.rst | 9 ++++--- fs/f2fs/f2fs.h | 17 ++++++++---- fs/f2fs/super.c | 43 +++++++++++++++++++++++++----- 3 files changed, 54 insertions(+), 15 deletions(-) diff --git a/Documentation/filesystems/f2fs.rst b/Documentation/filesystems/f2fs.rst index 5cad369ceb92..e06cbb823bb7 100644 --- a/Documentation/filesystems/f2fs.rst +++ b/Documentation/filesystems/f2fs.rst @@ -173,9 +173,12 @@ data_flush Enable data flushing before checkpoint in order to persist data of regular and symlink. reserve_root=%d Support configuring reserved space which is used for allocation from a privileged user with specified uid or - gid, unit: 4KB, the default limit is 0.2% of user blocks. -resuid=%d The user ID which may use the reserved blocks. -resgid=%d The group ID which may use the reserved blocks. + gid, unit: 4KB, the default limit is 12.5% of user blocks. +reserve_node=%d Support configuring reserved nodes which are used for + allocation from a privileged user with specified uid or + gid, the default limit is 12.5% of all nodes. +resuid=%d The user ID which may use the reserved blocks and nodes. +resgid=%d The group ID which may use the reserved blocks and nodes. fault_injection=%d Enable fault injection in all supported types with specified injection rate. fault_type=%d Support configuring fault injection type, should be diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index dba391b72119..d6a49de1b7e9 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -131,6 +131,7 @@ extern const char *f2fs_fault_name[FAULT_MAX]; * string rather than using the MS_LAZYTIME flag, so this must remain. */ #define F2FS_MOUNT_LAZYTIME 0x40000000 +#define F2FS_MOUNT_RESERVE_NODE 0x80000000 #define F2FS_OPTION(sbi) ((sbi)->mount_opt) #define clear_opt(sbi, option) (F2FS_OPTION(sbi).opt &= ~F2FS_MOUNT_##option) @@ -178,6 +179,7 @@ struct f2fs_rwsem { struct f2fs_mount_info { unsigned int opt; block_t root_reserved_blocks; /* root reserved blocks */ + block_t root_reserved_nodes; /* root reserved nodes */ kuid_t s_resuid; /* reserved blocks for uid */ kgid_t s_resgid; /* reserved blocks for gid */ int active_logs; /* # of active logs */ @@ -2400,7 +2402,7 @@ static inline bool f2fs_has_xattr_block(unsigned int ofs) return ofs == XATTR_NODE_OFFSET; } -static inline bool __allow_reserved_blocks(struct f2fs_sb_info *sbi, +static inline bool __allow_reserved_root(struct f2fs_sb_info *sbi, struct inode *inode, bool cap) { if (!inode) @@ -2425,7 +2427,7 @@ static inline unsigned int get_available_block_count(struct f2fs_sb_info *sbi, avail_user_block_count = sbi->user_block_count - sbi->current_reserved_blocks; - if (test_opt(sbi, RESERVE_ROOT) && !__allow_reserved_blocks(sbi, inode, cap)) + if (test_opt(sbi, RESERVE_ROOT) && !__allow_reserved_root(sbi, inode, cap)) avail_user_block_count -= F2FS_OPTION(sbi).root_reserved_blocks; if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) { @@ -2783,7 +2785,7 @@ static inline int inc_valid_node_count(struct f2fs_sb_info *sbi, struct inode *inode, bool is_inode) { block_t valid_block_count; - unsigned int valid_node_count; + unsigned int valid_node_count, avail_user_node_count; unsigned int avail_user_block_count; int err; @@ -2805,15 +2807,20 @@ static inline int inc_valid_node_count(struct f2fs_sb_info *sbi, spin_lock(&sbi->stat_lock); valid_block_count = sbi->total_valid_block_count + 1; - avail_user_block_count = get_available_block_count(sbi, inode, false); + avail_user_block_count = get_available_block_count(sbi, inode, + test_opt(sbi, RESERVE_NODE)); if (unlikely(valid_block_count > avail_user_block_count)) { spin_unlock(&sbi->stat_lock); goto enospc; } + avail_user_node_count = sbi->total_node_count - F2FS_RESERVED_NODE_NUM; + if (test_opt(sbi, RESERVE_NODE) && + !__allow_reserved_root(sbi, inode, true)) + avail_user_node_count -= F2FS_OPTION(sbi).root_reserved_nodes; valid_node_count = sbi->total_valid_node_count + 1; - if (unlikely(valid_node_count > sbi->total_node_count)) { + if (unlikely(valid_node_count > avail_user_node_count)) { spin_unlock(&sbi->stat_lock); goto enospc; } diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 2000880b7dca..5aa9d650512d 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -143,6 +143,7 @@ enum { Opt_extent_cache, Opt_data_flush, Opt_reserve_root, + Opt_reserve_node, Opt_resgid, Opt_resuid, Opt_mode, @@ -273,6 +274,7 @@ static const struct fs_parameter_spec f2fs_param_specs[] = { fsparam_flag_no("extent_cache", Opt_extent_cache), fsparam_flag("data_flush", Opt_data_flush), fsparam_u32("reserve_root", Opt_reserve_root), + fsparam_u32("reserve_node", Opt_reserve_node), fsparam_gid("resgid", Opt_resgid), fsparam_uid("resuid", Opt_resuid), fsparam_enum("mode", Opt_mode, f2fs_param_mode), @@ -346,6 +348,7 @@ static match_table_t f2fs_checkpoint_tokens = { #define F2FS_SPEC_memory_mode (1 << 22) #define F2FS_SPEC_errors (1 << 23) #define F2FS_SPEC_lookup_mode (1 << 24) +#define F2FS_SPEC_reserve_node (1 << 25) struct f2fs_fs_context { struct f2fs_mount_info info; @@ -447,22 +450,30 @@ static void f2fs_destroy_casefold_cache(void) { } static inline void limit_reserve_root(struct f2fs_sb_info *sbi) { - block_t limit = min((sbi->user_block_count >> 3), + block_t block_limit = min((sbi->user_block_count >> 3), sbi->user_block_count - sbi->reserved_blocks); + block_t node_limit = sbi->total_node_count >> 3; /* limit is 12.5% */ if (test_opt(sbi, RESERVE_ROOT) && - F2FS_OPTION(sbi).root_reserved_blocks > limit) { - F2FS_OPTION(sbi).root_reserved_blocks = limit; + F2FS_OPTION(sbi).root_reserved_blocks > block_limit) { + F2FS_OPTION(sbi).root_reserved_blocks = block_limit; f2fs_info(sbi, "Reduce reserved blocks for root = %u", F2FS_OPTION(sbi).root_reserved_blocks); } - if (!test_opt(sbi, RESERVE_ROOT) && + if (test_opt(sbi, RESERVE_NODE) && + F2FS_OPTION(sbi).root_reserved_nodes > node_limit) { + F2FS_OPTION(sbi).root_reserved_nodes = node_limit; + f2fs_info(sbi, "Reduce reserved nodes for root = %u", + F2FS_OPTION(sbi).root_reserved_nodes); + } + if (!test_opt(sbi, RESERVE_ROOT) && !test_opt(sbi, RESERVE_NODE) && (!uid_eq(F2FS_OPTION(sbi).s_resuid, make_kuid(&init_user_ns, F2FS_DEF_RESUID)) || !gid_eq(F2FS_OPTION(sbi).s_resgid, make_kgid(&init_user_ns, F2FS_DEF_RESGID)))) - f2fs_info(sbi, "Ignore s_resuid=%u, s_resgid=%u w/o reserve_root", + f2fs_info(sbi, "Ignore s_resuid=%u, s_resgid=%u w/o reserve_root" + " and reserve_node", from_kuid_munged(&init_user_ns, F2FS_OPTION(sbi).s_resuid), from_kgid_munged(&init_user_ns, @@ -851,6 +862,11 @@ static int f2fs_parse_param(struct fs_context *fc, struct fs_parameter *param) F2FS_CTX_INFO(ctx).root_reserved_blocks = result.uint_32; ctx->spec_mask |= F2FS_SPEC_reserve_root; break; + case Opt_reserve_node: + ctx_set_opt(ctx, F2FS_MOUNT_RESERVE_NODE); + F2FS_CTX_INFO(ctx).root_reserved_nodes = result.uint_32; + ctx->spec_mask |= F2FS_SPEC_reserve_node; + break; case Opt_resuid: F2FS_CTX_INFO(ctx).s_resuid = result.uid; ctx->spec_mask |= F2FS_SPEC_resuid; @@ -1442,6 +1458,14 @@ static int f2fs_check_opt_consistency(struct fs_context *fc, ctx_clear_opt(ctx, F2FS_MOUNT_RESERVE_ROOT); ctx->opt_mask &= ~F2FS_MOUNT_RESERVE_ROOT; } + if (test_opt(sbi, RESERVE_NODE) && + (ctx->opt_mask & F2FS_MOUNT_RESERVE_NODE) && + ctx_test_opt(ctx, F2FS_MOUNT_RESERVE_NODE)) { + f2fs_info(sbi, "Preserve previous reserve_node=%u", + F2FS_OPTION(sbi).root_reserved_nodes); + ctx_clear_opt(ctx, F2FS_MOUNT_RESERVE_NODE); + ctx->opt_mask &= ~F2FS_MOUNT_RESERVE_NODE; + } err = f2fs_check_test_dummy_encryption(fc, sb); if (err) @@ -1641,6 +1665,9 @@ static void f2fs_apply_options(struct fs_context *fc, struct super_block *sb) if (ctx->spec_mask & F2FS_SPEC_reserve_root) F2FS_OPTION(sbi).root_reserved_blocks = F2FS_CTX_INFO(ctx).root_reserved_blocks; + if (ctx->spec_mask & F2FS_SPEC_reserve_node) + F2FS_OPTION(sbi).root_reserved_nodes = + F2FS_CTX_INFO(ctx).root_reserved_nodes; if (ctx->spec_mask & F2FS_SPEC_resgid) F2FS_OPTION(sbi).s_resgid = F2FS_CTX_INFO(ctx).s_resgid; if (ctx->spec_mask & F2FS_SPEC_resuid) @@ -2363,9 +2390,11 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) else if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_BLK) seq_puts(seq, "fragment:block"); seq_printf(seq, ",active_logs=%u", F2FS_OPTION(sbi).active_logs); - if (test_opt(sbi, RESERVE_ROOT)) - seq_printf(seq, ",reserve_root=%u,resuid=%u,resgid=%u", + if (test_opt(sbi, RESERVE_ROOT) || test_opt(sbi, RESERVE_NODE)) + seq_printf(seq, ",reserve_root=%u,reserve_node=%u,resuid=%u," + "resgid=%u", F2FS_OPTION(sbi).root_reserved_blocks, + F2FS_OPTION(sbi).root_reserved_nodes, from_kuid_munged(&init_user_ns, F2FS_OPTION(sbi).s_resuid), from_kgid_munged(&init_user_ns, From 248a99832499036b330d471336b8765ef0e14cb4 Mon Sep 17 00:00:00 2001 From: Soham Metha Date: Wed, 13 Aug 2025 01:45:15 +0530 Subject: [PATCH 01605/11391] docs: f2fs: fixed spelling mistakes in documentation found/fixed the following typos - deivces -> devices - substracting -> subtracting in `Documentation/ABI/testing/sysfs-fs-f2fs` Signed-off-by: Soham Metha Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- Documentation/ABI/testing/sysfs-fs-f2fs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs index 66ee15681983..ee3acc8c2cb8 100644 --- a/Documentation/ABI/testing/sysfs-fs-f2fs +++ b/Documentation/ABI/testing/sysfs-fs-f2fs @@ -822,8 +822,8 @@ What: /sys/fs/f2fs//gc_valid_thresh_ratio Date: September 2024 Contact: "Daeho Jeong" Description: It controls the valid block ratio threshold not to trigger excessive GC - for zoned deivces. The initial value of it is 95(%). F2FS will stop the - background GC thread from intiating GC for sections having valid blocks + for zoned devices. The initial value of it is 95(%). F2FS will stop the + background GC thread from initiating GC for sections having valid blocks exceeding the ratio. What: /sys/fs/f2fs//max_read_extent_count @@ -847,7 +847,7 @@ Description: For several zoned storage devices, vendors will provide extra space filesystem level GC. To do that, we can reserve the space using reserved_blocks. However, it is not enough, since this extra space should not be shown to users. So, with this new sysfs node, we can hide the space - by substracting reserved_blocks from total bytes. + by subtracting reserved_blocks from total bytes. What: /sys/fs/f2fs//encoding_flags Date: April 2025 From 4978f0a5ee239e66b2633725ecc81d3b43c2a7a5 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Mon, 11 Aug 2025 19:41:23 +0800 Subject: [PATCH 01606/11391] f2fs: clean up w/ get_left_section_blocks() Introduce get_left_section_blocks() for cleanup, no logic changes. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.h | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index 5e2ee5c686b1..1ce2c8abaf48 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -600,6 +600,16 @@ static inline int reserved_sections(struct f2fs_sb_info *sbi) return GET_SEC_FROM_SEG(sbi, reserved_segments(sbi)); } +static inline unsigned int get_left_section_blocks(struct f2fs_sb_info *sbi, + enum log_type type, unsigned int segno) +{ + if (f2fs_lfs_mode(sbi) && __is_large_section(sbi)) + return CAP_BLKS_PER_SEC(sbi) - SEGS_TO_BLKS(sbi, + (segno - GET_START_SEG_FROM_SEC(sbi, segno))) - + CURSEG_I(sbi, type)->next_blkoff; + return CAP_BLKS_PER_SEC(sbi) - get_ckpt_valid_blocks(sbi, segno, true); +} + static inline bool has_curseg_enough_space(struct f2fs_sb_info *sbi, unsigned int node_blocks, unsigned int data_blocks, unsigned int dent_blocks) @@ -614,14 +624,7 @@ static inline bool has_curseg_enough_space(struct f2fs_sb_info *sbi, if (unlikely(segno == NULL_SEGNO)) return false; - if (f2fs_lfs_mode(sbi) && __is_large_section(sbi)) { - left_blocks = CAP_BLKS_PER_SEC(sbi) - - SEGS_TO_BLKS(sbi, (segno - GET_START_SEG_FROM_SEC(sbi, segno))) - - CURSEG_I(sbi, i)->next_blkoff; - } else { - left_blocks = CAP_BLKS_PER_SEC(sbi) - - get_ckpt_valid_blocks(sbi, segno, true); - } + left_blocks = get_left_section_blocks(sbi, i, segno); blocks = i <= CURSEG_COLD_DATA ? data_blocks : node_blocks; if (blocks > left_blocks) @@ -634,14 +637,7 @@ static inline bool has_curseg_enough_space(struct f2fs_sb_info *sbi, if (unlikely(segno == NULL_SEGNO)) return false; - if (f2fs_lfs_mode(sbi) && __is_large_section(sbi)) { - left_blocks = CAP_BLKS_PER_SEC(sbi) - - SEGS_TO_BLKS(sbi, (segno - GET_START_SEG_FROM_SEC(sbi, segno))) - - CURSEG_I(sbi, CURSEG_HOT_DATA)->next_blkoff; - } else { - left_blocks = CAP_BLKS_PER_SEC(sbi) - - get_ckpt_valid_blocks(sbi, segno, true); - } + left_blocks = get_left_section_blocks(sbi, CURSEG_HOT_DATA, segno); if (dent_blocks > left_blocks) return false; From 930a9a6ee8e7ffa20af4bffbfc2bbd21d83bf81c Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Mon, 18 Aug 2025 10:09:38 +0800 Subject: [PATCH 01607/11391] f2fs: fix to avoid NULL pointer dereference in f2fs_check_quota_consistency() syzbot reported a f2fs bug as below: Oops: gen[ 107.736417][ T5848] Oops: general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] SMP KASAN PTI KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] CPU: 1 UID: 0 PID: 5848 Comm: syz-executor263 Tainted: G W 6.17.0-rc1-syzkaller-00014-g0e39a731820a #0 PREEMPT_{RT,(full)} RIP: 0010:strcmp+0x3c/0xc0 lib/string.c:284 Call Trace: f2fs_check_quota_consistency fs/f2fs/super.c:1188 [inline] f2fs_check_opt_consistency+0x1378/0x2c10 fs/f2fs/super.c:1436 __f2fs_remount fs/f2fs/super.c:2653 [inline] f2fs_reconfigure+0x482/0x1770 fs/f2fs/super.c:5297 reconfigure_super+0x224/0x890 fs/super.c:1077 do_remount fs/namespace.c:3314 [inline] path_mount+0xd18/0xfe0 fs/namespace.c:4112 do_mount fs/namespace.c:4133 [inline] __do_sys_mount fs/namespace.c:4344 [inline] __se_sys_mount+0x317/0x410 fs/namespace.c:4321 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xfa/0x3b0 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f The direct reason is f2fs_check_quota_consistency() may suffer null-ptr-deref issue in strcmp(). The bug can be reproduced w/ below scripts: mkfs.f2fs -f /dev/vdb mount -t f2fs -o usrquota /dev/vdb /mnt/f2fs quotacheck -uc /mnt/f2fs/ umount /mnt/f2fs mount -t f2fs -o usrjquota=aquota.user,jqfmt=vfsold /dev/vdb /mnt/f2fs mount -t f2fs -o remount,usrjquota=,jqfmt=vfsold /dev/vdb /mnt/f2fs umount /mnt/f2fs So, before old_qname and new_qname comparison, we need to check whether they are all valid pointers, fix it. Reported-by: syzbot+d371efea57d5aeab877b@syzkaller.appspotmail.com Fixes: d18535132523 ("f2fs: separate the options parsing and options checking") Closes: https://lore.kernel.org/linux-f2fs-devel/689ff889.050a0220.e29e5.0037.GAE@google.com Cc: Hongbo Li Signed-off-by: Chao Yu Reviewed-by: Hongbo Li Signed-off-by: Jaegeuk Kim --- fs/f2fs/super.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 5aa9d650512d..465604fdc5dd 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1219,7 +1219,8 @@ static int f2fs_check_quota_consistency(struct fs_context *fc, goto err_jquota_change; if (old_qname) { - if (strcmp(old_qname, new_qname) == 0) { + if (new_qname && + strcmp(old_qname, new_qname) == 0) { ctx->qname_mask &= ~(1 << i); continue; } From ff11d8701b77e303593fd86cf9ef74ef3ac4048e Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Mon, 18 Aug 2025 10:09:39 +0800 Subject: [PATCH 01608/11391] f2fs: fix to allow removing qf_name The mount behavior changed after commit d18535132523 ("f2fs: separate the options parsing and options checking"), let's fix it. [Scripts] mkfs.f2fs -f /dev/vdb mount -t f2fs -o usrquota /dev/vdb /mnt/f2fs quotacheck -uc /mnt/f2fs umount /mnt/f2fs mount -t f2fs -o usrjquota=aquota.user,jqfmt=vfsold /dev/vdb /mnt/f2fs mount|grep f2fs mount -t f2fs -o remount,usrjquota=,jqfmt=vfsold /dev/vdb /mnt/f2fs mount|grep f2fs dmesg [Before commit] mount#1: ...,quota,jqfmt=vfsold,usrjquota=aquota.user,... mount#2: ...,quota,jqfmt=vfsold,... kmsg: no output [After commit] mount#1: ...,quota,jqfmt=vfsold,usrjquota=aquota.user,... mount#2: ...,quota,jqfmt=vfsold,usrjquota=aquota.user,... kmsg: "user quota file already specified" [After patch] mount#1: ...,quota,jqfmt=vfsold,usrjquota=aquota.user,... mount#2: ...,quota,jqfmt=vfsold,... kmsg: "remove qf_name aquota.user" Fixes: d18535132523 ("f2fs: separate the options parsing and options checking") Cc: Hongbo Li Signed-off-by: Chao Yu Reviewed-by: Hongbo Li Signed-off-by: Jaegeuk Kim --- fs/f2fs/super.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 465604fdc5dd..07f6c8cac07a 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1219,8 +1219,11 @@ static int f2fs_check_quota_consistency(struct fs_context *fc, goto err_jquota_change; if (old_qname) { - if (new_qname && - strcmp(old_qname, new_qname) == 0) { + if (!new_qname) { + f2fs_info(sbi, "remove qf_name %s", + old_qname); + continue; + } else if (strcmp(old_qname, new_qname) == 0) { ctx->qname_mask &= ~(1 << i); continue; } From f1a49c1b112b899643b01a5b86cf642a09a01cb6 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Mon, 11 Aug 2025 23:50:25 +0000 Subject: [PATCH 01609/11391] f2fs: show the list of donation files This patch introduces a proc entry to show the currently enrolled donation files. - "File path" indicates a file. - "Status" a. "Donated" means the file is registed in the donation list by fadvise(offset, length, POSIX_FADV_NOREUSE) b. "Evicted" means the donated pages were reclaimed. - "Offset (kb)" and "Length (kb) show the registered donation range. - "Cached pages (kb)" shows the amount of cached pages in the inode page cache. For example, # of files : 2 File path Status Donation offset (kb) Donation size (kb) File cached size (kb) --- /local/test2 Donated 0 1048576 2097152 /local/test Evicted 0 1048576 1048576 Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/sysfs.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c index 1ffaf9e74ce9..86ebe97c256d 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c @@ -1769,6 +1769,68 @@ static int __maybe_unused disk_map_seq_show(struct seq_file *seq, return 0; } +static int __maybe_unused donation_list_seq_show(struct seq_file *seq, + void *offset) +{ + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct inode *inode; + struct f2fs_inode_info *fi; + struct dentry *dentry; + char *buf, *path; + int i; + + buf = f2fs_getname(sbi); + if (!buf) + return 0; + + seq_printf(seq, "Donation List\n"); + seq_printf(seq, " # of files : %u\n", sbi->donate_files); + seq_printf(seq, " %-50s %10s %20s %20s %22s\n", + "File path", "Status", "Donation offset (kb)", + "Donation size (kb)", "File cached size (kb)"); + seq_printf(seq, "---\n"); + + for (i = 0; i < sbi->donate_files; i++) { + spin_lock(&sbi->inode_lock[DONATE_INODE]); + if (list_empty(&sbi->inode_list[DONATE_INODE])) { + spin_unlock(&sbi->inode_lock[DONATE_INODE]); + break; + } + fi = list_first_entry(&sbi->inode_list[DONATE_INODE], + struct f2fs_inode_info, gdonate_list); + list_move_tail(&fi->gdonate_list, &sbi->inode_list[DONATE_INODE]); + inode = igrab(&fi->vfs_inode); + spin_unlock(&sbi->inode_lock[DONATE_INODE]); + + if (!inode) + continue; + + inode_lock_shared(inode); + + dentry = d_find_alias(inode); + if (!dentry) { + path = NULL; + } else { + path = dentry_path_raw(dentry, buf, PATH_MAX); + if (IS_ERR(path)) + goto next; + } + seq_printf(seq, " %-50s %10s %20llu %20llu %22llu\n", + path ? path : "", + is_inode_flag_set(inode, FI_DONATE_FINISHED) ? + "Evicted" : "Donated", + (loff_t)fi->donate_start << (PAGE_SHIFT - 10), + (loff_t)(fi->donate_end + 1) << (PAGE_SHIFT - 10), + (loff_t)inode->i_mapping->nrpages << (PAGE_SHIFT - 10)); +next: + inode_unlock_shared(inode); + iput(inode); + } + f2fs_putname(buf); + return 0; +} + #ifdef CONFIG_F2FS_FAULT_INJECTION static int __maybe_unused inject_stats_seq_show(struct seq_file *seq, void *offset) @@ -1878,6 +1940,8 @@ int f2fs_register_sysfs(struct f2fs_sb_info *sbi) discard_plist_seq_show, sb); proc_create_single_data("disk_map", 0444, sbi->s_proc, disk_map_seq_show, sb); + proc_create_single_data("donation_list", 0444, sbi->s_proc, + donation_list_seq_show, sb); #ifdef CONFIG_F2FS_FAULT_INJECTION proc_create_single_data("inject_stats", 0444, sbi->s_proc, inject_stats_seq_show, sb); From a35da57357221a989e59ced9407ba4f2d4d6d2d2 Mon Sep 17 00:00:00 2001 From: Uros Bizjak Date: Tue, 19 Aug 2025 10:57:49 +0200 Subject: [PATCH 01610/11391] 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 01611/11391] 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 01612/11391] 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 01613/11391] 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 01614/11391] 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 01615/11391] 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 01616/11391] 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 78e097fbca719ce3dbca8f81a6c339a8e0e41d1c Mon Sep 17 00:00:00 2001 From: Cryolitia PukNgae Date: Wed, 20 Aug 2025 17:22:42 +0800 Subject: [PATCH 01617/11391] libbpf: Add documentation to version and error API functions Add documentation for the following API functions: - libbpf_major_version() - libbpf_minor_version() - libbpf_version_string() - libbpf_strerror() Signed-off-by: Cryolitia PukNgae Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20250820-libbpf-doc-1-v1-1-13841f25a134@uniontech.com --- tools/lib/bpf/libbpf.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 2b86e21190d3..2e91148d9b44 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -24,8 +24,25 @@ extern "C" { #endif +/** + * @brief **libbpf_major_version()** provides the major version of libbpf. + * @return An integer, the major version number + */ LIBBPF_API __u32 libbpf_major_version(void); + +/** + * @brief **libbpf_minor_version()** provides the minor version of libbpf. + * @return An integer, the minor version number + */ LIBBPF_API __u32 libbpf_minor_version(void); + +/** + * @brief **libbpf_version_string()** provides the version of libbpf in a + * human-readable form, e.g., "v1.7". + * @return Pointer to a static string containing the version + * + * The format is *not* a part of a stable API and may change in the future. + */ LIBBPF_API const char *libbpf_version_string(void); enum libbpf_errno { @@ -49,6 +66,14 @@ enum libbpf_errno { __LIBBPF_ERRNO__END, }; +/** + * @brief **libbpf_strerror()** converts the provided error code into a + * human-readable string. + * @param err The error code to convert + * @param buf Pointer to a buffer where the error message will be stored + * @param size The number of bytes in the buffer + * @return 0, on success; negative error code, otherwise + */ LIBBPF_API int libbpf_strerror(int err, char *buf, size_t size); /** 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 01618/11391] 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 01619/11391] 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 01620/11391] 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 1400227773201918f270dda48f20afcd613d9bc3 Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Tue, 19 Aug 2025 13:05:44 +1000 Subject: [PATCH 01621/11391] gen_init_cpio: write to fd instead of stdout stream In preparation for more efficient archiving using copy_file_range(), switch from writing archive data to stdout to using STDOUT_FILENO and I/O via write(), dprintf(), etc. Basic I/O error handling is added to cover cases such as ENOSPC. Partial writes are treated as errors. Signed-off-by: David Disseldorp Reviewed-by: Nicolas Schier Link: https://lore.kernel.org/r/20250819032607.28727-2-ddiss@suse.de Signed-off-by: Nathan Chancellor --- usr/gen_init_cpio.c | 139 ++++++++++++++++++++++++++------------------ 1 file changed, 81 insertions(+), 58 deletions(-) diff --git a/usr/gen_init_cpio.c b/usr/gen_init_cpio.c index edcdb8abfa31..235bfc574e6b 100644 --- a/usr/gen_init_cpio.c +++ b/usr/gen_init_cpio.c @@ -23,64 +23,71 @@ #define xstr(s) #s #define str(s) xstr(s) #define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define CPIO_HDR_LEN 110 +#define padlen(_off, _align) (((_align) - ((_off) & ((_align) - 1))) % (_align)) +static char padding[512]; static unsigned int offset; static unsigned int ino = 721; static time_t default_mtime; static bool do_file_mtime; static bool do_csum = false; +static int outfd = STDOUT_FILENO; struct file_handler { const char *type; int (*handler)(const char *line); }; -static void push_string(const char *name) +static int push_string(const char *name) { unsigned int name_len = strlen(name) + 1; + ssize_t len; + + len = write(outfd, name, name_len); + if (len != name_len) + return -1; - fputs(name, stdout); - putchar(0); offset += name_len; + return 0; } -static void push_pad (void) +static int push_pad(size_t padlen) { - while (offset & 3) { - putchar(0); - offset++; - } + ssize_t len = 0; + + if (!padlen) + return 0; + + if (padlen < sizeof(padding)) + len = write(outfd, padding, padlen); + if (len != padlen) + return -1; + + offset += padlen; + return 0; } -static void push_rest(const char *name) +static int push_rest(const char *name) { unsigned int name_len = strlen(name) + 1; - unsigned int tmp_ofs; + ssize_t len; + + len = write(outfd, name, name_len); + if (len != name_len) + return -1; - fputs(name, stdout); - putchar(0); offset += name_len; - tmp_ofs = name_len + 110; - while (tmp_ofs & 3) { - putchar(0); - offset++; - tmp_ofs++; - } + return push_pad(padlen(name_len + CPIO_HDR_LEN, 4)); } -static void push_hdr(const char *s) +static int cpio_trailer(void) { - fputs(s, stdout); - offset += 110; -} - -static void cpio_trailer(void) -{ - char s[256]; const char name[] = "TRAILER!!!"; + int len; - sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX" + len = dprintf(outfd, "%s%08X%08X%08lX%08lX%08X%08lX" "%08X%08X%08X%08X%08X%08X%08X", do_csum ? "070702" : "070701", /* magic */ 0, /* ino */ @@ -96,23 +103,24 @@ static void cpio_trailer(void) 0, /* rminor */ (unsigned)strlen(name)+1, /* namesize */ 0); /* chksum */ - push_hdr(s); - push_rest(name); + offset += len; - while (offset % 512) { - putchar(0); - offset++; - } + if (len != CPIO_HDR_LEN || + push_rest(name) < 0 || + push_pad(padlen(offset, 512)) < 0) + return -1; + + return 0; } static int cpio_mkslink(const char *name, const char *target, unsigned int mode, uid_t uid, gid_t gid) { - char s[256]; + int len; if (name[0] == '/') name++; - sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" + len = dprintf(outfd, "%s%08X%08X%08lX%08lX%08X%08lX" "%08X%08X%08X%08X%08X%08X%08X", do_csum ? "070702" : "070701", /* magic */ ino++, /* ino */ @@ -128,12 +136,17 @@ static int cpio_mkslink(const char *name, const char *target, 0, /* rminor */ (unsigned)strlen(name) + 1,/* namesize */ 0); /* chksum */ - push_hdr(s); - push_string(name); - push_pad(); - push_string(target); - push_pad(); + offset += len; + + if (len != CPIO_HDR_LEN || + push_string(name) < 0 || + push_pad(padlen(offset, 4)) < 0 || + push_string(target) < 0 || + push_pad(padlen(offset, 4)) < 0) + return -1; + return 0; + } static int cpio_mkslink_line(const char *line) @@ -157,11 +170,11 @@ static int cpio_mkslink_line(const char *line) static int cpio_mkgeneric(const char *name, unsigned int mode, uid_t uid, gid_t gid) { - char s[256]; + int len; if (name[0] == '/') name++; - sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" + len = dprintf(outfd, "%s%08X%08X%08lX%08lX%08X%08lX" "%08X%08X%08X%08X%08X%08X%08X", do_csum ? "070702" : "070701", /* magic */ ino++, /* ino */ @@ -177,8 +190,12 @@ static int cpio_mkgeneric(const char *name, unsigned int mode, 0, /* rminor */ (unsigned)strlen(name) + 1,/* namesize */ 0); /* chksum */ - push_hdr(s); - push_rest(name); + offset += len; + + if (len != CPIO_HDR_LEN || + push_rest(name) < 0) + return -1; + return 0; } @@ -246,7 +263,7 @@ static int cpio_mknod(const char *name, unsigned int mode, uid_t uid, gid_t gid, char dev_type, unsigned int maj, unsigned int min) { - char s[256]; + int len; if (dev_type == 'b') mode |= S_IFBLK; @@ -255,7 +272,7 @@ static int cpio_mknod(const char *name, unsigned int mode, if (name[0] == '/') name++; - sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" + len = dprintf(outfd, "%s%08X%08X%08lX%08lX%08X%08lX" "%08X%08X%08X%08X%08X%08X%08X", do_csum ? "070702" : "070701", /* magic */ ino++, /* ino */ @@ -271,8 +288,12 @@ static int cpio_mknod(const char *name, unsigned int mode, min, /* rminor */ (unsigned)strlen(name) + 1,/* namesize */ 0); /* chksum */ - push_hdr(s); - push_rest(name); + offset += len; + + if (len != CPIO_HDR_LEN || + push_rest(name) < 0) + return -1; + return 0; } @@ -324,11 +345,9 @@ static int cpio_mkfile(const char *name, const char *location, unsigned int mode, uid_t uid, gid_t gid, unsigned int nlinks) { - char s[256]; struct stat buf; unsigned long size; - int file; - int retval; + int file, retval, len; int rc = -1; time_t mtime; int namesize; @@ -386,7 +405,7 @@ static int cpio_mkfile(const char *name, const char *location, if (name[0] == '/') name++; namesize = strlen(name) + 1; - sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" + len = dprintf(outfd, "%s%08X%08X%08lX%08lX%08X%08lX" "%08lX%08X%08X%08X%08X%08X%08X", do_csum ? "070702" : "070701", /* magic */ ino, /* ino */ @@ -402,9 +421,12 @@ static int cpio_mkfile(const char *name, const char *location, 0, /* rminor */ namesize, /* namesize */ size ? csum : 0); /* chksum */ - push_hdr(s); - push_string(name); - push_pad(); + offset += len; + + if (len != CPIO_HDR_LEN || + push_string(name) < 0 || + push_pad(padlen(offset, 4)) < 0) + goto error; while (size) { unsigned char filebuf[65536]; @@ -417,14 +439,15 @@ static int cpio_mkfile(const char *name, const char *location, goto error; } - if (fwrite(filebuf, this_read, 1, stdout) != 1) { + if (write(outfd, filebuf, this_read) != this_read) { fprintf(stderr, "writing filebuf failed\n"); goto error; } offset += this_read; size -= this_read; } - push_pad(); + if (push_pad(padlen(offset, 4)) < 0) + goto error; name += namesize; } @@ -691,7 +714,7 @@ int main (int argc, char *argv[]) } } if (ec == 0) - cpio_trailer(); + ec = cpio_trailer(); exit(ec); } From ae18b94099b04264b32e33b057114024bc72c993 Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Tue, 19 Aug 2025 13:05:45 +1000 Subject: [PATCH 01622/11391] gen_init_cpio: support -o parameter This is another preparatory change to allow for reflink-optimized cpio archives with file data written / cloned via copy_file_range(). The output file is truncated prior to write, so that it maps to usr/gen_initramfs.sh usage. It may make sense to offer an append option in future, for easier archive concatenation. Signed-off-by: David Disseldorp Reviewed-by: Nicolas Schier Link: https://lore.kernel.org/r/20250819032607.28727-3-ddiss@suse.de Signed-off-by: Nathan Chancellor --- usr/gen_init_cpio.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/usr/gen_init_cpio.c b/usr/gen_init_cpio.c index 235bfc574e6b..ea4b9b5fed01 100644 --- a/usr/gen_init_cpio.c +++ b/usr/gen_init_cpio.c @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 +#define _GNU_SOURCE #include #include #include @@ -110,7 +111,7 @@ static int cpio_trailer(void) push_pad(padlen(offset, 512)) < 0) return -1; - return 0; + return fsync(outfd); } static int cpio_mkslink(const char *name, const char *target, @@ -532,7 +533,7 @@ static int cpio_mkfile_line(const char *line) static void usage(const char *prog) { fprintf(stderr, "Usage:\n" - "\t%s [-t ] [-c] \n" + "\t%s [-t ] [-c] [-o ] \n" "\n" " is a file containing newline separated entries that\n" "describe the files to be included in the initramfs archive:\n" @@ -569,7 +570,8 @@ static void usage(const char *prog) "as mtime for symlinks, directories, regular and special files.\n" "The default is to use the current time for all files, but\n" "preserve modification time for regular files.\n" - "-c: calculate and store 32-bit checksums for file data.\n", + "-c: calculate and store 32-bit checksums for file data.\n" + ": write cpio to this file instead of stdout\n", prog); } @@ -611,7 +613,7 @@ int main (int argc, char *argv[]) default_mtime = time(NULL); while (1) { - int opt = getopt(argc, argv, "t:ch"); + int opt = getopt(argc, argv, "t:cho:"); char *invalid; if (opt == -1) @@ -630,6 +632,16 @@ int main (int argc, char *argv[]) case 'c': do_csum = true; break; + case 'o': + outfd = open(optarg, + O_WRONLY | O_CREAT | O_LARGEFILE | O_TRUNC, + 0600); + if (outfd < 0) { + fprintf(stderr, "failed to open %s\n", optarg); + usage(argv[0]); + exit(1); + } + break; case 'h': case '?': usage(argv[0]); From 97169cd6d95b338f2dbf5d3154b7d2233fce7d8a Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Tue, 19 Aug 2025 13:05:46 +1000 Subject: [PATCH 01623/11391] gen_init_cpio: attempt copy_file_range for file data The copy_file_range syscall can improve copy performance by cloning extents between cpio archive source and destination files. Existing read / write based copy logic is retained for fallback in case the copy_file_range syscall is unsupported or unavailable due to cross-filesystem EXDEV, etc. Clone or reflink, as opposed to copy, of source file extents into the output cpio archive may (e.g. on Btrfs and XFS) require alignment of the output to the filesystem block size. This could be achieved by inserting padding entries into the cpio archive manifest. Signed-off-by: David Disseldorp Reviewed-by: Nicolas Schier Link: https://lore.kernel.org/r/20250819032607.28727-4-ddiss@suse.de Signed-off-by: Nathan Chancellor --- usr/gen_init_cpio.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/usr/gen_init_cpio.c b/usr/gen_init_cpio.c index ea4b9b5fed01..aa73afd3756c 100644 --- a/usr/gen_init_cpio.c +++ b/usr/gen_init_cpio.c @@ -354,6 +354,7 @@ static int cpio_mkfile(const char *name, const char *location, int namesize; unsigned int i; uint32_t csum = 0; + ssize_t this_read; mode |= S_IFREG; @@ -429,9 +430,19 @@ static int cpio_mkfile(const char *name, const char *location, push_pad(padlen(offset, 4)) < 0) goto error; + if (size) { + this_read = copy_file_range(file, NULL, outfd, NULL, size, 0); + if (this_read > 0) { + if (this_read > size) + goto error; + offset += this_read; + size -= this_read; + } + /* short or failed copy falls back to read/write... */ + } + while (size) { unsigned char filebuf[65536]; - ssize_t this_read; size_t this_size = MIN(size, sizeof(filebuf)); this_read = read(file, filebuf, this_size); From 348ff9e3c1cf1a4124be1c94937dfc131bf6be29 Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Tue, 19 Aug 2025 13:05:47 +1000 Subject: [PATCH 01624/11391] gen_init_cpio: avoid duplicate strlen calls We determine the filename length for the cpio header, so shouldn't recalculate it when writing out the filename. Signed-off-by: David Disseldorp Reviewed-by: Nicolas Schier Link: https://lore.kernel.org/r/20250819032607.28727-5-ddiss@suse.de Signed-off-by: Nathan Chancellor --- usr/gen_init_cpio.c | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/usr/gen_init_cpio.c b/usr/gen_init_cpio.c index aa73afd3756c..729585342e16 100644 --- a/usr/gen_init_cpio.c +++ b/usr/gen_init_cpio.c @@ -25,6 +25,7 @@ #define str(s) xstr(s) #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define CPIO_HDR_LEN 110 +#define CPIO_TRAILER "TRAILER!!!" #define padlen(_off, _align) (((_align) - ((_off) & ((_align) - 1))) % (_align)) static char padding[512]; @@ -40,9 +41,8 @@ struct file_handler { int (*handler)(const char *line); }; -static int push_string(const char *name) +static int push_buf(const char *name, size_t name_len) { - unsigned int name_len = strlen(name) + 1; ssize_t len; len = write(outfd, name, name_len); @@ -69,9 +69,8 @@ static int push_pad(size_t padlen) return 0; } -static int push_rest(const char *name) +static int push_rest(const char *name, size_t name_len) { - unsigned int name_len = strlen(name) + 1; ssize_t len; len = write(outfd, name, name_len); @@ -85,8 +84,8 @@ static int push_rest(const char *name) static int cpio_trailer(void) { - const char name[] = "TRAILER!!!"; int len; + unsigned int namesize = sizeof(CPIO_TRAILER); len = dprintf(outfd, "%s%08X%08X%08lX%08lX%08X%08lX" "%08X%08X%08X%08X%08X%08X%08X", @@ -102,12 +101,12 @@ static int cpio_trailer(void) 0, /* minor */ 0, /* rmajor */ 0, /* rminor */ - (unsigned)strlen(name)+1, /* namesize */ + namesize, /* namesize */ 0); /* chksum */ offset += len; if (len != CPIO_HDR_LEN || - push_rest(name) < 0 || + push_rest(CPIO_TRAILER, namesize) < 0 || push_pad(padlen(offset, 512)) < 0) return -1; @@ -118,9 +117,12 @@ static int cpio_mkslink(const char *name, const char *target, unsigned int mode, uid_t uid, gid_t gid) { int len; + unsigned int namesize, targetsize = strlen(target) + 1; if (name[0] == '/') name++; + namesize = strlen(name) + 1; + len = dprintf(outfd, "%s%08X%08X%08lX%08lX%08X%08lX" "%08X%08X%08X%08X%08X%08X%08X", do_csum ? "070702" : "070701", /* magic */ @@ -130,19 +132,19 @@ static int cpio_mkslink(const char *name, const char *target, (long) gid, /* gid */ 1, /* nlink */ (long) default_mtime, /* mtime */ - (unsigned)strlen(target)+1, /* filesize */ + targetsize, /* filesize */ 3, /* major */ 1, /* minor */ 0, /* rmajor */ 0, /* rminor */ - (unsigned)strlen(name) + 1,/* namesize */ + namesize, /* namesize */ 0); /* chksum */ offset += len; if (len != CPIO_HDR_LEN || - push_string(name) < 0 || + push_buf(name, namesize) < 0 || push_pad(padlen(offset, 4)) < 0 || - push_string(target) < 0 || + push_buf(target, targetsize) < 0 || push_pad(padlen(offset, 4)) < 0) return -1; @@ -172,9 +174,12 @@ static int cpio_mkgeneric(const char *name, unsigned int mode, uid_t uid, gid_t gid) { int len; + unsigned int namesize; if (name[0] == '/') name++; + namesize = strlen(name) + 1; + len = dprintf(outfd, "%s%08X%08X%08lX%08lX%08X%08lX" "%08X%08X%08X%08X%08X%08X%08X", do_csum ? "070702" : "070701", /* magic */ @@ -189,12 +194,12 @@ static int cpio_mkgeneric(const char *name, unsigned int mode, 1, /* minor */ 0, /* rmajor */ 0, /* rminor */ - (unsigned)strlen(name) + 1,/* namesize */ + namesize, /* namesize */ 0); /* chksum */ offset += len; if (len != CPIO_HDR_LEN || - push_rest(name) < 0) + push_rest(name, namesize) < 0) return -1; return 0; @@ -265,6 +270,7 @@ static int cpio_mknod(const char *name, unsigned int mode, unsigned int maj, unsigned int min) { int len; + unsigned int namesize; if (dev_type == 'b') mode |= S_IFBLK; @@ -273,6 +279,8 @@ static int cpio_mknod(const char *name, unsigned int mode, if (name[0] == '/') name++; + namesize = strlen(name) + 1; + len = dprintf(outfd, "%s%08X%08X%08lX%08lX%08X%08lX" "%08X%08X%08X%08X%08X%08X%08X", do_csum ? "070702" : "070701", /* magic */ @@ -287,12 +295,12 @@ static int cpio_mknod(const char *name, unsigned int mode, 1, /* minor */ maj, /* rmajor */ min, /* rminor */ - (unsigned)strlen(name) + 1,/* namesize */ + namesize, /* namesize */ 0); /* chksum */ offset += len; if (len != CPIO_HDR_LEN || - push_rest(name) < 0) + push_rest(name, namesize) < 0) return -1; return 0; @@ -426,7 +434,7 @@ static int cpio_mkfile(const char *name, const char *location, offset += len; if (len != CPIO_HDR_LEN || - push_string(name) < 0 || + push_buf(name, namesize) < 0 || push_pad(padlen(offset, 4)) < 0) goto error; From 9135564db4904e82a3207bd2d134ca64ce618047 Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Tue, 19 Aug 2025 13:05:48 +1000 Subject: [PATCH 01625/11391] gen_initramfs.sh: use gen_init_cpio -o parameter gen_init_cpio can now write to a file directly, so use it when gen_initramfs.sh is called with -o (e.g. usr/Makefile invocation). Signed-off-by: David Disseldorp Reviewed-by: Nicolas Schier Link: https://lore.kernel.org/r/20250819032607.28727-6-ddiss@suse.de Signed-off-by: Nathan Chancellor --- usr/gen_initramfs.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/usr/gen_initramfs.sh b/usr/gen_initramfs.sh index 14b5782f961a..7eba2fddf0ef 100755 --- a/usr/gen_initramfs.sh +++ b/usr/gen_initramfs.sh @@ -193,7 +193,8 @@ root_gid=0 dep_list= timestamp= cpio_list=$(mktemp ${TMPDIR:-/tmp}/cpiolist.XXXXXX) -output="/dev/stdout" +# gen_init_cpio writes to stdout by default +output="" trap "rm -f $cpio_list" EXIT @@ -207,7 +208,7 @@ while [ $# -gt 0 ]; do shift ;; "-o") # generate cpio image named $1 - output="$1" + output="-o $1" shift ;; "-u") # map $1 to uid=0 (root) @@ -246,4 +247,4 @@ done # If output_file is set we will generate cpio archive # we are careful to delete tmp files -usr/gen_init_cpio $timestamp $cpio_list > $output +usr/gen_init_cpio $output $timestamp $cpio_list From 7c1f14f6e8e7f288350faec02b3fbc25971da289 Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Tue, 19 Aug 2025 13:05:49 +1000 Subject: [PATCH 01626/11391] docs: initramfs: file data alignment via name padding The existing cpio extraction logic reads (maximum PATH_MAX) name_len bytes from the archive into the collected name buffer and ensures that the trailing byte is a null-terminator. This allows the actual file name to be shorter than name_len, with the name string simply zero-terminated prior to the last byte. Initramfs generators, such as dracut-cpio[1], can take advantage of name zero-padding to align file data segments within the archive to filesystem block boundaries. Block boundary alignment may allow the copy_file_range syscall to reflink archive source and destination extents. Link: https://github.com/dracutdevs/dracut/commit/300e4b116c624bca1b9e7251708b1ae656fe9157 [1] Signed-off-by: David Disseldorp Reviewed-by: Nicolas Schier Link: https://lore.kernel.org/r/20250819032607.28727-7-ddiss@suse.de Signed-off-by: Nathan Chancellor --- Documentation/driver-api/early-userspace/buffer-format.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/driver-api/early-userspace/buffer-format.rst b/Documentation/driver-api/early-userspace/buffer-format.rst index 726bfa2fe70d..4597a91100b7 100644 --- a/Documentation/driver-api/early-userspace/buffer-format.rst +++ b/Documentation/driver-api/early-userspace/buffer-format.rst @@ -86,6 +86,11 @@ c_mtime is ignored unless CONFIG_INITRAMFS_PRESERVE_MTIME=y is set. The c_filesize should be zero for any file which is not a regular file or symlink. +c_namesize may account for more than one trailing '\0', as long as the +value doesn't exceed PATH_MAX. This can be useful for ensuring that a +subsequent file data segment is aligned, e.g. to a filesystem block +boundary. + The c_chksum field contains a simple 32-bit unsigned sum of all the bytes in the data field. cpio(1) refers to this as "crc", which is clearly incorrect (a cyclic redundancy check is a different and From 5467e85508fd106443311eb7973ef588b4ef8bb6 Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Tue, 19 Aug 2025 13:05:50 +1000 Subject: [PATCH 01627/11391] gen_init_cpio: add -a as reflink optimization As described in buffer-format.rst, the existing initramfs.c extraction logic works fine if the cpio filename field is padded out with trailing zeros, with a caveat that the padded namesize can't exceed PATH_MAX. Add filename zero-padding logic to gen_init_cpio, which can be triggered via the new -a parameter. Performance and storage utilization is improved for Btrfs and XFS workloads, as copy_file_range can reflink the entire source file into a filesystem block-size aligned destination offset within the cpio archive. Btrfs benchmarks run on 6.15.8-1-default (Tumbleweed) x86_64 host: > truncate --size=2G /tmp/backing.img > /sbin/mkfs.btrfs /tmp/backing.img ... Sector size: 4096 (CPU page size: 4096) ... > sudo mount /tmp/backing.img mnt > sudo chown $USER mnt > cd mnt mnt> dd if=/dev/urandom of=foo bs=1M count=20 && cat foo >/dev/null ... mnt> echo "file /foo foo 0755 0 0" > list mnt> perf stat -r 10 gen_init_cpio -o unaligned_btrfs list ... 0.023496 +- 0.000472 seconds time elapsed ( +- 2.01% ) mnt> perf stat -r 10 gen_init_cpio -o aligned_btrfs -a 4096 list ... 0.0010010 +- 0.0000565 seconds time elapsed ( +- 5.65% ) mnt> /sbin/xfs_io -c "fiemap -v" unaligned_btrfs unaligned_btrfs: EXT: FILE-OFFSET BLOCK-RANGE TOTAL FLAGS 0: [0..40967]: 695040..736007 40968 0x1 mnt> /sbin/xfs_io -c "fiemap -v" aligned_btrfs aligned_btrfs: EXT: FILE-OFFSET BLOCK-RANGE TOTAL FLAGS 0: [0..7]: 26768..26775 8 0x0 1: [8..40967]: 269056..310015 40960 0x2000 2: [40968..40975]: 26776..26783 8 0x1 mnt> /sbin/btrfs fi du unaligned_btrfs aligned_btrfs Total Exclusive Set shared Filename 20.00MiB 20.00MiB 0.00B unaligned_btrfs 20.01MiB 8.00KiB 20.00MiB aligned_btrfs XFS benchmarks run on same host: > sudo umount mnt && rm /tmp/backing.img > truncate --size=2G /tmp/backing.img > /sbin/mkfs.xfs /tmp/backing.img ... = reflink=1 ... data = bsize=4096 blocks=524288, imaxpct=25 ... > sudo mount /tmp/backing.img mnt > sudo chown $USER mnt > cd mnt mnt> dd if=/dev/urandom of=foo bs=1M count=20 && cat foo >/dev/null ... mnt> echo "file /foo foo 0755 0 0" > list mnt> perf stat -r 10 gen_init_cpio -o unaligned_xfs list ... 0.011069 +- 0.000469 seconds time elapsed ( +- 4.24% ) mnt> perf stat -r 10 gen_init_cpio -o aligned_xfs -a 4096 list ... 0.001273 +- 0.000288 seconds time elapsed ( +- 22.60% ) mnt> /sbin/xfs_io -c "fiemap -v" unaligned_xfs unaligned_xfs: EXT: FILE-OFFSET BLOCK-RANGE TOTAL FLAGS 0: [0..40967]: 106176..147143 40968 0x0 1: [40968..65023]: 147144..171199 24056 0x801 mnt> /sbin/xfs_io -c "fiemap -v" aligned_xfs aligned_xfs: EXT: FILE-OFFSET BLOCK-RANGE TOTAL FLAGS 0: [0..7]: 120..127 8 0x0 1: [8..40967]: 192..41151 40960 0x2000 2: [40968..40975]: 236728..236735 8 0x0 3: [40976..106495]: 236736..302255 65520 0x801 The alignment is best-effort; a stderr message is printed if alignment can't be achieved due to PATH_MAX overrun, with fallback to non-padded filename. This allows it to still be useful for opportunistic alignment, e.g. on aarch64 Btrfs with 64K block-size. Alignment failure messages provide an indicator that reordering of the cpio-manifest may be beneficial. Archive read performance for reflinked initramfs images may suffer due to the effects of fragmentation, particularly on spinning disks. To mitigate excessive fragmentation, files with lengths less than data_align aren't padded. Signed-off-by: David Disseldorp Reviewed-by: Nicolas Schier Link: https://lore.kernel.org/r/20250819032607.28727-8-ddiss@suse.de Signed-off-by: Nathan Chancellor --- usr/gen_init_cpio.c | 49 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/usr/gen_init_cpio.c b/usr/gen_init_cpio.c index 729585342e16..75e9561ba313 100644 --- a/usr/gen_init_cpio.c +++ b/usr/gen_init_cpio.c @@ -28,13 +28,15 @@ #define CPIO_TRAILER "TRAILER!!!" #define padlen(_off, _align) (((_align) - ((_off) & ((_align) - 1))) % (_align)) -static char padding[512]; +/* zero-padding the filename field for data alignment is limited by PATH_MAX */ +static char padding[PATH_MAX]; static unsigned int offset; static unsigned int ino = 721; static time_t default_mtime; static bool do_file_mtime; static bool do_csum = false; static int outfd = STDOUT_FILENO; +static unsigned int dalign; struct file_handler { const char *type; @@ -359,7 +361,7 @@ static int cpio_mkfile(const char *name, const char *location, int file, retval, len; int rc = -1; time_t mtime; - int namesize; + int namesize, namepadlen; unsigned int i; uint32_t csum = 0; ssize_t this_read; @@ -407,14 +409,27 @@ static int cpio_mkfile(const char *name, const char *location, } size = 0; + namepadlen = 0; for (i = 1; i <= nlinks; i++) { - /* data goes on last link */ - if (i == nlinks) - size = buf.st_size; - if (name[0] == '/') name++; namesize = strlen(name) + 1; + + /* data goes on last link, after any alignment padding */ + if (i == nlinks) + size = buf.st_size; + + if (dalign && size > dalign) { + namepadlen = padlen(offset + CPIO_HDR_LEN + namesize, + dalign); + if (namesize + namepadlen > PATH_MAX) { + fprintf(stderr, + "%s: best-effort alignment %u missed\n", + name, dalign); + namepadlen = 0; + } + } + len = dprintf(outfd, "%s%08X%08X%08lX%08lX%08X%08lX" "%08lX%08X%08X%08X%08X%08X%08X", do_csum ? "070702" : "070701", /* magic */ @@ -429,13 +444,13 @@ static int cpio_mkfile(const char *name, const char *location, 1, /* minor */ 0, /* rmajor */ 0, /* rminor */ - namesize, /* namesize */ + namesize + namepadlen, /* namesize */ size ? csum : 0); /* chksum */ offset += len; if (len != CPIO_HDR_LEN || push_buf(name, namesize) < 0 || - push_pad(padlen(offset, 4)) < 0) + push_pad(namepadlen ? namepadlen : padlen(offset, 4)) < 0) goto error; if (size) { @@ -552,7 +567,7 @@ static int cpio_mkfile_line(const char *line) static void usage(const char *prog) { fprintf(stderr, "Usage:\n" - "\t%s [-t ] [-c] [-o ] \n" + "\t%s [-t ] [-c] [-o ] [-a ] \n" "\n" " is a file containing newline separated entries that\n" "describe the files to be included in the initramfs archive:\n" @@ -590,7 +605,10 @@ static void usage(const char *prog) "The default is to use the current time for all files, but\n" "preserve modification time for regular files.\n" "-c: calculate and store 32-bit checksums for file data.\n" - ": write cpio to this file instead of stdout\n", + ": write cpio to this file instead of stdout\n" + ": attempt to align file data by zero-padding the\n" + "filename field up to data_align. Must be a multiple of 4.\n" + "Alignment is best-effort; PATH_MAX limits filename padding.\n", prog); } @@ -632,7 +650,7 @@ int main (int argc, char *argv[]) default_mtime = time(NULL); while (1) { - int opt = getopt(argc, argv, "t:cho:"); + int opt = getopt(argc, argv, "t:cho:a:"); char *invalid; if (opt == -1) @@ -661,6 +679,15 @@ int main (int argc, char *argv[]) exit(1); } break; + case 'a': + dalign = strtoul(optarg, &invalid, 10); + if (!*optarg || *invalid || (dalign & 3)) { + fprintf(stderr, "Invalid data_align: %s\n", + optarg); + usage(argv[0]); + exit(1); + } + break; case 'h': case '?': usage(argv[0]); From 8f2c72f2252cf228879de0224d5055470fc20c06 Mon Sep 17 00:00:00 2001 From: Pengtao He Date: Tue, 19 Aug 2025 10:15:51 +0800 Subject: [PATCH 01628/11391] net: avoid one loop iteration in __skb_splice_bits If *len is equal to 0 at the beginning of __splice_segment it returns true directly. But when decreasing *len from a positive number to 0 in __splice_segment, it returns false. The __skb_splice_bits needs to call __splice_segment again. Recheck *len if it changes, return true in time. Reduce unnecessary calls to __splice_segment. Signed-off-by: Pengtao He Reviewed-by: Willem de Bruijn Link: https://patch.msgid.link/20250819021551.8361-1-hept.hept.hept@gmail.com Signed-off-by: Jakub Kicinski --- net/core/skbuff.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index ee0274417948..23b776cd9879 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -3112,7 +3112,9 @@ static bool __splice_segment(struct page *page, unsigned int poff, poff += flen; plen -= flen; *len -= flen; - } while (*len && plen); + if (!*len) + return true; + } while (plen); return false; } From 6b4b1d577e1fe8a4e436a250e098b5c247d978d9 Mon Sep 17 00:00:00 2001 From: Alex Tran Date: Mon, 18 Aug 2025 19:52:27 -0700 Subject: [PATCH 01629/11391] selftests/net/socket.c: removed warnings from unused returns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit socket.c: In function ‘run_tests’: socket.c:59:25: warning: ignoring return value of ‘strerror_r’ \ declared with attribute ‘warn_unused_result’ [-Wunused-result] 59 | strerror_r(-s->expect, err_string1, ERR_STRING_SZ); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ socket.c:60:25: warning: ignoring return value of ‘strerror_r’ \ declared with attribute ‘warn_unused_result’ [-Wunused-result] 60 | strerror_r(errno, err_string2, ERR_STRING_SZ); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ socket.c:73:33: warning: ignoring return value of ‘strerror_r’ \ declared with attribute ‘warn_unused_result’ [-Wunused-result] 73 | strerror_r(errno, err_string1, ERR_STRING_SZ); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ changelog: v2 - const char* messages and fixed patch warnings of max 75 chars per line Signed-off-by: Alex Tran Link: https://patch.msgid.link/20250819025227.239885-1-alex.t.tran@gmail.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/socket.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/net/socket.c b/tools/testing/selftests/net/socket.c index db1aeb8c5d1e..be1080003c61 100644 --- a/tools/testing/selftests/net/socket.c +++ b/tools/testing/selftests/net/socket.c @@ -39,6 +39,7 @@ static int run_tests(void) { char err_string1[ERR_STRING_SZ]; char err_string2[ERR_STRING_SZ]; + const char *msg1, *msg2; int i, err; err = 0; @@ -56,13 +57,13 @@ static int run_tests(void) errno == -s->expect) continue; - strerror_r(-s->expect, err_string1, ERR_STRING_SZ); - strerror_r(errno, err_string2, ERR_STRING_SZ); + msg1 = strerror_r(-s->expect, err_string1, ERR_STRING_SZ); + msg2 = strerror_r(errno, err_string2, ERR_STRING_SZ); fprintf(stderr, "socket(%d, %d, %d) expected " "err (%s) got (%s)\n", s->domain, s->type, s->protocol, - err_string1, err_string2); + msg1, msg2); err = -1; break; @@ -70,12 +71,12 @@ static int run_tests(void) close(fd); if (s->expect < 0) { - strerror_r(errno, err_string1, ERR_STRING_SZ); + msg1 = strerror_r(errno, err_string1, ERR_STRING_SZ); fprintf(stderr, "socket(%d, %d, %d) expected " "success got err (%s)\n", s->domain, s->type, s->protocol, - err_string1); + msg1); err = -1; break; From eacb6e408dc861fb93baf10d6837204a3b39e915 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Tue, 19 Aug 2025 07:33:48 +0000 Subject: [PATCH 01630/11391] selftests: net: bpf_offload: print loaded programs on mismatch The test sometimes fails due to an unexpected number of loaded programs. e.g FAIL: 2 BPF programs loaded, expected 1 File "/usr/libexec/kselftests/net/./bpf_offload.py", line 940, in progs = bpftool_prog_list(expected=1) File "/usr/libexec/kselftests/net/./bpf_offload.py", line 187, in bpftool_prog_list fail(True, "%d BPF programs loaded, expected %d" % File "/usr/libexec/kselftests/net/./bpf_offload.py", line 89, in fail tb = "".join(traceback.extract_stack().format()) However, the logs do not show which programs were actually loaded, making it difficult to debug the failure. Add printing of the loaded programs when a mismatch is detected to help troubleshoot such errors. The list is printed on a new line to avoid breaking the current log format. Signed-off-by: Hangbin Liu Link: https://patch.msgid.link/20250819073348.387972-1-liuhangbin@gmail.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/bpf_offload.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/net/bpf_offload.py b/tools/testing/selftests/net/bpf_offload.py index b2c271b79240..c856d266c8f3 100755 --- a/tools/testing/selftests/net/bpf_offload.py +++ b/tools/testing/selftests/net/bpf_offload.py @@ -184,8 +184,8 @@ def bpftool_prog_list(expected=None, ns="", exclude_orphaned=True): progs = [ p for p in progs if not p['orphaned'] ] if expected is not None: if len(progs) != expected: - fail(True, "%d BPF programs loaded, expected %d" % - (len(progs), expected)) + fail(True, "%d BPF programs loaded, expected %d\nLoaded Progs:\n%s" % + (len(progs), expected, pp.pformat(progs))) return progs def bpftool_map_list(expected=None, ns=""): From 781bf2cc0616d44cc4a63bab3664a54b221bdc14 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Tue, 19 Aug 2025 07:47:49 +0000 Subject: [PATCH 01631/11391] selftests: rtnetlink: print device info on preferred_lft test failure Even with slowwait used to avoid system sleep in the preferred_lft test, failures can still occur after long runtimes. Print the device address info when the test fails to provide better troubleshooting data. Signed-off-by: Hangbin Liu Link: https://patch.msgid.link/20250819074749.388064-1-liuhangbin@gmail.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/rtnetlink.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/testing/selftests/net/rtnetlink.sh b/tools/testing/selftests/net/rtnetlink.sh index d6c00efeb664..91b0f6cae04d 100755 --- a/tools/testing/selftests/net/rtnetlink.sh +++ b/tools/testing/selftests/net/rtnetlink.sh @@ -313,6 +313,8 @@ kci_test_addrlft() slowwait 5 check_addr_not_exist "$devdummy" "10.23.11." if [ $? -eq 1 ]; then + # troubleshoot the reason for our failure + run_cmd ip addr show dev "$devdummy" check_err 1 end_test "FAIL: preferred_lft addresses remaining" return From 5f8a4f34f6dcf4b64c3cbcfd4aa5a8d7dbcd268d Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 19 Aug 2025 09:39:15 -0700 Subject: [PATCH 01632/11391] bnxt_en: hsi: Update FW interface to 1.10.3.133 The major change is struct pcie_ctx_hw_stats_v2 which has new latency histograms added. Signed-off-by: Michael Chan Link: https://patch.msgid.link/20250819163919.104075-2-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- include/linux/bnxt/hsi.h | 315 +++++++++++++++++++++++++++++++-------- 1 file changed, 253 insertions(+), 62 deletions(-) diff --git a/include/linux/bnxt/hsi.h b/include/linux/bnxt/hsi.h index 549231703bce..8c5dac3b3ef3 100644 --- a/include/linux/bnxt/hsi.h +++ b/include/linux/bnxt/hsi.h @@ -276,6 +276,10 @@ struct cmd_nums { #define HWRM_REG_POWER_QUERY 0xe1UL #define HWRM_CORE_FREQUENCY_QUERY 0xe2UL #define HWRM_REG_POWER_HISTOGRAM 0xe3UL + #define HWRM_MONITOR_PAX_HISTOGRAM_START 0xe4UL + #define HWRM_MONITOR_PAX_HISTOGRAM_COLLECT 0xe5UL + #define HWRM_STAT_QUERY_ROCE_STATS 0xe6UL + #define HWRM_STAT_QUERY_ROCE_STATS_EXT 0xe7UL #define HWRM_WOL_FILTER_ALLOC 0xf0UL #define HWRM_WOL_FILTER_FREE 0xf1UL #define HWRM_WOL_FILTER_QCFG 0xf2UL @@ -407,9 +411,8 @@ struct cmd_nums { #define HWRM_FUNC_LAG_UPDATE 0x1b1UL #define HWRM_FUNC_LAG_FREE 0x1b2UL #define HWRM_FUNC_LAG_QCFG 0x1b3UL - #define HWRM_FUNC_TIMEDTX_PACING_RATE_ADD 0x1c2UL - #define HWRM_FUNC_TIMEDTX_PACING_RATE_DELETE 0x1c3UL - #define HWRM_FUNC_TIMEDTX_PACING_RATE_QUERY 0x1c4UL + #define HWRM_FUNC_TTX_PACING_RATE_PROF_QUERY 0x1c3UL + #define HWRM_FUNC_TTX_PACING_RATE_QUERY 0x1c4UL #define HWRM_SELFTEST_QLIST 0x200UL #define HWRM_SELFTEST_EXEC 0x201UL #define HWRM_SELFTEST_IRQ 0x202UL @@ -441,6 +444,7 @@ struct cmd_nums { #define HWRM_MFG_WRITE_CERT_NVM 0x21cUL #define HWRM_PORT_POE_CFG 0x230UL #define HWRM_PORT_POE_QCFG 0x231UL + #define HWRM_PORT_PHY_FDRSTAT 0x232UL #define HWRM_UDCC_QCAPS 0x258UL #define HWRM_UDCC_CFG 0x259UL #define HWRM_UDCC_QCFG 0x25aUL @@ -453,6 +457,8 @@ struct cmd_nums { #define HWRM_QUEUE_PFCWD_TIMEOUT_QCAPS 0x261UL #define HWRM_QUEUE_PFCWD_TIMEOUT_CFG 0x262UL #define HWRM_QUEUE_PFCWD_TIMEOUT_QCFG 0x263UL + #define HWRM_QUEUE_ADPTV_QOS_RX_QCFG 0x264UL + #define HWRM_QUEUE_ADPTV_QOS_TX_QCFG 0x265UL #define HWRM_TF 0x2bcUL #define HWRM_TF_VERSION_GET 0x2bdUL #define HWRM_TF_SESSION_OPEN 0x2c6UL @@ -551,6 +557,8 @@ struct cmd_nums { #define HWRM_DBG_COREDUMP_CAPTURE 0xff2cUL #define HWRM_DBG_PTRACE 0xff2dUL #define HWRM_DBG_SIM_CABLE_STATE 0xff2eUL + #define HWRM_DBG_TOKEN_QUERY_AUTH_IDS 0xff2fUL + #define HWRM_DBG_TOKEN_CFG 0xff30UL #define HWRM_NVM_GET_VPD_FIELD_INFO 0xffeaUL #define HWRM_NVM_SET_VPD_FIELD_INFO 0xffebUL #define HWRM_NVM_DEFRAG 0xffecUL @@ -632,8 +640,8 @@ struct hwrm_err_output { #define HWRM_VERSION_MAJOR 1 #define HWRM_VERSION_MINOR 10 #define HWRM_VERSION_UPDATE 3 -#define HWRM_VERSION_RSVD 97 -#define HWRM_VERSION_STR "1.10.3.97" +#define HWRM_VERSION_RSVD 133 +#define HWRM_VERSION_STR "1.10.3.133" /* hwrm_ver_get_input (size:192b/24B) */ struct hwrm_ver_get_input { @@ -688,6 +696,7 @@ struct hwrm_ver_get_output { #define VER_GET_RESP_DEV_CAPS_CFG_CFA_TRUFLOW_SUPPORTED 0x4000UL #define VER_GET_RESP_DEV_CAPS_CFG_SECURE_BOOT_CAPABLE 0x8000UL #define VER_GET_RESP_DEV_CAPS_CFG_SECURE_SOC_CAPABLE 0x10000UL + #define VER_GET_RESP_DEV_CAPS_CFG_DEBUG_TOKEN_SUPPORTED 0x20000UL u8 roce_fw_maj_8b; u8 roce_fw_min_8b; u8 roce_fw_bld_8b; @@ -872,7 +881,8 @@ struct hwrm_async_event_cmpl { #define ASYNC_EVENT_CMPL_EVENT_ID_REPRESENTOR_PAIR_CHANGE 0x4eUL #define ASYNC_EVENT_CMPL_EVENT_ID_VF_STAT_CHANGE 0x4fUL #define ASYNC_EVENT_CMPL_EVENT_ID_HOST_COREDUMP 0x50UL - #define ASYNC_EVENT_CMPL_EVENT_ID_MAX_RGTR_EVENT_ID 0x51UL + #define ASYNC_EVENT_CMPL_EVENT_ID_ADPTV_QOS 0x51UL + #define ASYNC_EVENT_CMPL_EVENT_ID_MAX_RGTR_EVENT_ID 0x52UL #define ASYNC_EVENT_CMPL_EVENT_ID_FW_TRACE_MSG 0xfeUL #define ASYNC_EVENT_CMPL_EVENT_ID_HWRM_ERROR 0xffUL #define ASYNC_EVENT_CMPL_EVENT_ID_LAST ASYNC_EVENT_CMPL_EVENT_ID_HWRM_ERROR @@ -1344,7 +1354,8 @@ struct hwrm_async_event_cmpl_dbg_buf_producer { #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_CA2_TRACE 0x9UL #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_RIGP1_TRACE 0xaUL #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_AFM_KONG_HWRM_TRACE 0xbUL - #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_LAST ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_AFM_KONG_HWRM_TRACE + #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_ERR_QPC_TRACE 0xcUL + #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_LAST ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_ERR_QPC_TRACE }; /* hwrm_async_event_cmpl_hwrm_error (size:128b/16B) */ @@ -1401,7 +1412,11 @@ struct hwrm_async_event_cmpl_error_report_base { #define ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_DOORBELL_DROP_THRESHOLD 0x4UL #define ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_THERMAL_THRESHOLD 0x5UL #define ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_DUAL_DATA_RATE_NOT_SUPPORTED 0x6UL - #define ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_LAST ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_DUAL_DATA_RATE_NOT_SUPPORTED + #define ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_DUP_UDCC_SES 0x7UL + #define ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_DB_DROP 0x8UL + #define ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_MD_TEMP 0x9UL + #define ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_VNIC_ERR 0xaUL + #define ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_LAST ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_VNIC_ERR }; /* hwrm_async_event_cmpl_error_report_pause_storm (size:128b/16B) */ @@ -1914,6 +1929,12 @@ struct hwrm_func_qcaps_output { #define FUNC_QCAPS_RESP_FLAGS_EXT3_RX_RATE_PROFILE_SEL_SUPPORTED 0x8UL #define FUNC_QCAPS_RESP_FLAGS_EXT3_BIDI_OPT_SUPPORTED 0x10UL #define FUNC_QCAPS_RESP_FLAGS_EXT3_MIRROR_ON_ROCE_SUPPORTED 0x20UL + #define FUNC_QCAPS_RESP_FLAGS_EXT3_ROCE_VF_DYN_ALLOC_SUPPORT 0x40UL + #define FUNC_QCAPS_RESP_FLAGS_EXT3_CHANGE_UDP_SRCPORT_SUPPORT 0x80UL + #define FUNC_QCAPS_RESP_FLAGS_EXT3_PCIE_COMPLIANCE_SUPPORTED 0x100UL + #define FUNC_QCAPS_RESP_FLAGS_EXT3_MULTI_L2_DB_SUPPORTED 0x200UL + #define FUNC_QCAPS_RESP_FLAGS_EXT3_PCIE_SECURE_ATS_SUPPORTED 0x400UL + #define FUNC_QCAPS_RESP_FLAGS_EXT3_MBUF_STATS_SUPPORTED 0x800UL __le16 max_roce_vfs; __le16 max_crypto_rx_flow_filters; u8 unused_3[3]; @@ -1931,7 +1952,7 @@ struct hwrm_func_qcfg_input { u8 unused_0[6]; }; -/* hwrm_func_qcfg_output (size:1344b/168B) */ +/* hwrm_func_qcfg_output (size:1408b/176B) */ struct hwrm_func_qcfg_output { __le16 error_code; __le16 req_type; @@ -2124,7 +2145,43 @@ struct hwrm_func_qcfg_output { #define FUNC_QCFG_RESP_XID_PARTITION_CFG_TX_CK 0x1UL #define FUNC_QCFG_RESP_XID_PARTITION_CFG_RX_CK 0x2UL __le16 mirror_vnic_id; - u8 unused_7[7]; + u8 max_link_width; + #define FUNC_QCFG_RESP_MAX_LINK_WIDTH_UNKNOWN 0x0UL + #define FUNC_QCFG_RESP_MAX_LINK_WIDTH_X1 0x1UL + #define FUNC_QCFG_RESP_MAX_LINK_WIDTH_X2 0x2UL + #define FUNC_QCFG_RESP_MAX_LINK_WIDTH_X4 0x4UL + #define FUNC_QCFG_RESP_MAX_LINK_WIDTH_X8 0x8UL + #define FUNC_QCFG_RESP_MAX_LINK_WIDTH_X16 0x10UL + #define FUNC_QCFG_RESP_MAX_LINK_WIDTH_LAST FUNC_QCFG_RESP_MAX_LINK_WIDTH_X16 + u8 max_link_speed; + #define FUNC_QCFG_RESP_MAX_LINK_SPEED_UNKNOWN 0x0UL + #define FUNC_QCFG_RESP_MAX_LINK_SPEED_G1 0x1UL + #define FUNC_QCFG_RESP_MAX_LINK_SPEED_G2 0x2UL + #define FUNC_QCFG_RESP_MAX_LINK_SPEED_G3 0x3UL + #define FUNC_QCFG_RESP_MAX_LINK_SPEED_G4 0x4UL + #define FUNC_QCFG_RESP_MAX_LINK_SPEED_G5 0x5UL + #define FUNC_QCFG_RESP_MAX_LINK_SPEED_LAST FUNC_QCFG_RESP_MAX_LINK_SPEED_G5 + u8 negotiated_link_width; + #define FUNC_QCFG_RESP_NEGOTIATED_LINK_WIDTH_UNKNOWN 0x0UL + #define FUNC_QCFG_RESP_NEGOTIATED_LINK_WIDTH_X1 0x1UL + #define FUNC_QCFG_RESP_NEGOTIATED_LINK_WIDTH_X2 0x2UL + #define FUNC_QCFG_RESP_NEGOTIATED_LINK_WIDTH_X4 0x4UL + #define FUNC_QCFG_RESP_NEGOTIATED_LINK_WIDTH_X8 0x8UL + #define FUNC_QCFG_RESP_NEGOTIATED_LINK_WIDTH_X16 0x10UL + #define FUNC_QCFG_RESP_NEGOTIATED_LINK_WIDTH_LAST FUNC_QCFG_RESP_NEGOTIATED_LINK_WIDTH_X16 + u8 negotiated_link_speed; + #define FUNC_QCFG_RESP_NEGOTIATED_LINK_SPEED_UNKNOWN 0x0UL + #define FUNC_QCFG_RESP_NEGOTIATED_LINK_SPEED_G1 0x1UL + #define FUNC_QCFG_RESP_NEGOTIATED_LINK_SPEED_G2 0x2UL + #define FUNC_QCFG_RESP_NEGOTIATED_LINK_SPEED_G3 0x3UL + #define FUNC_QCFG_RESP_NEGOTIATED_LINK_SPEED_G4 0x4UL + #define FUNC_QCFG_RESP_NEGOTIATED_LINK_SPEED_G5 0x5UL + #define FUNC_QCFG_RESP_NEGOTIATED_LINK_SPEED_LAST FUNC_QCFG_RESP_NEGOTIATED_LINK_SPEED_G5 + u8 unused_7[2]; + u8 pcie_compliance; + u8 unused_8; + __le16 l2_db_multi_page_size_kb; + u8 unused_9[5]; u8 valid; }; @@ -2322,6 +2379,7 @@ struct hwrm_func_cfg_input { #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_GID_PER_VF 0x200UL #define FUNC_CFG_REQ_ENABLES2_XID_PARTITION_CFG 0x400UL #define FUNC_CFG_REQ_ENABLES2_PHYSICAL_SLOT_NUMBER 0x800UL + #define FUNC_CFG_REQ_ENABLES2_PCIE_COMPLIANCE 0x1000UL u8 port_kdnet_mode; #define FUNC_CFG_REQ_PORT_KDNET_MODE_DISABLED 0x0UL #define FUNC_CFG_REQ_PORT_KDNET_MODE_ENABLED 0x1UL @@ -2353,7 +2411,8 @@ struct hwrm_func_cfg_input { __le16 xid_partition_cfg; #define FUNC_CFG_REQ_XID_PARTITION_CFG_TX_CK 0x1UL #define FUNC_CFG_REQ_XID_PARTITION_CFG_RX_CK 0x2UL - __le16 unused_2; + u8 pcie_compliance; + u8 unused_2; }; /* hwrm_func_cfg_output (size:128b/16B) */ @@ -2370,11 +2429,41 @@ struct hwrm_func_cfg_output { struct hwrm_func_cfg_cmd_err { u8 code; #define FUNC_CFG_CMD_ERR_CODE_UNKNOWN 0x0UL - #define FUNC_CFG_CMD_ERR_CODE_PARTITION_MIN_BW_RANGE 0x1UL - #define FUNC_CFG_CMD_ERR_CODE_PARTITION_MIN_MORE_THAN_MAX 0x2UL - #define FUNC_CFG_CMD_ERR_CODE_PARTITION_MIN_BW_UNSUPPORTED 0x3UL - #define FUNC_CFG_CMD_ERR_CODE_PARTITION_BW_PERCENT 0x4UL - #define FUNC_CFG_CMD_ERR_CODE_LAST FUNC_CFG_CMD_ERR_CODE_PARTITION_BW_PERCENT + #define FUNC_CFG_CMD_ERR_CODE_PARTITION_BW_OUT_OF_RANGE 0x1UL + #define FUNC_CFG_CMD_ERR_CODE_NPAR_PARTITION_DOWN_FAILED 0x2UL + #define FUNC_CFG_CMD_ERR_CODE_TPID_SET_DFLT_VLAN_NOT_SET 0x3UL + #define FUNC_CFG_CMD_ERR_CODE_RES_ARRAY_ALLOC_FAILED 0x4UL + #define FUNC_CFG_CMD_ERR_CODE_TX_RING_ASSET_TEST_FAILED 0x5UL + #define FUNC_CFG_CMD_ERR_CODE_TX_RING_RES_UPDATE_FAILED 0x6UL + #define FUNC_CFG_CMD_ERR_CODE_APPLY_MAX_BW_FAILED 0x7UL + #define FUNC_CFG_CMD_ERR_CODE_ENABLE_EVB_FAILED 0x8UL + #define FUNC_CFG_CMD_ERR_CODE_RSS_CTXT_ASSET_TEST_FAILED 0x9UL + #define FUNC_CFG_CMD_ERR_CODE_RSS_CTXT_RES_UPDATE_FAILED 0xaUL + #define FUNC_CFG_CMD_ERR_CODE_CMPL_RING_ASSET_TEST_FAILED 0xbUL + #define FUNC_CFG_CMD_ERR_CODE_CMPL_RING_RES_UPDATE_FAILED 0xcUL + #define FUNC_CFG_CMD_ERR_CODE_NQ_ASSET_TEST_FAILED 0xdUL + #define FUNC_CFG_CMD_ERR_CODE_NQ_RES_UPDATE_FAILED 0xeUL + #define FUNC_CFG_CMD_ERR_CODE_RX_RING_ASSET_TEST_FAILED 0xfUL + #define FUNC_CFG_CMD_ERR_CODE_RX_RING_RES_UPDATE_FAILED 0x10UL + #define FUNC_CFG_CMD_ERR_CODE_VNIC_ASSET_TEST_FAILED 0x11UL + #define FUNC_CFG_CMD_ERR_CODE_VNIC_RES_UPDATE_FAILED 0x12UL + #define FUNC_CFG_CMD_ERR_CODE_FAILED_TO_START_STATS_THREAD 0x13UL + #define FUNC_CFG_CMD_ERR_CODE_RDMA_SRIOV_DISABLED 0x14UL + #define FUNC_CFG_CMD_ERR_CODE_TX_KTLS_DISABLED 0x15UL + #define FUNC_CFG_CMD_ERR_CODE_TX_KTLS_ASSET_TEST_FAILED 0x16UL + #define FUNC_CFG_CMD_ERR_CODE_TX_KTLS_RES_UPDATE_FAILED 0x17UL + #define FUNC_CFG_CMD_ERR_CODE_RX_KTLS_DISABLED 0x18UL + #define FUNC_CFG_CMD_ERR_CODE_RX_KTLS_ASSET_TEST_FAILED 0x19UL + #define FUNC_CFG_CMD_ERR_CODE_RX_KTLS_RES_UPDATE_FAILED 0x1aUL + #define FUNC_CFG_CMD_ERR_CODE_TX_QUIC_DISABLED 0x1bUL + #define FUNC_CFG_CMD_ERR_CODE_TX_QUIC_ASSET_TEST_FAILED 0x1cUL + #define FUNC_CFG_CMD_ERR_CODE_TX_QUIC_RES_UPDATE_FAILED 0x1dUL + #define FUNC_CFG_CMD_ERR_CODE_RX_QUIC_DISABLED 0x1eUL + #define FUNC_CFG_CMD_ERR_CODE_RX_QUIC_ASSET_TEST_FAILED 0x1fUL + #define FUNC_CFG_CMD_ERR_CODE_RX_QUIC_RES_UPDATE_FAILED 0x20UL + #define FUNC_CFG_CMD_ERR_CODE_INVALID_KDNET_MODE 0x21UL + #define FUNC_CFG_CMD_ERR_CODE_SCHQ_CFG_FAIL 0x22UL + #define FUNC_CFG_CMD_ERR_CODE_LAST FUNC_CFG_CMD_ERR_CODE_SCHQ_CFG_FAIL u8 unused_0[7]; }; @@ -3780,6 +3869,7 @@ struct hwrm_func_backing_store_cfg_v2_input { #define FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_CA2_TRACE 0x28UL #define FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_RIGP1_TRACE 0x29UL #define FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_AFM_KONG_HWRM_TRACE 0x2aUL + #define FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_ERR_QPC_TRACE 0x2bUL #define FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_INVALID 0xffffUL #define FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_LAST FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_INVALID __le16 instance; @@ -3865,6 +3955,7 @@ struct hwrm_func_backing_store_qcfg_v2_input { #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_CA2_TRACE 0x28UL #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_RIGP1_TRACE 0x29UL #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_AFM_KONG_HWRM_TRACE 0x2aUL + #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_ERR_QPC_TRACE 0x2bUL #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_INVALID 0xffffUL #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_LAST FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_INVALID __le16 instance; @@ -3904,6 +3995,7 @@ struct hwrm_func_backing_store_qcfg_v2_output { #define FUNC_BACKING_STORE_QCFG_V2_RESP_TYPE_CA1_TRACE 0x27UL #define FUNC_BACKING_STORE_QCFG_V2_RESP_TYPE_CA2_TRACE 0x28UL #define FUNC_BACKING_STORE_QCFG_V2_RESP_TYPE_RIGP1_TRACE 0x29UL + #define FUNC_BACKING_STORE_QCFG_V2_RESP_TYPE_ERR_QPC_TRACE 0x2aUL #define FUNC_BACKING_STORE_QCFG_V2_RESP_TYPE_INVALID 0xffffUL #define FUNC_BACKING_STORE_QCFG_V2_RESP_TYPE_LAST FUNC_BACKING_STORE_QCFG_V2_RESP_TYPE_INVALID __le16 instance; @@ -4027,6 +4119,7 @@ struct hwrm_func_backing_store_qcaps_v2_input { #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_CA2_TRACE 0x28UL #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_RIGP1_TRACE 0x29UL #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_AFM_KONG_HWRM_TRACE 0x2aUL + #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_ERR_QPC_TRACE 0x2bUL #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_INVALID 0xffffUL #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_LAST FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_INVALID u8 rsvd[6]; @@ -4070,6 +4163,7 @@ struct hwrm_func_backing_store_qcaps_v2_output { #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_CA2_TRACE 0x28UL #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_RIGP1_TRACE 0x29UL #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_AFM_KONG_HWRM_TRACE 0x2aUL + #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_ERR_QPC_TRACE 0x2bUL #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_INVALID 0xffffUL #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_LAST FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_INVALID __le16 entry_size; @@ -4216,6 +4310,10 @@ struct hwrm_port_phy_cfg_input { #define PORT_PHY_CFG_REQ_FLAGS_FEC_RS272_1XN_DISABLE 0x100000UL #define PORT_PHY_CFG_REQ_FLAGS_FEC_RS272_IEEE_ENABLE 0x200000UL #define PORT_PHY_CFG_REQ_FLAGS_FEC_RS272_IEEE_DISABLE 0x400000UL + #define PORT_PHY_CFG_REQ_FLAGS_LINK_TRAINING_ENABLE 0x800000UL + #define PORT_PHY_CFG_REQ_FLAGS_LINK_TRAINING_DISABLE 0x1000000UL + #define PORT_PHY_CFG_REQ_FLAGS_PRECODING_ENABLE 0x2000000UL + #define PORT_PHY_CFG_REQ_FLAGS_PRECODING_DISABLE 0x4000000UL __le32 enables; #define PORT_PHY_CFG_REQ_ENABLES_AUTO_MODE 0x1UL #define PORT_PHY_CFG_REQ_ENABLES_AUTO_DUPLEX 0x2UL @@ -4703,6 +4801,8 @@ struct hwrm_port_phy_qcfg_output { #define PORT_PHY_QCFG_RESP_OPTION_FLAGS_MEDIA_AUTO_DETECT 0x1UL #define PORT_PHY_QCFG_RESP_OPTION_FLAGS_SIGNAL_MODE_KNOWN 0x2UL #define PORT_PHY_QCFG_RESP_OPTION_FLAGS_SPEEDS2_SUPPORTED 0x4UL + #define PORT_PHY_QCFG_RESP_OPTION_FLAGS_LINK_TRAINING 0x8UL + #define PORT_PHY_QCFG_RESP_OPTION_FLAGS_PRECODING 0x10UL char phy_vendor_name[16]; char phy_vendor_partnumber[16]; __le16 support_pam4_speeds; @@ -4725,6 +4825,10 @@ struct hwrm_port_phy_qcfg_output { u8 link_down_reason; #define PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_RF 0x1UL #define PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_OTP_SPEED_VIOLATION 0x2UL + #define PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_CABLE_REMOVED 0x4UL + #define PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_MODULE_FAULT 0x8UL + #define PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_BMC_REQUEST 0x10UL + #define PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_TX_LASER_DISABLED 0x20UL __le16 support_speeds2; #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_1GB 0x1UL #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_10GB 0x2UL @@ -5882,9 +5986,10 @@ struct hwrm_port_led_qcaps_output { #define PORT_LED_QCAPS_RESP_LED0_STATE_CAPS_BLINK_SUPPORTED 0x8UL #define PORT_LED_QCAPS_RESP_LED0_STATE_CAPS_BLINK_ALT_SUPPORTED 0x10UL __le16 led0_color_caps; - #define PORT_LED_QCAPS_RESP_LED0_COLOR_CAPS_RSVD 0x1UL - #define PORT_LED_QCAPS_RESP_LED0_COLOR_CAPS_AMBER_SUPPORTED 0x2UL - #define PORT_LED_QCAPS_RESP_LED0_COLOR_CAPS_GREEN_SUPPORTED 0x4UL + #define PORT_LED_QCAPS_RESP_LED0_COLOR_CAPS_RSVD 0x1UL + #define PORT_LED_QCAPS_RESP_LED0_COLOR_CAPS_AMBER_SUPPORTED 0x2UL + #define PORT_LED_QCAPS_RESP_LED0_COLOR_CAPS_GREEN_SUPPORTED 0x4UL + #define PORT_LED_QCAPS_RESP_LED0_COLOR_CAPS_GRNAMB_SUPPORTED 0x8UL u8 led1_id; u8 led1_type; #define PORT_LED_QCAPS_RESP_LED1_TYPE_SPEED 0x0UL @@ -5900,9 +6005,10 @@ struct hwrm_port_led_qcaps_output { #define PORT_LED_QCAPS_RESP_LED1_STATE_CAPS_BLINK_SUPPORTED 0x8UL #define PORT_LED_QCAPS_RESP_LED1_STATE_CAPS_BLINK_ALT_SUPPORTED 0x10UL __le16 led1_color_caps; - #define PORT_LED_QCAPS_RESP_LED1_COLOR_CAPS_RSVD 0x1UL - #define PORT_LED_QCAPS_RESP_LED1_COLOR_CAPS_AMBER_SUPPORTED 0x2UL - #define PORT_LED_QCAPS_RESP_LED1_COLOR_CAPS_GREEN_SUPPORTED 0x4UL + #define PORT_LED_QCAPS_RESP_LED1_COLOR_CAPS_RSVD 0x1UL + #define PORT_LED_QCAPS_RESP_LED1_COLOR_CAPS_AMBER_SUPPORTED 0x2UL + #define PORT_LED_QCAPS_RESP_LED1_COLOR_CAPS_GREEN_SUPPORTED 0x4UL + #define PORT_LED_QCAPS_RESP_LED1_COLOR_CAPS_GRNAMB_SUPPORTED 0x8UL u8 led2_id; u8 led2_type; #define PORT_LED_QCAPS_RESP_LED2_TYPE_SPEED 0x0UL @@ -5918,9 +6024,10 @@ struct hwrm_port_led_qcaps_output { #define PORT_LED_QCAPS_RESP_LED2_STATE_CAPS_BLINK_SUPPORTED 0x8UL #define PORT_LED_QCAPS_RESP_LED2_STATE_CAPS_BLINK_ALT_SUPPORTED 0x10UL __le16 led2_color_caps; - #define PORT_LED_QCAPS_RESP_LED2_COLOR_CAPS_RSVD 0x1UL - #define PORT_LED_QCAPS_RESP_LED2_COLOR_CAPS_AMBER_SUPPORTED 0x2UL - #define PORT_LED_QCAPS_RESP_LED2_COLOR_CAPS_GREEN_SUPPORTED 0x4UL + #define PORT_LED_QCAPS_RESP_LED2_COLOR_CAPS_RSVD 0x1UL + #define PORT_LED_QCAPS_RESP_LED2_COLOR_CAPS_AMBER_SUPPORTED 0x2UL + #define PORT_LED_QCAPS_RESP_LED2_COLOR_CAPS_GREEN_SUPPORTED 0x4UL + #define PORT_LED_QCAPS_RESP_LED2_COLOR_CAPS_GRNAMB_SUPPORTED 0x8UL u8 led3_id; u8 led3_type; #define PORT_LED_QCAPS_RESP_LED3_TYPE_SPEED 0x0UL @@ -5936,9 +6043,10 @@ struct hwrm_port_led_qcaps_output { #define PORT_LED_QCAPS_RESP_LED3_STATE_CAPS_BLINK_SUPPORTED 0x8UL #define PORT_LED_QCAPS_RESP_LED3_STATE_CAPS_BLINK_ALT_SUPPORTED 0x10UL __le16 led3_color_caps; - #define PORT_LED_QCAPS_RESP_LED3_COLOR_CAPS_RSVD 0x1UL - #define PORT_LED_QCAPS_RESP_LED3_COLOR_CAPS_AMBER_SUPPORTED 0x2UL - #define PORT_LED_QCAPS_RESP_LED3_COLOR_CAPS_GREEN_SUPPORTED 0x4UL + #define PORT_LED_QCAPS_RESP_LED3_COLOR_CAPS_RSVD 0x1UL + #define PORT_LED_QCAPS_RESP_LED3_COLOR_CAPS_AMBER_SUPPORTED 0x2UL + #define PORT_LED_QCAPS_RESP_LED3_COLOR_CAPS_GREEN_SUPPORTED 0x4UL + #define PORT_LED_QCAPS_RESP_LED3_COLOR_CAPS_GRNAMB_SUPPORTED 0x8UL u8 unused_4[3]; u8 valid; }; @@ -7036,9 +7144,22 @@ struct hwrm_vnic_rss_cfg_output { /* hwrm_vnic_rss_cfg_cmd_err (size:64b/8B) */ struct hwrm_vnic_rss_cfg_cmd_err { u8 code; - #define VNIC_RSS_CFG_CMD_ERR_CODE_UNKNOWN 0x0UL - #define VNIC_RSS_CFG_CMD_ERR_CODE_INTERFACE_NOT_READY 0x1UL - #define VNIC_RSS_CFG_CMD_ERR_CODE_LAST VNIC_RSS_CFG_CMD_ERR_CODE_INTERFACE_NOT_READY + #define VNIC_RSS_CFG_CMD_ERR_CODE_UNKNOWN 0x0UL + #define VNIC_RSS_CFG_CMD_ERR_CODE_INTERFACE_NOT_READY 0x1UL + #define VNIC_RSS_CFG_CMD_ERR_CODE_UNABLE_TO_GET_RSS_CFG 0x2UL + #define VNIC_RSS_CFG_CMD_ERR_CODE_HASH_TYPE_UNSUPPORTED 0x3UL + #define VNIC_RSS_CFG_CMD_ERR_CODE_HASH_TYPE_ERR 0x4UL + #define VNIC_RSS_CFG_CMD_ERR_CODE_HASH_MODE_FAIL 0x5UL + #define VNIC_RSS_CFG_CMD_ERR_CODE_RING_GRP_TABLE_ALLOC_ERR 0x6UL + #define VNIC_RSS_CFG_CMD_ERR_CODE_HASH_KEY_ALLOC_ERR 0x7UL + #define VNIC_RSS_CFG_CMD_ERR_CODE_DMA_FAILED 0x8UL + #define VNIC_RSS_CFG_CMD_ERR_CODE_RX_RING_ALLOC_ERR 0x9UL + #define VNIC_RSS_CFG_CMD_ERR_CODE_CMPL_RING_ALLOC_ERR 0xaUL + #define VNIC_RSS_CFG_CMD_ERR_CODE_HW_SET_RSS_FAILED 0xbUL + #define VNIC_RSS_CFG_CMD_ERR_CODE_CTX_INVALID 0xcUL + #define VNIC_RSS_CFG_CMD_ERR_CODE_VNIC_INVALID 0xdUL + #define VNIC_RSS_CFG_CMD_ERR_CODE_VNIC_RING_TABLE_PAIR_INVALID 0xeUL + #define VNIC_RSS_CFG_CMD_ERR_CODE_LAST VNIC_RSS_CFG_CMD_ERR_CODE_VNIC_RING_TABLE_PAIR_INVALID u8 unused_0[7]; }; @@ -7177,7 +7298,7 @@ struct hwrm_vnic_rss_cos_lb_ctx_free_output { u8 valid; }; -/* hwrm_ring_alloc_input (size:704b/88B) */ +/* hwrm_ring_alloc_input (size:768b/96B) */ struct hwrm_ring_alloc_input { __le16 req_type; __le16 cmpl_ring; @@ -7195,6 +7316,7 @@ struct hwrm_ring_alloc_input { #define RING_ALLOC_REQ_ENABLES_MPC_CHNLS_TYPE 0x400UL #define RING_ALLOC_REQ_ENABLES_STEERING_TAG_VALID 0x800UL #define RING_ALLOC_REQ_ENABLES_RX_RATE_PROFILE_VALID 0x1000UL + #define RING_ALLOC_REQ_ENABLES_DPI_VALID 0x2000UL u8 ring_type; #define RING_ALLOC_REQ_RING_TYPE_L2_CMPL 0x0UL #define RING_ALLOC_REQ_RING_TYPE_TX 0x1UL @@ -7287,6 +7409,8 @@ struct hwrm_ring_alloc_input { #define RING_ALLOC_REQ_RX_RATE_PROFILE_SEL_LAST RING_ALLOC_REQ_RX_RATE_PROFILE_SEL_POLL_MODE u8 unused_4; __le64 cq_handle; + __le16 dpi; + __le16 unused_5[3]; }; /* hwrm_ring_alloc_output (size:128b/16B) */ @@ -7776,7 +7900,10 @@ struct hwrm_cfa_l2_set_rx_mask_cmd_err { u8 code; #define CFA_L2_SET_RX_MASK_CMD_ERR_CODE_UNKNOWN 0x0UL #define CFA_L2_SET_RX_MASK_CMD_ERR_CODE_NTUPLE_FILTER_CONFLICT_ERR 0x1UL - #define CFA_L2_SET_RX_MASK_CMD_ERR_CODE_LAST CFA_L2_SET_RX_MASK_CMD_ERR_CODE_NTUPLE_FILTER_CONFLICT_ERR + #define CFA_L2_SET_RX_MASK_CMD_ERR_CODE_MAX_VLAN_TAGS 0x2UL + #define CFA_L2_SET_RX_MASK_CMD_ERR_CODE_INVALID_VNIC_ID 0x3UL + #define CFA_L2_SET_RX_MASK_CMD_ERR_CODE_INVALID_ACTION 0x4UL + #define CFA_L2_SET_RX_MASK_CMD_ERR_CODE_LAST CFA_L2_SET_RX_MASK_CMD_ERR_CODE_INVALID_ACTION u8 unused_0[7]; }; @@ -8109,9 +8236,38 @@ struct hwrm_cfa_ntuple_filter_alloc_output { /* hwrm_cfa_ntuple_filter_alloc_cmd_err (size:64b/8B) */ struct hwrm_cfa_ntuple_filter_alloc_cmd_err { u8 code; - #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_UNKNOWN 0x0UL - #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_RX_MASK_VLAN_CONFLICT_ERR 0x1UL - #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_LAST CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_RX_MASK_VLAN_CONFLICT_ERR + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_UNKNOWN 0x0UL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_ZERO_MAC 0x65UL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_BC_MC_MAC 0x66UL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_INVALID_VNIC 0x67UL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_INVALID_PF_FID 0x68UL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_INVALID_L2_CTXT_ID 0x69UL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_NULL_L2_CTXT_CFG 0x6aUL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_NULL_L2_DATA_FLD 0x6bUL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_INVALID_CFA_LAYOUT 0x6cUL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_L2_CTXT_ALLOC_FAIL 0x6dUL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_ROCE_FLOW_ERR 0x6eUL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_INVALID_OWNER_FID 0x6fUL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_ZERO_REF_CNT 0x70UL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_INVALID_FLOW_TYPE 0x71UL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_INVALID_IVLAN 0x72UL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_MAX_VLAN_ID 0x73UL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_INVALID_TNL_REQ 0x74UL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_L2_ADDR 0x75UL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_L2_IVLAN 0x76UL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_L3_ADDR 0x77UL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_L3_ADDR_TYPE 0x78UL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_T_L3_ADDR_TYPE 0x79UL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_DST_VNIC_ID 0x7aUL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_VNI 0x7bUL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_INVALID_DST_ID 0x7cUL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_FAIL_ROCE_L2_FLOW 0x7dUL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_INVALID_NPAR_VLAN 0x7eUL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_ATSP_ADD 0x7fUL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_DFLT_VLAN_FAIL 0x80UL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_INVALID_L3_TYPE 0x81UL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_VAL_FAIL_TNL_FLOW 0x82UL + #define CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_LAST CFA_NTUPLE_FILTER_ALLOC_CMD_ERR_CODE_VAL_FAIL_TNL_FLOW u8 unused_0[7]; }; @@ -9181,7 +9337,7 @@ struct pcie_ctx_hw_stats { __le64 pcie_recovery_histogram; }; -/* pcie_ctx_hw_stats_v2 (size:4096b/512B) */ +/* pcie_ctx_hw_stats_v2 (size:4544b/568B) */ struct pcie_ctx_hw_stats_v2 { __le64 pcie_pl_signal_integrity; __le64 pcie_dl_signal_integrity; @@ -9212,6 +9368,9 @@ struct pcie_ctx_hw_stats_v2 { __le64 pcie_other_packet_count; __le64 pcie_blocked_packet_count; __le64 pcie_cmpl_packet_count; + __le32 pcie_rd_latency_histogram[12]; + __le32 pcie_rd_latency_all_normal_count; + __le32 unused_2; }; /* hwrm_stat_generic_qstats_input (size:256b/32B) */ @@ -9406,7 +9565,8 @@ struct hwrm_struct_hdr { #define STRUCT_HDR_STRUCT_ID_MSIX_PER_VF 0xc8UL #define STRUCT_HDR_STRUCT_ID_UDCC_RTT_BUCKET_COUNT 0x12cUL #define STRUCT_HDR_STRUCT_ID_UDCC_RTT_BUCKET_BOUND 0x12dUL - #define STRUCT_HDR_STRUCT_ID_LAST STRUCT_HDR_STRUCT_ID_UDCC_RTT_BUCKET_BOUND + #define STRUCT_HDR_STRUCT_ID_DBG_TOKEN_CLAIMS 0x190UL + #define STRUCT_HDR_STRUCT_ID_LAST STRUCT_HDR_STRUCT_ID_DBG_TOKEN_CLAIMS __le16 len; u8 version; #define STRUCT_HDR_VERSION_0 0x0UL @@ -9459,11 +9619,13 @@ struct hwrm_fw_set_structured_data_output { /* hwrm_fw_set_structured_data_cmd_err (size:64b/8B) */ struct hwrm_fw_set_structured_data_cmd_err { u8 code; - #define FW_SET_STRUCTURED_DATA_CMD_ERR_CODE_UNKNOWN 0x0UL - #define FW_SET_STRUCTURED_DATA_CMD_ERR_CODE_BAD_HDR_CNT 0x1UL - #define FW_SET_STRUCTURED_DATA_CMD_ERR_CODE_BAD_FMT 0x2UL - #define FW_SET_STRUCTURED_DATA_CMD_ERR_CODE_BAD_ID 0x3UL - #define FW_SET_STRUCTURED_DATA_CMD_ERR_CODE_LAST FW_SET_STRUCTURED_DATA_CMD_ERR_CODE_BAD_ID + #define FW_SET_STRUCTURED_DATA_CMD_ERR_CODE_UNKNOWN 0x0UL + #define FW_SET_STRUCTURED_DATA_CMD_ERR_CODE_BAD_HDR_CNT 0x1UL + #define FW_SET_STRUCTURED_DATA_CMD_ERR_CODE_BAD_FMT 0x2UL + #define FW_SET_STRUCTURED_DATA_CMD_ERR_CODE_BAD_ID 0x3UL + #define FW_SET_STRUCTURED_DATA_CMD_ERR_CODE_ALREADY_ADDED 0x4UL + #define FW_SET_STRUCTURED_DATA_CMD_ERR_CODE_INST_IN_PROG 0x5UL + #define FW_SET_STRUCTURED_DATA_CMD_ERR_CODE_LAST FW_SET_STRUCTURED_DATA_CMD_ERR_CODE_INST_IN_PROG u8 unused_0[7]; }; @@ -9487,7 +9649,9 @@ struct hwrm_fw_get_structured_data_input { #define FW_GET_STRUCTURED_DATA_REQ_SUBTYPE_NON_TPMR_PEER 0x201UL #define FW_GET_STRUCTURED_DATA_REQ_SUBTYPE_NON_TPMR_OPERATIONAL 0x202UL #define FW_GET_STRUCTURED_DATA_REQ_SUBTYPE_HOST_OPERATIONAL 0x300UL - #define FW_GET_STRUCTURED_DATA_REQ_SUBTYPE_LAST FW_GET_STRUCTURED_DATA_REQ_SUBTYPE_HOST_OPERATIONAL + #define FW_GET_STRUCTURED_DATA_REQ_SUBTYPE_CLAIMS_SUPPORTED 0x320UL + #define FW_GET_STRUCTURED_DATA_REQ_SUBTYPE_CLAIMS_ACTIVE 0x321UL + #define FW_GET_STRUCTURED_DATA_REQ_SUBTYPE_LAST FW_GET_STRUCTURED_DATA_REQ_SUBTYPE_CLAIMS_ACTIVE u8 count; u8 unused_0; }; @@ -10172,7 +10336,8 @@ struct hwrm_dbg_log_buffer_flush_input { #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_CA2_TRACE 0x9UL #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_RIGP1_TRACE 0xaUL #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_AFM_KONG_HWRM_TRACE 0xbUL - #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_LAST DBG_LOG_BUFFER_FLUSH_REQ_TYPE_AFM_KONG_HWRM_TRACE + #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_ERR_QPC_TRACE 0xcUL + #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_LAST DBG_LOG_BUFFER_FLUSH_REQ_TYPE_ERR_QPC_TRACE u8 unused_1[2]; __le32 flags; #define DBG_LOG_BUFFER_FLUSH_REQ_FLAGS_FLUSH_ALL_BUFFERS 0x1UL @@ -10295,10 +10460,15 @@ struct hwrm_nvm_write_output { /* hwrm_nvm_write_cmd_err (size:64b/8B) */ struct hwrm_nvm_write_cmd_err { u8 code; - #define NVM_WRITE_CMD_ERR_CODE_UNKNOWN 0x0UL - #define NVM_WRITE_CMD_ERR_CODE_FRAG_ERR 0x1UL - #define NVM_WRITE_CMD_ERR_CODE_NO_SPACE 0x2UL - #define NVM_WRITE_CMD_ERR_CODE_LAST NVM_WRITE_CMD_ERR_CODE_NO_SPACE + #define NVM_WRITE_CMD_ERR_CODE_UNKNOWN 0x0UL + #define NVM_WRITE_CMD_ERR_CODE_FRAG_ERR 0x1UL + #define NVM_WRITE_CMD_ERR_CODE_NO_SPACE 0x2UL + #define NVM_WRITE_CMD_ERR_CODE_WRITE_FAILED 0x3UL + #define NVM_WRITE_CMD_ERR_CODE_REQD_ERASE_FAILED 0x4UL + #define NVM_WRITE_CMD_ERR_CODE_VERIFY_FAILED 0x5UL + #define NVM_WRITE_CMD_ERR_CODE_INVALID_HEADER 0x6UL + #define NVM_WRITE_CMD_ERR_CODE_UPDATE_DIGEST_FAILED 0x7UL + #define NVM_WRITE_CMD_ERR_CODE_LAST NVM_WRITE_CMD_ERR_CODE_UPDATE_DIGEST_FAILED u8 unused_0[7]; }; @@ -10438,7 +10608,11 @@ struct hwrm_nvm_get_dev_info_output { __le16 srt2_fw_minor; __le16 srt2_fw_build; __le16 srt2_fw_patch; - u8 unused_0[7]; + u8 security_soc_fw_major; + u8 security_soc_fw_minor; + u8 security_soc_fw_build; + u8 security_soc_fw_patch; + u8 unused_0[3]; u8 valid; }; @@ -10568,7 +10742,9 @@ struct hwrm_nvm_install_update_cmd_err { #define NVM_INSTALL_UPDATE_CMD_ERR_CODE_NO_SPACE 0x2UL #define NVM_INSTALL_UPDATE_CMD_ERR_CODE_ANTI_ROLLBACK 0x3UL #define NVM_INSTALL_UPDATE_CMD_ERR_CODE_NO_VOLTREG_SUPPORT 0x4UL - #define NVM_INSTALL_UPDATE_CMD_ERR_CODE_LAST NVM_INSTALL_UPDATE_CMD_ERR_CODE_NO_VOLTREG_SUPPORT + #define NVM_INSTALL_UPDATE_CMD_ERR_CODE_DEFRAG_FAILED 0x5UL + #define NVM_INSTALL_UPDATE_CMD_ERR_CODE_UNKNOWN_DIR_ERR 0x6UL + #define NVM_INSTALL_UPDATE_CMD_ERR_CODE_LAST NVM_INSTALL_UPDATE_CMD_ERR_CODE_UNKNOWN_DIR_ERR u8 unused_0[7]; }; @@ -10591,7 +10767,8 @@ struct hwrm_nvm_get_variable_input { __le16 index_2; __le16 index_3; u8 flags; - #define NVM_GET_VARIABLE_REQ_FLAGS_FACTORY_DFLT 0x1UL + #define NVM_GET_VARIABLE_REQ_FLAGS_FACTORY_DFLT 0x1UL + #define NVM_GET_VARIABLE_REQ_FLAGS_VALIDATE_OPT_VALUE 0x2UL u8 unused_0; }; @@ -10606,18 +10783,25 @@ struct hwrm_nvm_get_variable_output { #define NVM_GET_VARIABLE_RESP_OPTION_NUM_RSVD_0 0x0UL #define NVM_GET_VARIABLE_RESP_OPTION_NUM_RSVD_FFFF 0xffffUL #define NVM_GET_VARIABLE_RESP_OPTION_NUM_LAST NVM_GET_VARIABLE_RESP_OPTION_NUM_RSVD_FFFF - u8 unused_0[3]; + u8 flags; + #define NVM_GET_VARIABLE_RESP_FLAGS_VALIDATE_OPT_VALUE 0x1UL + u8 unused_0[2]; u8 valid; }; /* hwrm_nvm_get_variable_cmd_err (size:64b/8B) */ struct hwrm_nvm_get_variable_cmd_err { u8 code; - #define NVM_GET_VARIABLE_CMD_ERR_CODE_UNKNOWN 0x0UL - #define NVM_GET_VARIABLE_CMD_ERR_CODE_VAR_NOT_EXIST 0x1UL - #define NVM_GET_VARIABLE_CMD_ERR_CODE_CORRUPT_VAR 0x2UL - #define NVM_GET_VARIABLE_CMD_ERR_CODE_LEN_TOO_SHORT 0x3UL - #define NVM_GET_VARIABLE_CMD_ERR_CODE_LAST NVM_GET_VARIABLE_CMD_ERR_CODE_LEN_TOO_SHORT + #define NVM_GET_VARIABLE_CMD_ERR_CODE_UNKNOWN 0x0UL + #define NVM_GET_VARIABLE_CMD_ERR_CODE_VAR_NOT_EXIST 0x1UL + #define NVM_GET_VARIABLE_CMD_ERR_CODE_CORRUPT_VAR 0x2UL + #define NVM_GET_VARIABLE_CMD_ERR_CODE_LEN_TOO_SHORT 0x3UL + #define NVM_GET_VARIABLE_CMD_ERR_CODE_INDEX_INVALID 0x4UL + #define NVM_GET_VARIABLE_CMD_ERR_CODE_ACCESS_DENIED 0x5UL + #define NVM_GET_VARIABLE_CMD_ERR_CODE_CB_FAILED 0x6UL + #define NVM_GET_VARIABLE_CMD_ERR_CODE_INVALID_DATA_LEN 0x7UL + #define NVM_GET_VARIABLE_CMD_ERR_CODE_NO_MEM 0x8UL + #define NVM_GET_VARIABLE_CMD_ERR_CODE_LAST NVM_GET_VARIABLE_CMD_ERR_CODE_NO_MEM u8 unused_0[7]; }; @@ -10667,10 +10851,17 @@ struct hwrm_nvm_set_variable_output { /* hwrm_nvm_set_variable_cmd_err (size:64b/8B) */ struct hwrm_nvm_set_variable_cmd_err { u8 code; - #define NVM_SET_VARIABLE_CMD_ERR_CODE_UNKNOWN 0x0UL - #define NVM_SET_VARIABLE_CMD_ERR_CODE_VAR_NOT_EXIST 0x1UL - #define NVM_SET_VARIABLE_CMD_ERR_CODE_CORRUPT_VAR 0x2UL - #define NVM_SET_VARIABLE_CMD_ERR_CODE_LAST NVM_SET_VARIABLE_CMD_ERR_CODE_CORRUPT_VAR + #define NVM_SET_VARIABLE_CMD_ERR_CODE_UNKNOWN 0x0UL + #define NVM_SET_VARIABLE_CMD_ERR_CODE_VAR_NOT_EXIST 0x1UL + #define NVM_SET_VARIABLE_CMD_ERR_CODE_CORRUPT_VAR 0x2UL + #define NVM_SET_VARIABLE_CMD_ERR_CODE_LEN_TOO_SHORT 0x3UL + #define NVM_SET_VARIABLE_CMD_ERR_CODE_ACTION_NOT_SUPPORTED 0x4UL + #define NVM_SET_VARIABLE_CMD_ERR_CODE_INDEX_INVALID 0x5UL + #define NVM_SET_VARIABLE_CMD_ERR_CODE_ACCESS_DENIED 0x6UL + #define NVM_SET_VARIABLE_CMD_ERR_CODE_CB_FAILED 0x7UL + #define NVM_SET_VARIABLE_CMD_ERR_CODE_INVALID_DATA_LEN 0x8UL + #define NVM_SET_VARIABLE_CMD_ERR_CODE_NO_MEM 0x9UL + #define NVM_SET_VARIABLE_CMD_ERR_CODE_LAST NVM_SET_VARIABLE_CMD_ERR_CODE_NO_MEM u8 unused_0[7]; }; From 1cc174d33a1f9acfd840014b6ded874aa12edc6c Mon Sep 17 00:00:00 2001 From: Shruti Parab Date: Tue, 19 Aug 2025 09:39:16 -0700 Subject: [PATCH 01633/11391] bnxt_en: Refactor bnxt_get_regs() Separate the code that sends the FW message to retrieve pcie stats into a new helper function. The caller of the helper will call hwrm_req_hold() beforehand and so the caller will call hwrm_req_drop() in all cases afterwards. This helper will be useful when adding the support for the larger struct pcie_ctx_hw_stats_v2. Signed-off-by: Shruti Parab Signed-off-by: Michael Chan Reviewed-by: Przemek Kitszel Link: https://patch.msgid.link/20250819163919.104075-3-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 68a4ee9f69b1..2eb7c09a116f 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -2074,6 +2074,25 @@ static int bnxt_get_regs_len(struct net_device *dev) return reg_len; } +static void * +__bnxt_hwrm_pcie_qstats(struct bnxt *bp, struct hwrm_pcie_qstats_input *req) +{ + struct pcie_ctx_hw_stats_v2 *hw_pcie_stats; + dma_addr_t hw_pcie_stats_addr; + int rc; + + hw_pcie_stats = hwrm_req_dma_slice(bp, req, sizeof(*hw_pcie_stats), + &hw_pcie_stats_addr); + if (!hw_pcie_stats) + return NULL; + + req->pcie_stat_size = cpu_to_le16(sizeof(*hw_pcie_stats)); + req->pcie_stat_host_addr = cpu_to_le64(hw_pcie_stats_addr); + rc = hwrm_req_send(bp, req); + + return rc ? NULL : hw_pcie_stats; +} + #define BNXT_PCIE_32B_ENTRY(start, end) \ { offsetof(struct pcie_ctx_hw_stats, start), \ offsetof(struct pcie_ctx_hw_stats, end) } @@ -2088,11 +2107,9 @@ static const struct { static void bnxt_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p) { - struct pcie_ctx_hw_stats *hw_pcie_stats; struct hwrm_pcie_qstats_input *req; struct bnxt *bp = netdev_priv(dev); - dma_addr_t hw_pcie_stats_addr; - int rc; + u8 *src; regs->version = 0; if (!(bp->fw_dbg_cap & DBG_QCAPS_RESP_FLAGS_REG_ACCESS_RESTRICTED)) @@ -2104,24 +2121,14 @@ static void bnxt_get_regs(struct net_device *dev, struct ethtool_regs *regs, if (hwrm_req_init(bp, req, HWRM_PCIE_QSTATS)) return; - hw_pcie_stats = hwrm_req_dma_slice(bp, req, sizeof(*hw_pcie_stats), - &hw_pcie_stats_addr); - if (!hw_pcie_stats) { - hwrm_req_drop(bp, req); - return; - } - - regs->version = 1; - hwrm_req_hold(bp, req); /* hold on to slice */ - req->pcie_stat_size = cpu_to_le16(sizeof(*hw_pcie_stats)); - req->pcie_stat_host_addr = cpu_to_le64(hw_pcie_stats_addr); - rc = hwrm_req_send(bp, req); - if (!rc) { + hwrm_req_hold(bp, req); + src = __bnxt_hwrm_pcie_qstats(bp, req); + if (src) { u8 *dst = (u8 *)(_p + BNXT_PXP_REG_LEN); - u8 *src = (u8 *)hw_pcie_stats; int i, j; - for (i = 0, j = 0; i < sizeof(*hw_pcie_stats); ) { + regs->version = 1; + for (i = 0, j = 0; i < sizeof(struct pcie_ctx_hw_stats); ) { if (i >= bnxt_pcie_32b_entries[j].start && i <= bnxt_pcie_32b_entries[j].end) { u32 *dst32 = (u32 *)(dst + i); From b530173d3c8adbe2921240cd3bce06053ab47d27 Mon Sep 17 00:00:00 2001 From: Shruti Parab Date: Tue, 19 Aug 2025 09:39:17 -0700 Subject: [PATCH 01634/11391] bnxt_en: Add pcie_stat_len to struct bp Add this length field to capture the length of the pcie stats structure supported by the FW. This length will be determined in bnxt_ethtool_init(). The minimum of this FW length and the length known to the driver will determine the actual ethtool -d length. Suggested-by: Kalesh AP Reviewed-by: Andy Gospodarek Reviewed-by: Kalesh AP Signed-off-by: Shruti Parab Signed-off-by: Michael Chan Link: https://patch.msgid.link/20250819163919.104075-4-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 + .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 37 ++++++++++++++----- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 40ae34923511..25ca002fc382 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -2543,6 +2543,7 @@ struct bnxt { u16 fw_rx_stats_ext_size; u16 fw_tx_stats_ext_size; u16 hw_ring_stats_size; + u16 pcie_stat_len; u8 pri2cos_idx[8]; u8 pri2cos_valid; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 2eb7c09a116f..abb895fb1a9c 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -2061,17 +2061,11 @@ static void bnxt_get_drvinfo(struct net_device *dev, static int bnxt_get_regs_len(struct net_device *dev) { struct bnxt *bp = netdev_priv(dev); - int reg_len; if (!BNXT_PF(bp)) return -EOPNOTSUPP; - reg_len = BNXT_PXP_REG_LEN; - - if (bp->fw_cap & BNXT_FW_CAP_PCIE_STATS_SUPPORTED) - reg_len += sizeof(struct pcie_ctx_hw_stats); - - return reg_len; + return BNXT_PXP_REG_LEN + bp->pcie_stat_len; } static void * @@ -2107,6 +2101,7 @@ static const struct { static void bnxt_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p) { + struct hwrm_pcie_qstats_output *resp; struct hwrm_pcie_qstats_input *req; struct bnxt *bp = netdev_priv(dev); u8 *src; @@ -2121,14 +2116,15 @@ static void bnxt_get_regs(struct net_device *dev, struct ethtool_regs *regs, if (hwrm_req_init(bp, req, HWRM_PCIE_QSTATS)) return; - hwrm_req_hold(bp, req); + resp = hwrm_req_hold(bp, req); src = __bnxt_hwrm_pcie_qstats(bp, req); if (src) { u8 *dst = (u8 *)(_p + BNXT_PXP_REG_LEN); - int i, j; + int i, j, len; + len = min(bp->pcie_stat_len, le16_to_cpu(resp->pcie_stat_size)); regs->version = 1; - for (i = 0, j = 0; i < sizeof(struct pcie_ctx_hw_stats); ) { + for (i = 0, j = 0; i < len; ) { if (i >= bnxt_pcie_32b_entries[j].start && i <= bnxt_pcie_32b_entries[j].end) { u32 *dst32 = (u32 *)(dst + i); @@ -5273,6 +5269,26 @@ static int bnxt_get_ts_info(struct net_device *dev, return 0; } +static void bnxt_hwrm_pcie_qstats(struct bnxt *bp) +{ + struct hwrm_pcie_qstats_output *resp; + struct hwrm_pcie_qstats_input *req; + + bp->pcie_stat_len = 0; + if (!(bp->fw_cap & BNXT_FW_CAP_PCIE_STATS_SUPPORTED)) + return; + + if (hwrm_req_init(bp, req, HWRM_PCIE_QSTATS)) + return; + + resp = hwrm_req_hold(bp, req); + if (__bnxt_hwrm_pcie_qstats(bp, req)) + bp->pcie_stat_len = min_t(u16, + le16_to_cpu(resp->pcie_stat_size), + sizeof(struct pcie_ctx_hw_stats_v2)); + hwrm_req_drop(bp, req); +} + void bnxt_ethtool_init(struct bnxt *bp) { struct hwrm_selftest_qlist_output *resp; @@ -5281,6 +5297,7 @@ void bnxt_ethtool_init(struct bnxt *bp) struct net_device *dev = bp->dev; int i, rc; + bnxt_hwrm_pcie_qstats(bp); if (!(bp->fw_cap & BNXT_FW_CAP_PKG_VER)) bnxt_get_pkgver(dev); From 5a4cf42322a0260c7391a3e64d288861e43de673 Mon Sep 17 00:00:00 2001 From: Shruti Parab Date: Tue, 19 Aug 2025 09:39:18 -0700 Subject: [PATCH 01635/11391] bnxt_en: Add pcie_ctx_v2 support for ethtool -d Add support to dump the expanded v2 struct that contains PCIE read/write latency and credit histogram data. Reviewed-by: Kalesh AP Reviewed-by: Andy Gospodarek Signed-off-by: Shruti Parab Signed-off-by: Michael Chan Link: https://patch.msgid.link/20250819163919.104075-5-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index abb895fb1a9c..2830a2b17a27 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -2088,14 +2088,16 @@ __bnxt_hwrm_pcie_qstats(struct bnxt *bp, struct hwrm_pcie_qstats_input *req) } #define BNXT_PCIE_32B_ENTRY(start, end) \ - { offsetof(struct pcie_ctx_hw_stats, start), \ - offsetof(struct pcie_ctx_hw_stats, end) } + { offsetof(struct pcie_ctx_hw_stats_v2, start),\ + offsetof(struct pcie_ctx_hw_stats_v2, end) } static const struct { u16 start; u16 end; } bnxt_pcie_32b_entries[] = { BNXT_PCIE_32B_ENTRY(pcie_ltssm_histogram[0], pcie_ltssm_histogram[3]), + BNXT_PCIE_32B_ENTRY(pcie_tl_credit_nph_histogram[0], unused_1), + BNXT_PCIE_32B_ENTRY(pcie_rd_latency_histogram[0], unused_2), }; static void bnxt_get_regs(struct net_device *dev, struct ethtool_regs *regs, @@ -2123,7 +2125,13 @@ static void bnxt_get_regs(struct net_device *dev, struct ethtool_regs *regs, int i, j, len; len = min(bp->pcie_stat_len, le16_to_cpu(resp->pcie_stat_size)); - regs->version = 1; + if (len <= sizeof(struct pcie_ctx_hw_stats)) + regs->version = 1; + else if (len < sizeof(struct pcie_ctx_hw_stats_v2)) + regs->version = 2; + else + regs->version = 3; + for (i = 0, j = 0; i < len; ) { if (i >= bnxt_pcie_32b_entries[j].start && i <= bnxt_pcie_32b_entries[j].end) { From 5be7cb805bd9a6680b863a1477dbc6e7986cc223 Mon Sep 17 00:00:00 2001 From: Pavan Chebbi Date: Tue, 19 Aug 2025 09:39:19 -0700 Subject: [PATCH 01636/11391] bnxt_en: Add Hyper-V VF ID VFs of the P7 chip family created by Hyper-V will have the device ID of 0x181b. Reviewed-by: Somnath Kotur Reviewed-by: Kalesh AP Signed-off-by: Pavan Chebbi Signed-off-by: Michael Chan Link: https://patch.msgid.link/20250819163919.104075-6-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 5 ++++- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 2d4fdf5a0dc5..ba99de403138 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -142,6 +142,7 @@ static const struct { [NETXTREME_E_P5_VF] = { "Broadcom BCM5750X NetXtreme-E Ethernet Virtual Function" }, [NETXTREME_E_P5_VF_HV] = { "Broadcom BCM5750X NetXtreme-E Virtual Function for Hyper-V" }, [NETXTREME_E_P7_VF] = { "Broadcom BCM5760X Virtual Function" }, + [NETXTREME_E_P7_VF_HV] = { "Broadcom BCM5760X Virtual Function for Hyper-V" }, }; static const struct pci_device_id bnxt_pci_tbl[] = { @@ -217,6 +218,7 @@ static const struct pci_device_id bnxt_pci_tbl[] = { { PCI_VDEVICE(BROADCOM, 0x1808), .driver_data = NETXTREME_E_P5_VF_HV }, { PCI_VDEVICE(BROADCOM, 0x1809), .driver_data = NETXTREME_E_P5_VF_HV }, { PCI_VDEVICE(BROADCOM, 0x1819), .driver_data = NETXTREME_E_P7_VF }, + { PCI_VDEVICE(BROADCOM, 0x181b), .driver_data = NETXTREME_E_P7_VF_HV }, { PCI_VDEVICE(BROADCOM, 0xd800), .driver_data = NETXTREME_S_VF }, #endif { 0 } @@ -315,7 +317,8 @@ static bool bnxt_vf_pciid(enum board_idx idx) return (idx == NETXTREME_C_VF || idx == NETXTREME_E_VF || idx == NETXTREME_S_VF || idx == NETXTREME_C_VF_HV || idx == NETXTREME_E_VF_HV || idx == NETXTREME_E_P5_VF || - idx == NETXTREME_E_P5_VF_HV || idx == NETXTREME_E_P7_VF); + idx == NETXTREME_E_P5_VF_HV || idx == NETXTREME_E_P7_VF || + idx == NETXTREME_E_P7_VF_HV); } #define DB_CP_REARM_FLAGS (DB_KEY_CP | DB_IDX_VALID) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 25ca002fc382..1bb2a5de88cd 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -2130,6 +2130,7 @@ enum board_idx { NETXTREME_E_P5_VF, NETXTREME_E_P5_VF_HV, NETXTREME_E_P7_VF, + NETXTREME_E_P7_VF_HV, }; #define BNXT_TRACE_BUF_MAGIC_BYTE ((u8)0xbc) From a6d4f25888b83b8300aef28d9ee22765c1cc9b34 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 19 Aug 2025 17:40:30 +0000 Subject: [PATCH 01637/11391] net: set net.core.rmem_max and net.core.wmem_max to 4 MB SO_RCVBUF and SO_SNDBUF have limited range today, unless distros or system admins change rmem_max and wmem_max. Even iproute2 uses 1 MB SO_RCVBUF which is capped by the kernel. Decouple [rw]mem_max and [rw]mem_default and increase [rw]mem_max to 4 MB. Before: $ sysctl net.core.rmem_default net.core.rmem_max net.core.wmem_default net.core.wmem_max net.core.rmem_default = 212992 net.core.rmem_max = 212992 net.core.wmem_default = 212992 net.core.wmem_max = 212992 After: $ sysctl net.core.rmem_default net.core.rmem_max net.core.wmem_default net.core.wmem_max net.core.rmem_default = 212992 net.core.rmem_max = 4194304 net.core.wmem_default = 212992 net.core.wmem_max = 4194304 Signed-off-by: Eric Dumazet Reviewed-by: Neal Cardwell Link: https://patch.msgid.link/20250819174030.1986278-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- Documentation/admin-guide/sysctl/net.rst | 4 ++++ Documentation/networking/ip-sysctl.rst | 6 +++--- include/net/sock.h | 4 ++-- net/core/sock.c | 8 ++++---- net/ipv4/arp.c | 2 +- net/ipv6/ndisc.c | 2 +- 6 files changed, 15 insertions(+), 11 deletions(-) diff --git a/Documentation/admin-guide/sysctl/net.rst b/Documentation/admin-guide/sysctl/net.rst index 7b0c4291c686..2ef50828aff1 100644 --- a/Documentation/admin-guide/sysctl/net.rst +++ b/Documentation/admin-guide/sysctl/net.rst @@ -222,6 +222,8 @@ rmem_max The maximum receive socket buffer size in bytes. +Default: 4194304 + rps_default_mask ---------------- @@ -247,6 +249,8 @@ wmem_max The maximum send socket buffer size in bytes. +Default: 4194304 + message_burst and message_cost ------------------------------ diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst index 43badb338d22..9f5891c9b07b 100644 --- a/Documentation/networking/ip-sysctl.rst +++ b/Documentation/networking/ip-sysctl.rst @@ -209,7 +209,7 @@ neigh/default/unres_qlen_bytes - INTEGER Setting negative value is meaningless and will return error. - Default: SK_WMEM_MAX, (same as net.core.wmem_default). + Default: SK_WMEM_DEFAULT, (same as net.core.wmem_default). Exact value depends on architecture and kernel options, but should be enough to allow queuing 256 packets @@ -805,8 +805,8 @@ tcp_rmem - vector of 3 INTEGERs: min, default, max This value results in initial window of 65535. max: maximal size of receive buffer allowed for automatically - selected receiver buffers for TCP socket. This value does not override - net.core.rmem_max. Calling setsockopt() with SO_RCVBUF disables + selected receiver buffers for TCP socket. + Calling setsockopt() with SO_RCVBUF disables automatic tuning of that socket's receive buffer size, in which case this value is ignored. Default: between 131072 and 32MB, depending on RAM size. diff --git a/include/net/sock.h b/include/net/sock.h index 1c49ea13af4a..63a6a48afb48 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -2970,8 +2970,8 @@ void sk_get_meminfo(const struct sock *sk, u32 *meminfo); */ #define _SK_MEM_PACKETS 256 #define _SK_MEM_OVERHEAD SKB_TRUESIZE(256) -#define SK_WMEM_MAX (_SK_MEM_OVERHEAD * _SK_MEM_PACKETS) -#define SK_RMEM_MAX (_SK_MEM_OVERHEAD * _SK_MEM_PACKETS) +#define SK_WMEM_DEFAULT (_SK_MEM_OVERHEAD * _SK_MEM_PACKETS) +#define SK_RMEM_DEFAULT (_SK_MEM_OVERHEAD * _SK_MEM_PACKETS) extern __u32 sysctl_wmem_max; extern __u32 sysctl_rmem_max; diff --git a/net/core/sock.c b/net/core/sock.c index ab6953d295df..8002ac6293dc 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -281,12 +281,12 @@ static struct lock_class_key af_elock_keys[AF_MAX]; static struct lock_class_key af_kern_callback_keys[AF_MAX]; /* Run time adjustable parameters. */ -__u32 sysctl_wmem_max __read_mostly = SK_WMEM_MAX; +__u32 sysctl_wmem_max __read_mostly = 4 << 20; EXPORT_SYMBOL(sysctl_wmem_max); -__u32 sysctl_rmem_max __read_mostly = SK_RMEM_MAX; +__u32 sysctl_rmem_max __read_mostly = 4 << 20; EXPORT_SYMBOL(sysctl_rmem_max); -__u32 sysctl_wmem_default __read_mostly = SK_WMEM_MAX; -__u32 sysctl_rmem_default __read_mostly = SK_RMEM_MAX; +__u32 sysctl_wmem_default __read_mostly = SK_WMEM_DEFAULT; +__u32 sysctl_rmem_default __read_mostly = SK_RMEM_DEFAULT; DEFINE_STATIC_KEY_FALSE(memalloc_socks_key); EXPORT_SYMBOL_GPL(memalloc_socks_key); diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 5cfc1c939673..833f2cf97178 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -170,7 +170,7 @@ struct neigh_table arp_tbl = { [NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ, [NEIGH_VAR_INTERVAL_PROBE_TIME_MS] = 5 * HZ, [NEIGH_VAR_GC_STALETIME] = 60 * HZ, - [NEIGH_VAR_QUEUE_LEN_BYTES] = SK_WMEM_MAX, + [NEIGH_VAR_QUEUE_LEN_BYTES] = SK_WMEM_DEFAULT, [NEIGH_VAR_PROXY_QLEN] = 64, [NEIGH_VAR_ANYCAST_DELAY] = 1 * HZ, [NEIGH_VAR_PROXY_DELAY] = (8 * HZ) / 10, diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 7d5abb3158ec..57aaa7ae8ac3 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -130,7 +130,7 @@ struct neigh_table nd_tbl = { [NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ, [NEIGH_VAR_INTERVAL_PROBE_TIME_MS] = 5 * HZ, [NEIGH_VAR_GC_STALETIME] = 60 * HZ, - [NEIGH_VAR_QUEUE_LEN_BYTES] = SK_WMEM_MAX, + [NEIGH_VAR_QUEUE_LEN_BYTES] = SK_WMEM_DEFAULT, [NEIGH_VAR_PROXY_QLEN] = 64, [NEIGH_VAR_ANYCAST_DELAY] = 1 * HZ, [NEIGH_VAR_PROXY_DELAY] = (8 * HZ) / 10, From a5c10aa3d1ba643385534b5d40c8a67497f904b6 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Tue, 19 Aug 2025 23:14:57 +0000 Subject: [PATCH 01638/11391] selftests/net: packetdrill: Support single protocol test. Currently, we cannot write IPv4 or IPv6 specific packetdrill tests as ksft_runner.sh runs each .pkt file for both protocols. Let's support single protocol test by checking --ip_version in the .pkt file. Signed-off-by: Kuniyuki Iwashima Reviewed-by: Willem de Bruijn Link: https://patch.msgid.link/20250819231527.1427361-1-kuniyu@google.com Signed-off-by: Jakub Kicinski --- .../selftests/net/packetdrill/ksft_runner.sh | 47 +++++++++++-------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/tools/testing/selftests/net/packetdrill/ksft_runner.sh b/tools/testing/selftests/net/packetdrill/ksft_runner.sh index a7e790af38ff..0ae6eeeb1a8e 100755 --- a/tools/testing/selftests/net/packetdrill/ksft_runner.sh +++ b/tools/testing/selftests/net/packetdrill/ksft_runner.sh @@ -3,21 +3,22 @@ source "$(dirname $(realpath $0))/../../kselftest/ktap_helpers.sh" -readonly ipv4_args=('--ip_version=ipv4 ' - '--local_ip=192.168.0.1 ' - '--gateway_ip=192.168.0.1 ' - '--netmask_ip=255.255.0.0 ' - '--remote_ip=192.0.2.1 ' - '-D CMSG_LEVEL_IP=SOL_IP ' - '-D CMSG_TYPE_RECVERR=IP_RECVERR ') - -readonly ipv6_args=('--ip_version=ipv6 ' - '--mtu=1520 ' - '--local_ip=fd3d:0a0b:17d6::1 ' - '--gateway_ip=fd3d:0a0b:17d6:8888::1 ' - '--remote_ip=fd3d:fa7b:d17d::1 ' - '-D CMSG_LEVEL_IP=SOL_IPV6 ' - '-D CMSG_TYPE_RECVERR=IPV6_RECVERR ') +declare -A ip_args=( + [ipv4]="--ip_version=ipv4 + --local_ip=192.168.0.1 + --gateway_ip=192.168.0.1 + --netmask_ip=255.255.0.0 + --remote_ip=192.0.2.1 + -D CMSG_LEVEL_IP=SOL_IP + -D CMSG_TYPE_RECVERR=IP_RECVERR" + [ipv6]="--ip_version=ipv6 + --mtu=1520 + --local_ip=fd3d:0a0b:17d6::1 + --gateway_ip=fd3d:0a0b:17d6:8888::1 + --remote_ip=fd3d:fa7b:d17d::1 + -D CMSG_LEVEL_IP=SOL_IPV6 + -D CMSG_TYPE_RECVERR=IPV6_RECVERR" +) if [ $# -ne 1 ]; then ktap_exit_fail_msg "usage: $0